cmdx-rspec 1.4.0 → 2.0.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +274 -173
- data/lib/cmdx/rspec/helpers.rb +244 -276
- data/lib/cmdx/rspec/matchers/be_complete.rb +20 -0
- data/lib/cmdx/rspec/matchers/be_deprecated.rb +14 -52
- data/lib/cmdx/rspec/matchers/be_interrupted.rb +20 -0
- data/lib/cmdx/rspec/matchers/be_ko.rb +19 -0
- data/lib/cmdx/rspec/matchers/be_ok.rb +19 -0
- data/lib/cmdx/rspec/matchers/be_successful.rb +8 -20
- data/lib/cmdx/rspec/matchers/have_been_retried.rb +41 -0
- data/lib/cmdx/rspec/matchers/have_been_rolled_back.rb +23 -0
- data/lib/cmdx/rspec/matchers/have_callback.rb +46 -0
- data/lib/cmdx/rspec/matchers/have_chain_root.rb +30 -0
- data/lib/cmdx/rspec/matchers/have_chain_size.rb +29 -0
- data/lib/cmdx/rspec/matchers/have_duration.rb +30 -0
- data/lib/cmdx/rspec/matchers/have_empty_context.rb +4 -16
- data/lib/cmdx/rspec/matchers/have_empty_metadata.rb +3 -9
- data/lib/cmdx/rspec/matchers/have_errors_on.rb +50 -0
- data/lib/cmdx/rspec/matchers/have_failed.rb +7 -24
- data/lib/cmdx/rspec/matchers/have_input.rb +41 -0
- data/lib/cmdx/rspec/matchers/have_matching_context.rb +5 -20
- data/lib/cmdx/rspec/matchers/have_matching_metadata.rb +5 -17
- data/lib/cmdx/rspec/matchers/have_middleware.rb +29 -0
- data/lib/cmdx/rspec/matchers/have_no_errors.rb +30 -0
- data/lib/cmdx/rspec/matchers/have_output.rb +46 -0
- data/lib/cmdx/rspec/matchers/have_pipeline_tasks.rb +27 -0
- data/lib/cmdx/rspec/matchers/have_retry_on.rb +36 -0
- data/lib/cmdx/rspec/matchers/have_skipped.rb +7 -24
- data/lib/cmdx/rspec/matchers/have_tag.rb +30 -0
- data/lib/cmdx/rspec/matchers/raise_cmdx_fault.rb +74 -0
- data/lib/cmdx/rspec/version.rb +2 -1
- data/lib/cmdx/rspec.rb +22 -3
- metadata +24 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9d99809d55db6542a630f55457df90bacbf7598a9969a8a1e54cf27630362030
|
|
4
|
+
data.tar.gz: 7fe0770bb36f09002b9b45cbf01751b0aab0efac7529be7c3c65d5a751399dbb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3fa228ad4eec439aea347ed0c12746f66252e0712dfba58ddd246ffde63102dcedc5c2b2c5816441f9d5eec9a3261937ad19ea22c31b197c74b7e20f5daa8cdc
|
|
7
|
+
data.tar.gz: 5818b4c8a34414a5834abb7e8665480d24b9c0e63ae1d5bebc2f1fa37c5156b9b377ec26cef78251a24c1ce2bd98b4d8f439031aa4ba8efb52a9b8888c903c91
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.0.0] - Unreleased
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Support for CMDx v2
|
|
13
|
+
|
|
14
|
+
### Changes
|
|
15
|
+
- Updated helpers and matchers for new internals
|
|
16
|
+
|
|
9
17
|
## [1.4.0] - 2026-04-09
|
|
10
18
|
|
|
11
19
|
### Added
|
data/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Collection of RSpec matchers for the CMDx framework.
|
|
7
|
+
Collection of RSpec matchers and helpers for the CMDx framework.
|
|
8
8
|
|
|
9
9
|
[Changelog](./CHANGELOG.md) · [Report Bug](https://github.com/drexed/cmdx-rspec/issues) · [Request Feature](https://github.com/drexed/cmdx-rspec/issues)
|
|
10
10
|
|
|
@@ -15,304 +15,405 @@
|
|
|
15
15
|
|
|
16
16
|
# CMDx::RSpec
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
RSpec matchers and helpers for asserting [CMDx](https://github.com/drexed/cmdx) task and workflow behavior — result state, errors, faults, callbacks, retries, chains, and more — without invoking real `work` blocks.
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- Ruby: MRI 3.3+ or a compatible JRuby/TruffleRuby release
|
|
23
|
+
- CMDx 2.0+
|
|
19
24
|
|
|
20
25
|
## Installation
|
|
21
26
|
|
|
22
|
-
|
|
27
|
+
```sh
|
|
28
|
+
gem install cmdx-rspec
|
|
29
|
+
# - or -
|
|
30
|
+
bundle add cmdx-rspec --group test
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Require the library in `spec_helper.rb` (or equivalent):
|
|
23
34
|
|
|
24
35
|
```ruby
|
|
25
|
-
|
|
36
|
+
require "cmdx/rspec"
|
|
26
37
|
```
|
|
27
38
|
|
|
28
|
-
|
|
39
|
+
This loads every matcher under `RSpec::Matchers` and exposes the helpers under `CMDx::RSpec::Helpers`. See [Helpers](#helpers) for how to mix the helpers into your example groups.
|
|
29
40
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Or install it yourself as:
|
|
41
|
+
## Matchers
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
All result-oriented matchers raise `ArgumentError` when given a subject that isn't a `CMDx::Result`. Class-oriented matchers accept either the Task class or an instance.
|
|
35
44
|
|
|
36
|
-
|
|
45
|
+
### Result state & status
|
|
37
46
|
|
|
38
|
-
|
|
47
|
+
#### `be_successful`
|
|
39
48
|
|
|
40
|
-
Asserts
|
|
49
|
+
Asserts a `CMDx::Result` completed with `state: complete` and `status: success`. Extra keyword args are forwarded to a `result.to_h` inclusion check, so any field can be constrained inline.
|
|
41
50
|
|
|
42
51
|
```ruby
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
expect(SomeTask.execute).to be_successful
|
|
53
|
+
expect(SomeTask.execute).to be_successful(metadata: { id: 1 })
|
|
54
|
+
```
|
|
45
55
|
|
|
46
|
-
|
|
47
|
-
|
|
56
|
+
#### `have_skipped`
|
|
57
|
+
|
|
58
|
+
Asserts a result was skipped (`state: interrupted`, `status: skipped`). Extra keyword args constrain other `result.to_h` fields.
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
expect(result).to have_skipped
|
|
62
|
+
expect(result).to have_skipped(
|
|
63
|
+
reason: "out of stock",
|
|
64
|
+
cause: be_a(CMDx::SkipFault)
|
|
65
|
+
)
|
|
48
66
|
```
|
|
49
67
|
|
|
50
|
-
|
|
68
|
+
#### `have_failed`
|
|
51
69
|
|
|
52
|
-
Asserts
|
|
70
|
+
Asserts a result failed (`state: interrupted`, `status: failed`). Extra keyword args constrain other `result.to_h` fields.
|
|
53
71
|
|
|
54
72
|
```ruby
|
|
55
|
-
|
|
56
|
-
|
|
73
|
+
expect(result).to have_failed
|
|
74
|
+
expect(result).to have_failed(
|
|
75
|
+
reason: "boom",
|
|
76
|
+
cause: be_a(NoMethodError)
|
|
77
|
+
)
|
|
78
|
+
```
|
|
57
79
|
|
|
58
|
-
|
|
59
|
-
expect(result).to have_skipped
|
|
80
|
+
#### `be_ok` / `be_ko`
|
|
60
81
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
67
|
-
end
|
|
82
|
+
`be_ok` passes when the result is success or skipped (anything but failed). `be_ko` is its inverse.
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
expect(result).to be_ok
|
|
86
|
+
expect(result).to be_ko
|
|
68
87
|
```
|
|
69
88
|
|
|
70
|
-
|
|
89
|
+
#### `be_complete` / `be_interrupted`
|
|
71
90
|
|
|
72
|
-
|
|
91
|
+
State-only assertions. `be_complete` passes when `state == :complete`; `be_interrupted` when `state == :interrupted`.
|
|
73
92
|
|
|
74
93
|
```ruby
|
|
75
|
-
|
|
76
|
-
|
|
94
|
+
expect(result).to be_complete
|
|
95
|
+
expect(result).to be_interrupted
|
|
96
|
+
```
|
|
77
97
|
|
|
78
|
-
|
|
79
|
-
expect(result).to have_failed
|
|
98
|
+
### Result data
|
|
80
99
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
100
|
+
#### `have_empty_metadata` / `have_matching_metadata`
|
|
101
|
+
|
|
102
|
+
`have_empty_metadata` requires `metadata` to be empty. `have_matching_metadata` performs a partial-hash inclusion match (and delegates to `have_empty_metadata` when called with no args).
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
expect(result).to have_empty_metadata
|
|
106
|
+
expect(result).to have_matching_metadata(status_code: 500)
|
|
88
107
|
```
|
|
89
108
|
|
|
90
|
-
|
|
109
|
+
#### `have_empty_context` / `have_matching_context`
|
|
91
110
|
|
|
92
|
-
|
|
111
|
+
Same pattern for the result's context. Both accept a `Hash`, `CMDx::Context`, or `CMDx::Result` (the result's `.context` is unwrapped automatically).
|
|
93
112
|
|
|
94
113
|
```ruby
|
|
95
|
-
|
|
96
|
-
|
|
114
|
+
expect(result).to have_empty_context
|
|
115
|
+
expect(result).to have_matching_context(stored_id: 123)
|
|
116
|
+
```
|
|
97
117
|
|
|
98
|
-
|
|
99
|
-
|
|
118
|
+
### Errors
|
|
119
|
+
|
|
120
|
+
#### `have_no_errors`
|
|
121
|
+
|
|
122
|
+
Passes when the subject's `errors` collection is empty. Accepts a `CMDx::Result`, `CMDx::Task` instance, or `CMDx::Errors`.
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
expect(result).to have_no_errors
|
|
100
126
|
```
|
|
101
127
|
|
|
102
|
-
|
|
128
|
+
#### `have_errors_on`
|
|
103
129
|
|
|
104
|
-
Asserts
|
|
130
|
+
Asserts at least one error is present under `key`. Optional positional `messages` further constrain the matcher — all must be present.
|
|
105
131
|
|
|
106
132
|
```ruby
|
|
107
|
-
|
|
108
|
-
|
|
133
|
+
expect(result).to have_errors_on(:email)
|
|
134
|
+
expect(result).to have_errors_on(:email, "is required")
|
|
135
|
+
expect(task).to have_errors_on(:email, "is required", "is invalid")
|
|
136
|
+
```
|
|
109
137
|
|
|
110
|
-
|
|
111
|
-
|
|
138
|
+
### Execution metrics
|
|
139
|
+
|
|
140
|
+
#### `have_been_retried`
|
|
141
|
+
|
|
142
|
+
Passes when the result was retried at least once. Pass an integer to require an exact retry count.
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
expect(result).to have_been_retried
|
|
146
|
+
expect(result).to have_been_retried(3)
|
|
112
147
|
```
|
|
113
148
|
|
|
114
|
-
|
|
149
|
+
#### `have_been_rolled_back`
|
|
115
150
|
|
|
116
|
-
|
|
151
|
+
Passes when a failing task ran its rollback hook.
|
|
117
152
|
|
|
118
153
|
```ruby
|
|
119
|
-
|
|
120
|
-
|
|
154
|
+
expect(result).to have_been_rolled_back
|
|
155
|
+
```
|
|
121
156
|
|
|
122
|
-
|
|
123
|
-
|
|
157
|
+
#### `have_duration`
|
|
158
|
+
|
|
159
|
+
Asserts the result's duration (in milliseconds) falls within the supplied bounds. At least one of `:less_than` or `:greater_than` is required.
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
expect(result).to have_duration(less_than: 100)
|
|
163
|
+
expect(result).to have_duration(greater_than: 0.1, less_than: 50)
|
|
124
164
|
```
|
|
125
165
|
|
|
126
|
-
###
|
|
166
|
+
### Faults
|
|
127
167
|
|
|
128
|
-
|
|
168
|
+
#### `raise_cmdx_fault`
|
|
169
|
+
|
|
170
|
+
Block matcher that asserts a `CMDx::Fault` is raised. Optionally constrain by originating task class, reason, or underlying cause.
|
|
129
171
|
|
|
130
172
|
```ruby
|
|
131
|
-
|
|
132
|
-
|
|
173
|
+
expect { SomeTask.execute! }.to raise_cmdx_fault
|
|
174
|
+
expect { SomeTask.execute! }.to raise_cmdx_fault(SomeTask)
|
|
175
|
+
expect { SomeTask.execute! }
|
|
176
|
+
.to raise_cmdx_fault(SomeTask)
|
|
177
|
+
.with_reason(/invalid/)
|
|
178
|
+
.with_cause(MyError)
|
|
179
|
+
```
|
|
133
180
|
|
|
134
|
-
|
|
135
|
-
|
|
181
|
+
`with_reason` accepts a string (equality) or a Regexp; `with_cause` accepts a class (matches via `is_a?`) or a value (matched with `values_match?`).
|
|
182
|
+
|
|
183
|
+
### Chains
|
|
184
|
+
|
|
185
|
+
#### `have_chain_root`
|
|
186
|
+
|
|
187
|
+
Passes when the chain's root task class matches (or is a subclass of) `task_class`. Accepts a `CMDx::Chain` or `CMDx::Result`.
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
expect(result).to have_chain_root(MyWorkflow)
|
|
136
191
|
```
|
|
137
192
|
|
|
138
|
-
|
|
193
|
+
#### `have_chain_size`
|
|
139
194
|
|
|
140
|
-
|
|
195
|
+
Passes when the chain's size matches `expected`. Accepts a `CMDx::Chain` or `CMDx::Result`.
|
|
141
196
|
|
|
142
197
|
```ruby
|
|
143
|
-
|
|
144
|
-
expect(SomeTask).to be_deprecated
|
|
145
|
-
end
|
|
198
|
+
expect(result).to have_chain_size(3)
|
|
146
199
|
```
|
|
147
200
|
|
|
148
|
-
|
|
201
|
+
### Task class declarations
|
|
202
|
+
|
|
203
|
+
These matchers introspect a Task class's configuration. They accept either the class or an instance.
|
|
149
204
|
|
|
150
|
-
|
|
205
|
+
#### `be_deprecated`
|
|
151
206
|
|
|
152
|
-
|
|
207
|
+
Asserts a Task class is marked deprecated. Optionally constrain the deprecation behavior via a positional value or a chained convenience method.
|
|
153
208
|
|
|
154
209
|
```ruby
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
210
|
+
expect(SomeTask).to be_deprecated
|
|
211
|
+
expect(SomeTask).to be_deprecated.with_warning # :warn
|
|
212
|
+
expect(SomeTask).to be_deprecated.with_logging # :log
|
|
213
|
+
expect(SomeTask).to be_deprecated.with_error # :error
|
|
214
|
+
expect(SomeTask).to be_deprecated.with_behavior(:custom)
|
|
158
215
|
```
|
|
159
216
|
|
|
160
|
-
|
|
217
|
+
#### `have_input` / `have_output`
|
|
161
218
|
|
|
162
|
-
|
|
163
|
-
describe MyFeature do
|
|
164
|
-
include CMDx::RSpec::Helpers
|
|
219
|
+
Asserts the class declares the given input/output. Keyword args are matched (partial) against the parameter's serialized `to_h`.
|
|
165
220
|
|
|
166
|
-
|
|
167
|
-
|
|
221
|
+
```ruby
|
|
222
|
+
expect(SomeTask).to have_input(:user_id)
|
|
223
|
+
expect(SomeTask).to have_input(:user_id, type: :integer, required: true)
|
|
224
|
+
expect(SomeTask).to have_output(:total, required: true)
|
|
168
225
|
```
|
|
169
226
|
|
|
170
|
-
|
|
227
|
+
#### `have_callback`
|
|
228
|
+
|
|
229
|
+
Asserts a callback is registered for `event`. Optional `callable` further constrains the match — by `==` for symbols/lambdas, or by `is_a?` when given a class.
|
|
230
|
+
|
|
231
|
+
```ruby
|
|
232
|
+
expect(SomeTask).to have_callback(:before_execution)
|
|
233
|
+
expect(SomeTask).to have_callback(:before_execution, :authenticate!)
|
|
234
|
+
expect(SomeTask).to have_callback(:on_failed, AlertOnFailure)
|
|
235
|
+
```
|
|
171
236
|
|
|
172
|
-
|
|
237
|
+
#### `have_middleware`
|
|
173
238
|
|
|
174
|
-
|
|
239
|
+
Asserts the class registered `middleware`. Class arguments match by `is_a?` or `==`; other values match by `==`.
|
|
175
240
|
|
|
176
241
|
```ruby
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
stub_task_success(SomeTask)
|
|
180
|
-
stub_task_skip(SomeTask)
|
|
181
|
-
stub_task_fail(SomeTask)
|
|
242
|
+
expect(SomeTask).to have_middleware(LoggingMiddleware)
|
|
243
|
+
```
|
|
182
244
|
|
|
183
|
-
|
|
184
|
-
stub_task_success!(SomeTask)
|
|
185
|
-
stub_task_skip!(SomeTask)
|
|
186
|
-
stub_task_fail!(SomeTask)
|
|
245
|
+
#### `have_retry_on`
|
|
187
246
|
|
|
188
|
-
|
|
189
|
-
end
|
|
247
|
+
Asserts the class is configured to retry on `exception`. Keyword args check `CMDx::Retry` configuration values (`:limit`, `:delay`, `:max_delay`, `:jitter`).
|
|
190
248
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
249
|
+
```ruby
|
|
250
|
+
expect(SomeTask).to have_retry_on(Net::OpenTimeout)
|
|
251
|
+
expect(SomeTask).to have_retry_on(Net::OpenTimeout, limit: 5, jitter: :exponential)
|
|
252
|
+
```
|
|
194
253
|
|
|
195
|
-
|
|
196
|
-
stub_task_skip!(SomeTask, some: "value")
|
|
254
|
+
#### `have_tag`
|
|
197
255
|
|
|
198
|
-
|
|
199
|
-
|
|
256
|
+
Asserts the subject carries `tag`. Accepts a Task class (reads `settings.tags`) or a `CMDx::Result` (reads `result.tags`).
|
|
257
|
+
|
|
258
|
+
```ruby
|
|
259
|
+
expect(SomeTask).to have_tag(:critical)
|
|
260
|
+
expect(result).to have_tag(:critical)
|
|
200
261
|
```
|
|
201
262
|
|
|
202
|
-
|
|
263
|
+
### Workflows
|
|
264
|
+
|
|
265
|
+
#### `have_pipeline_tasks`
|
|
266
|
+
|
|
267
|
+
Asserts a `CMDx::Workflow` class declares the given pipeline tasks. Order-sensitive by default; chain `.in_any_order` for set comparison.
|
|
203
268
|
|
|
204
269
|
```ruby
|
|
205
|
-
|
|
206
|
-
|
|
270
|
+
expect(MyWorkflow).to have_pipeline_tasks(StepA, StepB, StepC)
|
|
271
|
+
expect(MyWorkflow).to have_pipeline_tasks(StepA, StepC, StepB).in_any_order
|
|
272
|
+
```
|
|
207
273
|
|
|
208
|
-
|
|
209
|
-
end
|
|
274
|
+
## Helpers
|
|
210
275
|
|
|
211
|
-
|
|
212
|
-
stub_task_skip!(SomeTask, reason: "Skipping for a custom reason")
|
|
276
|
+
### Including helper modules
|
|
213
277
|
|
|
214
|
-
|
|
215
|
-
end
|
|
278
|
+
Mix into all example groups via RSpec config, or include in specific groups:
|
|
216
279
|
|
|
217
|
-
|
|
218
|
-
|
|
280
|
+
```ruby
|
|
281
|
+
RSpec.configure do |config|
|
|
282
|
+
config.include CMDx::RSpec::Helpers
|
|
283
|
+
end
|
|
284
|
+
```
|
|
219
285
|
|
|
220
|
-
|
|
286
|
+
```ruby
|
|
287
|
+
describe MyFeature do
|
|
288
|
+
include CMDx::RSpec::Helpers
|
|
289
|
+
# ...
|
|
221
290
|
end
|
|
222
291
|
```
|
|
223
292
|
|
|
224
|
-
|
|
293
|
+
### Stubs
|
|
294
|
+
|
|
295
|
+
Each stub builds a frozen `CMDx::Result` carrying the requested signal and wires it into a fresh `CMDx::Chain`, so callers see realistic execution shape without invoking the task's `work`. Any extra keyword args (besides the documented ones) are forwarded to `command.new` as context overrides.
|
|
225
296
|
|
|
226
|
-
|
|
297
|
+
#### Result-type stubs
|
|
227
298
|
|
|
228
299
|
```ruby
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
300
|
+
# Non-bang variants stub `SomeTask.execute`
|
|
301
|
+
stub_task_success(SomeTask)
|
|
302
|
+
stub_task_skip(SomeTask)
|
|
303
|
+
stub_task_fail(SomeTask)
|
|
304
|
+
|
|
305
|
+
# Bang variants stub `SomeTask.execute!`
|
|
306
|
+
stub_task_success!(SomeTask)
|
|
307
|
+
stub_task_skip!(SomeTask)
|
|
308
|
+
stub_task_fail!(SomeTask)
|
|
309
|
+
|
|
310
|
+
# Stub a specific argument signature
|
|
311
|
+
stub_task_success(SomeTask, some: "value") # SomeTask.execute(some: "value")
|
|
312
|
+
stub_task_skip!(SomeTask, some: "value") # SomeTask.execute!(some: "value")
|
|
313
|
+
```
|
|
239
314
|
|
|
240
|
-
|
|
315
|
+
Common options:
|
|
241
316
|
|
|
242
|
-
|
|
243
|
-
|
|
317
|
+
```ruby
|
|
318
|
+
stub_task_success(SomeTask, metadata: { id: 1 })
|
|
319
|
+
stub_task_skip!(SomeTask, reason: "out of stock")
|
|
320
|
+
stub_task_fail!(SomeTask, cause: NoMethodError.new("boom"))
|
|
244
321
|
```
|
|
245
322
|
|
|
246
|
-
####
|
|
323
|
+
#### Specialized stubs
|
|
247
324
|
|
|
248
325
|
```ruby
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
326
|
+
# Models the rescued StandardError -> failed signal path that Runtime
|
|
327
|
+
# takes when `work` raises something other than a Fault.
|
|
328
|
+
stub_task_error(SomeTask, Net::OpenTimeout, "boom")
|
|
252
329
|
|
|
253
|
-
|
|
254
|
-
|
|
330
|
+
# Models the `throw!`-then-propagate path used by nested tasks/workflows.
|
|
331
|
+
# `upstream_result` must be a failed CMDx::Result.
|
|
332
|
+
stub_task_throw(SomeTask, upstream_result)
|
|
255
333
|
|
|
256
|
-
|
|
257
|
-
|
|
334
|
+
# Returns a successful Result flagged as `deprecated?` without triggering
|
|
335
|
+
# the real Deprecation action.
|
|
336
|
+
stub_task_deprecated(SomeTask)
|
|
337
|
+
```
|
|
258
338
|
|
|
259
|
-
|
|
260
|
-
# eg: SomeTask.execute(some: "value")
|
|
261
|
-
unstub_task(SomeTask, some: "value")
|
|
339
|
+
#### Workflow stubs
|
|
262
340
|
|
|
263
|
-
|
|
264
|
-
unstub_task!(SomeTask, some: "value")
|
|
341
|
+
`stub_workflow_tasks` yields each distinct Task class reachable from a Workflow's pipeline (first-seen order) so you can stub them in one place.
|
|
265
342
|
|
|
266
|
-
|
|
343
|
+
```ruby
|
|
344
|
+
stub_workflow_tasks(MyWorkflow) do |task|
|
|
345
|
+
case task
|
|
346
|
+
when TaskC then stub_task_skip(task)
|
|
347
|
+
else stub_task_success(task)
|
|
348
|
+
end
|
|
267
349
|
end
|
|
350
|
+
|
|
351
|
+
MyWorkflow.execute
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### Unstubbing
|
|
355
|
+
|
|
356
|
+
Restores the original implementation. When `context` is supplied, only that argument signature is unstubbed.
|
|
357
|
+
|
|
358
|
+
```ruby
|
|
359
|
+
unstub_task(SomeTask) # SomeTask.execute
|
|
360
|
+
unstub_task!(SomeTask) # SomeTask.execute!
|
|
361
|
+
unstub_task(SomeTask, some: "value") # SomeTask.execute(some: "value")
|
|
268
362
|
```
|
|
269
363
|
|
|
270
364
|
### Mocks
|
|
271
365
|
|
|
272
|
-
|
|
366
|
+
Message expectations on `execute` / `execute!`. When `context` is supplied, the expectation is constrained to that signature.
|
|
367
|
+
|
|
368
|
+
```ruby
|
|
369
|
+
expect_task_execution(SomeTask)
|
|
370
|
+
expect_task_execution!(SomeTask)
|
|
371
|
+
expect_task_execution(SomeTask, some: "value")
|
|
372
|
+
|
|
373
|
+
expect_no_task_execution(SomeTask)
|
|
374
|
+
expect_no_task_execution!(SomeTask)
|
|
375
|
+
expect_no_task_execution(SomeTask, some: "value")
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Diagnostics
|
|
273
379
|
|
|
274
|
-
####
|
|
380
|
+
#### `capture_cmdx_logs`
|
|
381
|
+
|
|
382
|
+
Captures lines written to a temporary `CMDx.configuration.logger` for the duration of the block. The previous logger is restored on exit.
|
|
275
383
|
|
|
276
384
|
```ruby
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
expect_no_task_execution(SomeTask)
|
|
385
|
+
logs = capture_cmdx_logs { MyCommand.execute }
|
|
386
|
+
expect(logs.join).to include("status=success")
|
|
387
|
+
```
|
|
281
388
|
|
|
282
|
-
|
|
283
|
-
expect_task_execution!(BangCommand)
|
|
284
|
-
expect_no_task_execution!(SomeTask)
|
|
389
|
+
#### `subscribe_telemetry`
|
|
285
390
|
|
|
286
|
-
|
|
287
|
-
end
|
|
391
|
+
Subscribes to telemetry events on a Task's telemetry registry for the duration of the block and returns every emitted event in order. Tasks subclassing `command` also fire (the registry is shared by reference until `dup`). Defaults to all events in `CMDx::Telemetry::EVENTS`.
|
|
288
392
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
393
|
+
```ruby
|
|
394
|
+
events = subscribe_telemetry(MyCommand, :task_executed) { MyCommand.execute }
|
|
395
|
+
expect(events.map(&:name)).to eq([:task_executed])
|
|
396
|
+
```
|
|
293
397
|
|
|
294
|
-
|
|
295
|
-
expect_task_execution!(SomeTask, some: "value")
|
|
296
|
-
expect_no_task_execution!(SomeTask, some: "value")
|
|
398
|
+
#### `with_cmdx_chain`
|
|
297
399
|
|
|
298
|
-
|
|
299
|
-
|
|
400
|
+
Captures the `CMDx::Chain` produced by the first root execution of `command` within the block. Returns `nil` if `command` didn't run as a root.
|
|
401
|
+
|
|
402
|
+
```ruby
|
|
403
|
+
chain = with_cmdx_chain(MyWorkflow) { MyWorkflow.execute }
|
|
404
|
+
expect(chain.size).to be > 1
|
|
300
405
|
```
|
|
301
406
|
|
|
302
407
|
## Development
|
|
303
408
|
|
|
304
|
-
|
|
409
|
+
Run `bin/setup` to install dependencies, then `rake spec` to run the tests. Use `bin/console` for an interactive prompt.
|
|
305
410
|
|
|
306
|
-
|
|
411
|
+
Release flow: bump `lib/cmdx/rspec/version.rb`, then `bundle exec rake release` to tag, push, and publish to [rubygems.org](https://rubygems.org).
|
|
307
412
|
|
|
308
413
|
## Contributing
|
|
309
414
|
|
|
310
|
-
Bug reports and pull requests are welcome
|
|
415
|
+
Bug reports and pull requests are welcome at <https://github.com/drexed/cmdx-rspec>. Contributors are expected to follow the [code of conduct](https://github.com/drexed/cmdx-rspec/blob/master/CODE_OF_CONDUCT.md).
|
|
311
416
|
|
|
312
417
|
## License
|
|
313
418
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
## Code of Conduct
|
|
317
|
-
|
|
318
|
-
Everyone interacting in the Cmdx::Rspec project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/drexed/cmdx-rspec/blob/master/CODE_OF_CONDUCT.md).
|
|
419
|
+
Released under the [MIT License](https://opensource.org/licenses/MIT).
|