rspec-retryable 0.2.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 236247a97d1e78fbff8c640dfe567b9c47bca7b72dd05e54edc3d6456cf4e412
4
- data.tar.gz: ee51a9030277de2b6cfb3aa7e6be7cd44bb5a2acafe1ed7d7bba6b9d61e0b85c
3
+ metadata.gz: d740994dab3e9b7a7aab752f4588db55caddeac9a51ed0508388ef20b09c341d
4
+ data.tar.gz: ad5919d6b7b34eab56768805e88df68d6be400ecf82c6ba11042bafabedd5ea2
5
5
  SHA512:
6
- metadata.gz: ab64dc3ef170cf3dd8b2dccf555eb16156c5cf84dce5b269fd81ff9a55213985d3e2aba57e4f7819c2f3b1eead695544c7fb6c4a4c1d707c2d3aabf93c6573ff
7
- data.tar.gz: e49515cbf957ed1ebdfcb0e7ba3b6f6415e01d70b0ca5a36801f55e7035ac9555395200af71f3bafe608b64cd9784bc7c20a8cb2408618b5ae32135e54338971
6
+ metadata.gz: c67f9c02d7be75d705b2b2b7fb851e55c9cd364b0071d769386dd63b9f2eb713f00135c10b47e1b4b81ca79dd6ee93a54204a957efa0b827ff3bda91cc5d1c2f
7
+ data.tar.gz: 9f21a5aa684eff320f9d3440f414f16b8c789f783925a69a2d6251130495046d6d3875c8498f97606ecac74354f8ce78f6758d616eda0f9fbbb78e0f77a40ab2
data/README.md CHANGED
@@ -1,35 +1,125 @@
1
1
  # RSpec::Retryable
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
4
-
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rspec/retryable`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ RSpec Retryable is a gem that allows you to retry RSpec examples based on custom handlers. This can be useful for handling flaky tests or tests that depend on external systems.
6
4
 
7
5
  ## Installation
8
6
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
10
-
11
- Install the gem and add to the application's Gemfile by executing:
7
+ Install the gem and add it to the application's Gemfile by executing:
12
8
 
13
9
  ```bash
14
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
10
+ $ bundle add rspec-retryable
15
11
  ```
16
12
 
17
13
  If bundler is not being used to manage dependencies, install the gem by executing:
18
14
 
19
15
  ```bash
20
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
16
+ $ gem install rspec-retryable
21
17
  ```
22
18
 
23
19
  ## Usage
24
20
 
25
- TODO: Write usage instructions here
21
+ Simply calling `RSpec::Retryable.bind` enables the ability to retry on test examples. You can add your first handler by using `RSpec::Retryable.handlers.register(SomeHandler)`.
26
22
 
27
- ## Development
23
+ #### Example
24
+
25
+ Create a file `retry_setup.rb` with the following content:
26
+
27
+ ```retry_setup.rb
28
+ require 'rspec/retryable'
29
+
30
+ class SimpleRetryHandler
31
+ MAX_RETRIES = 2
32
+
33
+ def initialize
34
+ # Initialization code here
35
+ @retries = Hash.new(0)
36
+ end
37
+
38
+ def call(payload)
39
+ # use payload to set retry or not based on RSpec example state
40
+
41
+ if @retries[payload.example.id] < MAX_RETRIES
42
+ # Set `payload.retry` to `true` to enable rspec retry
43
+ payload.retry = true if payload.state == :failed
44
+ else
45
+ # Pass down to next handler
46
+ yield
47
+ end
48
+ end
49
+ end
50
+
51
+ RSpec::Retryable.bind
52
+
53
+ RSpec::Retryable.handlers.register(SimpleRetryHandler)
54
+ ```
55
+
56
+ Then requires the setup in your `spec_helper.rb`
57
+
58
+ ```spec_helper.rb
59
+ require 'retry_setup'
60
+
61
+ RSpec.configure do |config|
62
+ # ... some rspec setup
63
+ end
64
+ ```
65
+
66
+ `payload` holds below information:
67
+
68
+ - `example`: (read-only) RSpec example
69
+ - `state`: Current state of the example, can be alterted by handlers
70
+ - `notify`: default to `true`, if set to `false`, reporter will not be notified
71
+ - `result`: this is the final result returned to RSpec runner
72
+ - `retry`: default to `false`, if set to `true`, the example will be retried
28
73
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
74
+ #### Interact with multiple Handlers
75
+
76
+ Since we use [Chain-of-responsibility pattern](http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern) to define handlers, it's possible to chain handlers with a payload passing down as `Rack::Builder` or `ActionDispatch::MiddlewareStack` to manage a stack of handlers, for example:
77
+
78
+ ```retry_setup.rb
79
+ RSpec::Retryable.bind
80
+
81
+ class FirstRetryHandler
82
+ def call(payload)
83
+ puts "-> First handler in"
84
+
85
+ # ... do something based on payload state ...
86
+
87
+ yield
88
+
89
+ puts "<- First handler out"
90
+ end
91
+ end
92
+
93
+ # This handler stops retry when expected condition met
94
+ class SecondRetryHandler
95
+ def call(payload)
96
+ puts "-> Second handler in"
97
+
98
+ # ... do something based on payload state ...
99
+
100
+ yield
101
+
102
+ puts "<- Second handler out"
103
+ end
104
+ end
105
+
106
+ RSpec::Retryable.handlers.register(FirstRetryHandler)
107
+ RSpec::Retryable.handlers.register(SecondRetryHandler)
108
+ ```
109
+
110
+ When execute tests, the output will look like:
111
+
112
+ ```
113
+ -> First handler in
114
+ -> Second handler in
115
+ <- Second handler out
116
+ <- First handler out
117
+ ```
118
+
119
+ ## Development
30
120
 
31
- 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).
121
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rspec` to run the tests.
32
122
 
33
123
  ## Contributing
34
124
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/ngan/rspec-retryable.
125
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Gusto/rspec-retryable.
@@ -28,8 +28,6 @@ module RSpec
28
28
  if @payload.retry
29
29
  # Replaced the final result by the retry result
30
30
  @payload.result = retry_example
31
- # Update the execution result status to the new state
32
- execution_result.status = @payload.state
33
31
  end
34
32
 
35
33
  # Notify reporter only if it's not handled by the handlers
@@ -58,6 +56,10 @@ module RSpec
58
56
  @payload.notify = false
59
57
  # Duplicate the example for re-run
60
58
  new_example = duplicate_with(metadata)
59
+ # The shared_group_inclusion_backtrace was reserved from duplication, but we need to keep as-is for
60
+ # reporter/formatter to show the correct backtrace.
61
+ # https://github.com/rspec/rspec/blob/0ae9cc43163507458494e631ca8e473bf24cdb26/rspec-core/lib/rspec/core/metadata.rb#L341
62
+ new_example.metadata[:shared_group_inclusion_backtrace] = metadata[:shared_group_inclusion_backtrace]
61
63
  new_example.instance_variable_set(:@id, id)
62
64
  # Taken from https://github.com/rspec/rspec-core/blob/main/lib/rspec/core/example_group.rb#L644-L646
63
65
  instance = new_example.example_group.new(new_example.inspect_output)
@@ -65,7 +67,16 @@ module RSpec
65
67
  # Use same reporter from example instead of the one passing in to behave like
66
68
  # a fresh new example.
67
69
 
68
- new_example.run(instance, reporter)
70
+ result = new_example.run(instance, reporter)
71
+ # Update the execution result status to the new state from retry
72
+ execution_result.status = new_example.execution_result.status
73
+
74
+ if execution_result.status == :failed
75
+ # Sets exception when retry failed
76
+ execution_result.exception = new_example.execution_result.exception
77
+ end
78
+
79
+ result
69
80
  end
70
81
 
71
82
  def notify_reporter
@@ -11,6 +11,10 @@ module RSpec
11
11
  @handlers << klass.new(*args, **kwargs)
12
12
  end
13
13
 
14
+ def reset!
15
+ @handlers.clear
16
+ end
17
+
14
18
  def invoke(payload)
15
19
  traverse(0, payload)
16
20
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module Retryable
5
- VERSION = "0.2.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-retryable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ngan Pham
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-03 00:00:00.000000000 Z
11
+ date: 2025-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-core
@@ -62,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
62
  - !ruby/object:Gem::Version
63
63
  version: '0'
64
64
  requirements: []
65
- rubygems_version: 3.5.9
65
+ rubygems_version: 3.5.22
66
66
  signing_key:
67
67
  specification_version: 4
68
68
  summary: Adds ability to fully control RSpec retrying