rspec-rebound 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2e912934fa33c3b36080535612810431e72564925d5fc9448e0a96254dc0e13a
4
+ data.tar.gz: 9a0b3c4a4f32979120e4da4b7a6c4cfe61cf2a57f3b0ee16da0112f2e4e06bcd
5
+ SHA512:
6
+ metadata.gz: f5983ecd3470416e8f5407bab05f11b900637b66953d881734095537143a7aea4ba6f2deae807cc10dddd6169989855f3c772ec2c8ece696be58b001586273ec
7
+ data.tar.gz: 27527c62988cee2af25cfdac853c3456f5e288e5060d59ce131b3476e92160102cf962d5e89c1a6e0acc12013cdabf2e3e6d8a276db23b6e0cea4576b7d43b6c
@@ -0,0 +1,53 @@
1
+ name: Test Rspec Rebound
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ branches:
9
+ - master
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+
15
+ strategy:
16
+ matrix:
17
+ gemfile: [rspec_3.3.gemfile, rspec_3.4.gemfile, rspec_3.5.gemfile, rspec_3.7.gemfile, rspec_3.9.gemfile, rspec_3.10.gemfile, rspec_3.11.gemfile, rspec_3.12.gemfile, rspec_3.13.gemfile]
18
+ ruby-version: [ '2.7', '3.0', '3.1', '3.3']
19
+ exclude:
20
+ - ruby-version: '2.7'
21
+ gemfile: 'rspec_3.13.gemfile'
22
+ - ruby-version: '2.7'
23
+ gemfile: 'rspec_3.12.gemfile'
24
+ - ruby-version: '2.7'
25
+ gemfile: 'rspec_3.11.gemfile'
26
+ - ruby-version: '2.7'
27
+ gemfile: 'rspec_3.10.gemfile'
28
+ - ruby-version: '2.7'
29
+ gemfile: 'rspec_3.9.gemfile'
30
+ - ruby-version: '2.7'
31
+ gemfile: 'rspec_3.8.gemfile'
32
+ - ruby-version: '3.3'
33
+ gemfile: 'rspec_3.3.gemfile'
34
+ - ruby-version: '3.3'
35
+ gemfile: 'rspec_3.4.gemfile'
36
+ - ruby-version: '3.3'
37
+ gemfile: 'rspec_3.5.gemfile'
38
+
39
+ env:
40
+ BUNDLE_GEMFILE: spec/gemfiles/${{ matrix.gemfile }}
41
+ steps:
42
+ - name: Checkout code
43
+ uses: actions/checkout@v2
44
+
45
+ - name: Set up Ruby ${{ matrix.ruby-version }}
46
+ uses: ruby/setup-ruby@v1
47
+ with:
48
+ ruby-version: ${{ matrix.ruby-version }}
49
+ bundler-cache: true
50
+
51
+ - name: Run tests
52
+ run: |
53
+ bundle exec rspec
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .byebug_history
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1
4
+ - 2.2
5
+ - 2.3
6
+ - 2.4
7
+ - 2.5
8
+ - 2.6
9
+ gemfile:
10
+ - gemfiles/rspec_3.3.gemfile
11
+ - gemfiles/rspec_3.4.gemfile
12
+ - gemfiles/rspec_3.5.gemfile
13
+ - gemfiles/rspec_3.6.gemfile
14
+ - gemfiles/rspec_3.7.gemfile
15
+ cache: bundler
data/Appraisals ADDED
@@ -0,0 +1,19 @@
1
+ appraise 'rspec-3.3' do
2
+ gem 'rspec', '~> 3.3.0'
3
+ end
4
+
5
+ appraise 'rspec-3.4' do
6
+ gem 'rspec', '~> 3.4.0'
7
+ end
8
+
9
+ appraise 'rspec-3.5' do
10
+ gem 'rspec', '~> 3.5.0'
11
+ end
12
+
13
+ appraise 'rspec-3.6' do
14
+ gem 'rspec', '~> 3.6.0'
15
+ end
16
+
17
+ appraise 'rspec-3.7' do
18
+ gem 'rspec', '~> 3.7.0'
19
+ end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rspec-retry.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard 'rspec', :version => 2, :cli => '-c -f d' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Yusuke Mito
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # RSpec::Rebound
2
+
3
+ RSpec::Rebound adds a ``:retry`` option for intermittently failing rspec examples.
4
+ If an example has the ``:retry`` option, rspec will retry the example the
5
+ specified number of times until the example succeeds.
6
+
7
+ ## Acknowledgments
8
+
9
+ This gem is derived from the [rspec-retry](https://github.com/NoRedInk/rspec-retry) gem by NoRedInk. We would like to express our sincere gratitude to NoRedInk for their original work. RSpec::Rebound is an updated, upgraded, and maintained version of that gem.
10
+
11
+ **Important migration note:** When moving from rspec-retry to rspec-rebound, you should subtract 1 from every `retry: X` value in your tests. In rspec-rebound, `retry: 2` means up to 2 retries (3 attempts total), whereas in rspec-retry it might have meant 2 attempts total. This change makes the retry count more intuitive.
12
+
13
+ ### Compatibility
14
+
15
+ | Rspec Version | Rspec-Rebound Version |
16
+ |---------------|------------------------|
17
+ | > 3.3 | 0.1.0 |
18
+ | < 3.3 | Use [rspec-retry](https://github.com/NoRedInk/rspec-retry) instead |
19
+
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'rspec-rebound', group: :test # Unlike rspec, this doesn't need to be included in development group
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install rspec-rebound
36
+
37
+ require in ``spec_helper.rb``
38
+
39
+ ```ruby
40
+ # spec/spec_helper.rb
41
+ require 'rspec/rebound'
42
+
43
+ RSpec.configure do |config|
44
+ # show retry status in spec process
45
+ config.verbose_retry = true
46
+ # show exception that triggers a retry if verbose_retry is set to true
47
+ config.display_try_failure_messages = true
48
+
49
+ # run retry only on features
50
+ config.around :each, :js do |ex|
51
+ ex.run_with_retry retry: 3
52
+ end
53
+
54
+ # callback to be run between retries
55
+ config.retry_callback = proc do |ex|
56
+ # run some additional clean up task - can be filtered by example metadata
57
+ if ex.metadata[:js]
58
+ Capybara.reset!
59
+ end
60
+ end
61
+ end
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ ```ruby
67
+ it 'should randomly succeed', :retry => 2 do
68
+ expect(rand(2)).to eq(1)
69
+ end
70
+
71
+ it 'should succeed after a while', :retry => 2, :retry_wait => 10 do
72
+ expect(command('service myservice status')).to eq('started')
73
+ end
74
+ # run spec (following log is shown if verbose_retry options is true)
75
+ # RSpec::Rebound: 2nd try ./spec/lib/random_spec.rb:49
76
+ # RSpec::Rebound: 3rd try ./spec/lib/random_spec.rb:49
77
+ ```
78
+
79
+ ### Calling `run_with_retry` programmatically
80
+
81
+ You can call `ex.run_with_retry(opts)` on an individual example.
82
+
83
+ ## Configuration
84
+
85
+ - __:verbose_retry__(default: *false*) Print retry status
86
+ - __:display_try_failure_messages__ (default: *false*) If verbose retry is enabled, print what reason forced the retry
87
+ - __:default_retry_count__(default: *0*) If retry count is not set in an example, this value is used by default. This is a 'retry' count. If increased from the default of 0 to 1, if they fail all examples will be retried once (and 2 attempts in total).
88
+ - __:default_sleep_interval__(default: *0*) Seconds to wait between retries
89
+ - __:clear_lets_on_failure__(default: *true*) Clear memoized values for ``let``s before retrying
90
+ - __:exceptions_to_hard_fail__(default: *[]*) List of exceptions that will trigger an immediate test failure without retry. Takes precedence over __:exceptions_to_retry__
91
+ - __:exceptions_to_retry__(default: *[]*) List of exceptions that will trigger a retry (when empty, all exceptions will)
92
+ - __:retry_callback__(default: *nil*) Callback function to be called between retries
93
+
94
+
95
+ ## Environment Variables
96
+ - __RSPEC_RETRY_RETRY_COUNT__ can override the retry counts even if a retry count is set in an example or default_retry_count is set in a configuration.
97
+
98
+ ## Contributing
99
+
100
+ 1. Fork it
101
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
102
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
103
+ 4. Push to the branch (`git push origin my-new-feature`)
104
+ 5. Create a pull request
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/setup'
3
+ require "bundler/gem_tasks"
4
+
5
+ begin
6
+ require 'rspec/core/rake_task'
7
+
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task :default => :spec
11
+ rescue LoadError
12
+ end
data/changelog.md ADDED
@@ -0,0 +1,107 @@
1
+ # 0.6.2 - 2019-11-21
2
+ ## enhancements
3
+ expose `example.attempts` (in addition to `example.metadata[:attempts]`) (thanks @knu / #103)
4
+ expose `example.metadata[:retry_exceptions]` (thanks @drummond-work / #106)
5
+
6
+ ## bugfixes / cleanup
7
+ ci works again! (#107)
8
+ cleanup travis.yml (thanks @olleolleolle / #105)
9
+
10
+
11
+ # 0.6.1 - 2018-06-11
12
+ ## enhancements
13
+ add more flexible method of retrying (thanks @varyform / #48)
14
+ store retry attempts in example metadata (thanks @aeberlin / #43)
15
+
16
+ # 0.6.0 - 2018-05-15
17
+ ## enhancements
18
+ add exponential backoff option (thanks @patveith, @thedrow / #91, #94, #95)
19
+ better documentation (thanks @swrobel / #90)
20
+
21
+ # 0.5.7 - 2018-03-13
22
+ ## enhancements
23
+ remove <3.8 constraint on rspec-core to prevent breaking when rspec-core upgrades (thanks @dthorsen / #89)
24
+
25
+ # 0.5.6 - 2017-10-17
26
+ ## enhancements
27
+ added support for rspec 3.7.0
28
+
29
+ # 0.5.5 - 2017-08-22
30
+ ## enhancements
31
+ added retry_callback to help with cleanup between runs (thanks @abrom / #80)
32
+
33
+ # 0.5.4 - 2017-05-08
34
+ ## enhancements
35
+ added support for rspec 3.6.0 (thanks @dthorsen / #76)
36
+
37
+ # 0.5.3 - 2017-01-11
38
+ ## enhancements
39
+ printing summary of rspec to output not STDOUT (thanks @trevorcreech / #68)
40
+ removing some development dependencies
41
+
42
+ # 0.5.2 - 2016-10-03
43
+ ## bugfixes
44
+ supports versions > 3.5.0 (thanks @y-yagi / #65)
45
+
46
+ # 0.5.1 - 2016-9-30
47
+ ## enhancements
48
+ better failure message for multiple failures in one test (thanks @JonRowe / #62)
49
+
50
+ # 0.5.0 - 2016-8-8
51
+ drop support for rspec 3.2, added support for 3.4, 3.5
52
+
53
+ # 0.4.6 - 2016-8-8
54
+ ## bugfixes
55
+ failure message was off by 1 (thanks @anthonywoo, @vgrigoruk / #57)
56
+
57
+ ## enhancements
58
+ add the `exceptions_to_hard_fail` options (thanks @james-dominy, @ShockwaveNN / #59)
59
+ add retry reporter & api for accessing retry from reporter (thanks @tdeo / #54)
60
+
61
+ # 0.4.5 - 2015-11-4
62
+ ## enhancements
63
+ retry can be called programmatically (thanks, @dwbutler / #45)
64
+
65
+ # 0.4.4 - 2015-9-9
66
+ ## bugfixes
67
+ fix gem permissions to be readable (thanks @jdelStrother / #42)
68
+
69
+ # 0.4.3 - 2015-8-29
70
+ ## bugfixes
71
+ will retry on children of exceptions in the `exceptions_to_retry` list
72
+ (thanks @dwbutler! #40, #41)
73
+
74
+ ## enhancements
75
+ setting `config.display_try_failure_messages` (and `config.verbose_retry`) will
76
+ spit out some debug information about why an exception is being retried
77
+ (thanks @mmorast, #24)
78
+
79
+ # 0.4.2 - 2015-7-10
80
+ ## bugfixes
81
+ setting retry to 0 will still run tests (#34)
82
+
83
+ ## enhancements
84
+ can set env variable RSPEC_RETRY_RETRY_COUNT to override anything specified in
85
+ code (thanks @sunflat, #28, #36)
86
+
87
+ # 0.4.1 - 2015-7-9
88
+ ## bugfixes
89
+ rspec-retry now supports rspec 3.3. (thanks @eitoball, #32)
90
+
91
+ ## dev changes
92
+ include travis configuration for testing rspec 3.2.* and 3.3.*
93
+ (thanks @eitoball, #31)
94
+
95
+ # Changelog
96
+
97
+ ## 0.1.0 (YYYY-MM-DD)
98
+
99
+ ### Added
100
+ - Initial release
101
+ - [List major features]
102
+
103
+ ### Changed
104
+ - [List changes]
105
+
106
+ ### Fixed
107
+ - [List fixes]
@@ -0,0 +1,56 @@
1
+ require 'rspec/core/formatters/base_text_formatter'
2
+
3
+ class RSpec::Rebound::Formatter < RSpec::Core::Formatters::BaseTextFormatter
4
+ RSpec::Core::Formatters.register self, :example_passed
5
+
6
+ def initialize(output)
7
+ super(output)
8
+ @tries = Hash.new { |h, k| h[k] = { successes: 0, tries: 0 } }
9
+ end
10
+
11
+ def seed(_); end
12
+
13
+ def message(_message); end
14
+
15
+ def close(_); end
16
+
17
+ def dump_failures(_); end
18
+
19
+ def dump_pending(_); end
20
+
21
+ def dump_summary(notification)
22
+ summary = "\nRSpec Rebound Summary:\n"
23
+ @tries.each do |key, retry_data|
24
+ next if retry_data[:successes] < 1 || retry_data[:tries] <= 1
25
+ summary += "\t#{key.location}: #{key.full_description}: passed at attempt #{retry_data[:tries]}\n"
26
+ end
27
+ retried = @tries.count { |_, v| v[:tries] > 1 && v[:successes] > 0 }
28
+ summary += "\n\t#{retried} of #{notification.example_count} tests passed with retries.\n"
29
+ summary += "\t#{notification.failure_count} tests failed all retries.\n"
30
+ output.puts summary
31
+ end
32
+
33
+ def example_passed(notification)
34
+ increment_success notification.example
35
+ end
36
+
37
+ def retry(example)
38
+ increment_tries example
39
+ end
40
+
41
+ private
42
+
43
+ def increment_success(example)
44
+ # debugger
45
+ previous = @tries[example]
46
+ @tries[example] = {
47
+ successes: previous[:successes] + 1, tries: previous[:tries] + 1 }
48
+ end
49
+
50
+ def increment_tries(example)
51
+ # debugger
52
+ previous = @tries[example]
53
+ @tries[example] = {
54
+ successes: previous[:successes], tries: previous[:tries] + 1 }
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ module RSpec
2
+ class Rebound
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,190 @@
1
+ require 'rspec/core'
2
+ require 'rspec/rebound/version'
3
+ require 'rspec_ext/rspec_ext'
4
+
5
+ module RSpec
6
+ class Rebound
7
+ def self.setup
8
+ RSpec.configure do |config|
9
+ config.add_setting :verbose_retry, :default => false
10
+ config.add_setting :default_retry_count, :default => 1
11
+ config.add_setting :default_sleep_interval, :default => 0
12
+ config.add_setting :exponential_backoff, :default => false
13
+ config.add_setting :clear_lets_on_failure, :default => true
14
+ config.add_setting :display_try_failure_messages, :default => false
15
+
16
+ # retry based on example metadata
17
+ config.add_setting :retry_count_condition, :default => ->(_) { nil }
18
+
19
+ # If a list of exceptions is provided and 'retry' > 1, we only retry if
20
+ # the exception that was raised by the example is NOT in that list. Otherwise
21
+ # we ignore the 'retry' value and fail immediately.
22
+ #
23
+ # If no list of exceptions is provided and 'retry' > 1, we always retry.
24
+ config.add_setting :exceptions_to_hard_fail, :default => []
25
+
26
+ # If a list of exceptions is provided and 'retry' > 1, we only retry if
27
+ # the exception that was raised by the example is in that list. Otherwise
28
+ # we ignore the 'retry' value and fail immediately.
29
+ #
30
+ # If no list of exceptions is provided and 'retry' > 1, we always retry.
31
+ config.add_setting :exceptions_to_retry, :default => []
32
+
33
+ # Callback between retries
34
+ config.add_setting :retry_callback, :default => nil
35
+
36
+ config.around(:each) do |ex|
37
+ ex.run_with_retry
38
+ end
39
+ end
40
+ end
41
+
42
+ attr_reader :context, :ex
43
+
44
+ def initialize(ex, opts = {})
45
+ @ex = ex
46
+ @ex.metadata.merge!(opts)
47
+ current_example.attempts ||= 0
48
+ end
49
+
50
+ def current_example
51
+ @current_example ||= RSpec.current_example
52
+ end
53
+
54
+ def retry_count
55
+ [
56
+ (
57
+ ENV['RSPEC_RETRY_RETRY_COUNT'] ||
58
+ ex.metadata[:retry] ||
59
+ RSpec.configuration.retry_count_condition.call(ex) ||
60
+ RSpec.configuration.default_retry_count
61
+ ).to_i,
62
+ 0
63
+ ].max
64
+ end
65
+
66
+ def attempts
67
+ current_example.attempts ||= 0
68
+ end
69
+
70
+ def attempts=(val)
71
+ current_example.attempts = val
72
+ end
73
+
74
+ def clear_lets
75
+ !ex.metadata[:clear_lets_on_failure].nil? ?
76
+ ex.metadata[:clear_lets_on_failure] :
77
+ RSpec.configuration.clear_lets_on_failure
78
+ end
79
+
80
+ def sleep_interval
81
+ if ex.metadata[:exponential_backoff]
82
+ 2**(current_example.attempts-1) * ex.metadata[:retry_wait]
83
+ else
84
+ ex.metadata[:retry_wait] ||
85
+ RSpec.configuration.default_sleep_interval
86
+ end
87
+ end
88
+
89
+ def exceptions_to_hard_fail
90
+ ex.metadata[:exceptions_to_hard_fail] ||
91
+ RSpec.configuration.exceptions_to_hard_fail
92
+ end
93
+
94
+ def exceptions_to_retry
95
+ ex.metadata[:exceptions_to_retry] ||
96
+ RSpec.configuration.exceptions_to_retry
97
+ end
98
+
99
+ def verbose_retry?
100
+ RSpec.configuration.verbose_retry?
101
+ end
102
+
103
+ def display_try_failure_messages?
104
+ RSpec.configuration.display_try_failure_messages?
105
+ end
106
+
107
+ def run
108
+ example = current_example
109
+ loop do
110
+ if attempts > 0
111
+ RSpec.configuration.formatters.each { |f| f.retry(example) if f.respond_to? :retry }
112
+ if verbose_retry?
113
+ message = "RSpec::Rebound: #{ordinalize(attempts + 1)} try #{example.location}"
114
+ message = "\n" + message if attempts == 1
115
+ RSpec.configuration.reporter.message(message)
116
+ end
117
+ end
118
+
119
+ example.metadata[:retry_attempts] = self.attempts
120
+ example.metadata[:retry_exceptions] ||= []
121
+
122
+ example.clear_exception
123
+ ex.run
124
+
125
+ self.attempts += 1
126
+
127
+ break if example.exception.nil?
128
+
129
+ example.metadata[:retry_exceptions] << example.exception
130
+
131
+ break if attempts >= retry_count + 1
132
+
133
+ if exceptions_to_hard_fail.any?
134
+ break if exception_exists_in?(exceptions_to_hard_fail, example.exception)
135
+ end
136
+
137
+ if exceptions_to_retry.any?
138
+ break unless exception_exists_in?(exceptions_to_retry, example.exception)
139
+ end
140
+
141
+ if verbose_retry? && display_try_failure_messages?
142
+ if attempts != retry_count + 1
143
+ exception_strings =
144
+ if ::RSpec::Core::MultipleExceptionError::InterfaceTag === example.exception
145
+ example.exception.all_exceptions.map(&:to_s)
146
+ else
147
+ [example.exception.to_s]
148
+ end
149
+
150
+ try_message = "\n#{ordinalize(attempts)} Try error in #{example.location}:\n#{exception_strings.join "\n"}\n"
151
+ RSpec.configuration.reporter.message(try_message)
152
+ end
153
+ end
154
+
155
+ example.example_group_instance.clear_lets if clear_lets
156
+
157
+ # If the callback is defined, let's call it
158
+ if RSpec.configuration.retry_callback
159
+ example.example_group_instance.instance_exec(example, &RSpec.configuration.retry_callback)
160
+ end
161
+
162
+ sleep sleep_interval if sleep_interval.to_f > 0
163
+ end
164
+ end
165
+
166
+ private
167
+
168
+ # borrowed from ActiveSupport::Inflector
169
+ def ordinalize(number)
170
+ if (11..13).include?(number.to_i % 100)
171
+ "#{number}th"
172
+ else
173
+ case number.to_i % 10
174
+ when 1; "#{number}st"
175
+ when 2; "#{number}nd"
176
+ when 3; "#{number}rd"
177
+ else "#{number}th"
178
+ end
179
+ end
180
+ end
181
+
182
+ def exception_exists_in?(list, exception)
183
+ list.any? do |exception_klass|
184
+ exception.is_a?(exception_klass) || exception_klass === exception
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ RSpec::Rebound.setup
@@ -0,0 +1,39 @@
1
+ module RSpec
2
+ module Core
3
+ class Example
4
+ attr_accessor :attempts
5
+
6
+ def clear_exception
7
+ @exception = nil
8
+ end
9
+
10
+ class Procsy
11
+ def run_with_retry(opts = {})
12
+ RSpec::Rebound.new(self, opts).run
13
+ end
14
+
15
+ def attempts
16
+ @example.attempts
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ module RSpec
24
+ module Core
25
+ class ExampleGroup
26
+ def clear_memoized
27
+ if respond_to? :__init_memoized, true
28
+ __init_memoized
29
+ else
30
+ @__memoized = nil
31
+ end
32
+ end
33
+
34
+ def clear_lets
35
+ clear_memoized
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/rspec/rebound/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Federico Aldunate", 'Agustin Fornio']
6
+ gem.email = ["tech@windmotion.io"]
7
+ gem.description = %q{A RSpec extension that automatically retries intermittently failing examples to reduce test flakiness and improve reliability in your test suite.}
8
+ gem.summary = %q{Retry intermittently failing RSpec examples to eliminate flaky tests and increase test suite stability without modifying your existing specs.}
9
+ gem.homepage = "https://github.com/windmotion-io/rspec-rebound"
10
+ gem.license = "MIT"
11
+
12
+ gem.required_ruby_version = ">= 2.0"
13
+
14
+ gem.files = `git ls-files`.split($\)
15
+ gem.executables = []
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.name = "rspec-rebound"
18
+ gem.require_paths = ["lib"]
19
+ gem.version = RSpec::Rebound::VERSION
20
+ gem.add_runtime_dependency "rspec-core", "~> 3.3"
21
+ gem.add_development_dependency "rspec", "~> 3.3"
22
+ end