trailblazer-test 0.1.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 484e57db55ede663a53082654e62fc6d12b1384b1591718dfc7fc440c59dd86b
4
- data.tar.gz: 5595d2f6daab154412e612e226474e1e88592e82ebdc8d8a1cdf8afc1849ae1e
3
+ metadata.gz: 25326dbdb940038e49c6830ac6c4c833583c13db2d5f11782cac2b457f0836cb
4
+ data.tar.gz: e0639ac0cacc534a105138840e15f1019c9136c30042d8ef5d28c80eeb4800fa
5
5
  SHA512:
6
- metadata.gz: 302594051f040ca9c3570ac2316cfb5c0a511814727fffc74727b9b2bd0d2adea2ee56a7037406af11c02c93b5c6fa91e7a0a28517352db72c2f6e99949b60c7
7
- data.tar.gz: a510c4907ace3ba13e59872d698c8771705bd3047072e3296141381a9c0281ce36bae05759038052dc98a2e0e3421b8e5d3dae9ce28dc4249dab3289367e4ba0
6
+ metadata.gz: 00332de32685126953eff6bfc0f1384f497e431e4ec1038a2f33a04cd3b37f762c8612c6834757a81095633ceaf55c748a799bf925ce27c923b5a391e8d2481d
7
+ data.tar.gz: a09347b703bf1eb6298f63b3e0c3b4481590e92b29b3d8abfb7e192e28a1986a94e2eafb1ff1d18792fc9693c94bcc4cad0cbec922ff9aff637e8ac2cc12fb4f
@@ -0,0 +1,20 @@
1
+ ## This file is managed by Terraform.
2
+ ## Do not modify this file directly, as it may be overwritten.
3
+ ## Please open an issue instead.
4
+ name: CI
5
+ on: [push, pull_request]
6
+ jobs:
7
+ test:
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ # commenting out 2.7 because of dry.
12
+ ruby: ['3.0', '3.1', '3.2', "3.3", "head", "jruby"]
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v3
16
+ - uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ bundler-cache: true
20
+ - run: bundle exec rake
data/CHANGES.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 1.0.0
2
+
3
+ * Releasing the first stable version.
4
+
1
5
  # 0.1.1
2
6
 
3
7
  * Added `mock_step` helper to mock activity's or nested activity's step
data/Gemfile CHANGED
@@ -2,3 +2,10 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in trailblazer-test.gemspec
4
4
  gemspec
5
+
6
+ # gem "reform-rails", path: "../reform-rails"
7
+
8
+ gem "trailblazer-endpoint", path: "../trailblazer-endpoint"
9
+ # gem "trailblazer-core-utils", path: "../trailblazer-core-utils"
10
+ # gem "trailblazer-endpoint", github: "trailblazer/trailblazer-endpoint"
11
+ gem "ostruct"
data/README.md CHANGED
@@ -1,140 +1,45 @@
1
1
  # Trailblazer::Test
2
2
 
3
- [![Build Status](https://travis-ci.org/trailblazer/trailblazer-test.svg)](https://travis-ci.org/trailblazer/trailblazer-test)
4
- [![Gem Version](https://badge.fury.io/rb/trailblazer-test.svg)](http://badge.fury.io/rb/trailblazer-test)
3
+ _Assertions and helpers for operation unit tests._
5
4
 
6
- ## Usage
5
+ The [comprehensive docs are here](https://trailblazer.to/2.1/docs/test/).
7
6
 
8
- Testing Trailblazer applications usually involves the following tests.
7
+ Read our introducing blog post for a better overview.
9
8
 
10
- 1. **Unit tests for operations**: They test all edge cases in a nice, fast unit test environment without any HTTP involved.
11
- 2. **Integration tests for controllers**: These Smoke tests only test the wiring between controller, operation and presentation layer. Usually, a coded click path simulates you manually clicking through your app and testing if it works. The preferred way here is using Rack-test and Capybara.
12
- 3. **Unit tests for cells** By invoking your cells with arbitrary data you functionally test the rendered markup using Capybara.
13
-
14
- All the up to date details on the available assertions and helpers is available at [official documentation](http://2019.trailblazer.to/2.1/docs/trailblazer.html#trailblazer-test).
15
-
16
- ### Assertions
17
-
18
- To use available assertions, add in your test `_helper` the following modules:
19
-
20
- ```ruby
21
- include Trailblazer::Test::Assertions
22
- include Trailblazer::Test::Operation::Assertions
23
- ```
24
-
25
- If you are using Trailblazer v2.0 you need to add also:
26
-
27
- ```ruby
28
- require "trailblazer/test/deprecation/operation/assertions"
29
-
30
- include Trailblazer::Test::Deprecation::Operation::Assertions # in your test class
31
- ```
32
-
33
- [Learn more](http://2019.trailblazer.to/2.1/docs/trailblazer.html#trailblazer-test-assertions)
34
-
35
- #### assert_pass
36
-
37
- Use `assert_pass` to run an operation and assert it was successful, while checking if the attributes of the operation's `model` are what you're expecting.
38
-
39
- ```ruby
40
- it { assert_pass Blog::Operation::Create, { params: { title: "Ruby Soho" } }, title: "Ruby Soho" }
41
- ```
42
-
43
- #### assert_fail
44
-
45
- To test an unsuccessful outcome of an operation, use `assert_fail`. This is used for testing all kinds of validations. By passing insufficient or wrong data to the operation, it will fail and mark errors on the errors object.
46
-
47
- ```ruby
48
- it { assert_fail Blog::Operation::Update, { params: { band: nil } }, expected_errors: [:band] }
49
- ```
50
-
51
- #### assert_policy_fail
52
-
53
- This will test that the operation fails due to a policy failure.
54
-
55
- ```ruby
56
- it { assert_policy_fail Blog::Operation::Delete, ctx({title: "Ruby Soho"}, current_user: not_allowed_user) }
57
- ```
58
-
59
- #### assert_exposes
60
-
61
- Test attributes of an arbitrary object.
62
-
63
- ```ruby
64
- it { assert_exposes model, title: "Timebomb", band: "Rancid" }
65
- ```
66
-
67
- ### Helpers
9
+ ## Installation
68
10
 
69
- There are several helpers to deal with operation tests and operations used as factories.
70
- Add this in your `_helper.rb` file to use all available helpers.
11
+ Add the following line to your project's `Gemfile`.
71
12
 
72
13
  ```ruby
73
- include Trailblazer::Test::Operation::Helper
14
+ gem "trailblazer-test", ">= 1.0.0", "< 2.0.0"
74
15
  ```
75
16
 
76
- [Learn more](http://2019.trailblazer.to/2.1/docs/trailblazer.html#trailblazer-test-helpers)
17
+ ## Overview
77
18
 
78
- #### call
19
+ This gem adds the following assertions and helpers:
79
20
 
80
- Instead of manually invoking an operation, you can use the `call` helper.
81
-
82
- ```ruby
83
- it do
84
- result = call Blog::Operation::Create, params: {title: "Shipwreck", band: "Rancid"}
85
- # use `result` object however you want
86
- end
87
- ```
21
+ * `#assert_pass` to test an operation terminating with success.
22
+ * `#assert_fail` to assert validation errors and the like.
23
+ * `#mock_step` helping the replace steps with stubs.
88
24
 
89
- #### factory
25
+ ## Example
90
26
 
91
- The `factory` method calls the operation and raises an error should the operation have failed. If successful, it will do the exact same thing `call` does.
27
+ An example test case checking if an operation passed and created a model could look as follows.
92
28
 
93
29
  ```ruby
94
- it do
95
- assert_raises do
96
- factory Blog::Operation::Create, params: {title: "Shipwreck", band: "The Chats"}
97
- end
98
- end
99
- ```
100
-
101
- #### mock_step
30
+ # test/operation/memo_test.rb
102
31
 
103
- This helper allows you to mock any step within a given or deeply nested activities. For example,
32
+ require "test_helper"
104
33
 
105
- ```ruby
106
- class Show < Trailblazer::Operation
107
- step :load_user
108
- ...
109
- end
110
- ```
34
+ class MemoOperationTest < Minitest::Spec
35
+ Trailblazer::Test.module!(self) # install our helpers.
111
36
 
112
- To skip processing inside `:load_user` and use a mock instead, use `mock_step`.
113
-
114
- ```ruby
115
- it do
116
- new_activity = mock_step(Show, id: :load_user) do |ctx|
117
- ctx[:user] = Struct.new(:name).new('Mocky')
118
- end
119
-
120
- assert_pass new_activity, {}, {} do |ctx|
121
- assert_equal ctx[:user].name, 'Mocky'
37
+ it "passes with valid input" do
38
+ # ...
39
+ assert_pass Memo::Operation::Create, input,
40
+ content: "Stock up beer",
41
+ persisted?: true,
42
+ id: ->(asserted:, **) { asserted.id > 0 }
122
43
  end
123
44
  end
124
45
  ```
125
-
126
- ## Installation
127
-
128
- Add this line to your application's Gemfile:
129
-
130
- ```ruby
131
- gem 'trailblazer-test'
132
- ```
133
-
134
- And then execute:
135
-
136
- $ bundle
137
-
138
- Or install it yourself as:
139
-
140
- $ gem install trailblazer-test
data/Rakefile CHANGED
@@ -1,8 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
- require "rubocop/rake_task"
4
-
5
- RuboCop::RakeTask.new(:rubocop)
6
3
 
7
4
  Rake::TestTask.new(:test) do |t|
8
5
  t.libs << "test"
@@ -0,0 +1,73 @@
1
+ module Trailblazer
2
+ module Test
3
+ module Assertion
4
+ module AssertExposes
5
+ # Test if all `tuples` values on `asserted` match the expected values.
6
+ # @param asserted Object Object that exposes attributes to test
7
+ # @param tuples Hash Key/value attribute pairs to test
8
+ # @param options Hash Default :reader is `asserted.{name}`,
9
+ # TODO: test err msgs!
10
+ def assert_exposes(asserted, expected=nil, reader: nil, **options)
11
+ expected = options.any? ? options : expected # allow passing {expected} as kwargs, too.
12
+
13
+ _assert_exposes_for(asserted, expected, reader: reader)
14
+ end
15
+
16
+ # def assert_exposes_hash(asserted, expected)
17
+ # _assert_exposes_for(asserted, expected, reader: :[])
18
+ # end
19
+
20
+ # @private
21
+ def _assert_exposes_for(asserted, expected, **options)
22
+ passed, matches, last_failed = Assert.assert_attributes(asserted, expected, **options) do |_matches, last_failed|
23
+ name, expected_value, actual_value, _passed, is_eq, error_msg = last_failed
24
+
25
+ is_eq ? assert_equal(expected_value, actual_value, error_msg) : assert(expected_value, error_msg)
26
+
27
+ return false
28
+ end
29
+
30
+ return true
31
+ end
32
+
33
+ module Assert
34
+ module_function
35
+
36
+ # Yields {block} if tuples don't match/failed.
37
+ def assert_attributes(asserted, expected, reader: false, &block)
38
+ passed, matches, last_failed = match_tuples(asserted, expected, reader: reader)
39
+
40
+ yield matches, last_failed unless passed
41
+
42
+ return passed, matches, last_failed
43
+ end
44
+
45
+ # Test if all properties match using our own {#test_equal}.
46
+ # @private
47
+ def match_tuples(asserted, expected, reader:)
48
+ passed = true # goes {false} if one or more attributes didn't match.
49
+
50
+ matches = expected.collect do |k, v|
51
+ actual = Test::Assertion.actual(asserted, reader, k)
52
+ expected, is_eq = Test::Assertion.expected(asserted, v, actual)
53
+
54
+ is_eq ?
55
+ [k, expected, actual, passed &= test_equal(expected, actual), is_eq, "Property [#{k}] mismatch"] :
56
+ [k, expected, actual, passed &= test_true(expected, actual), is_eq, "Actual: #{actual.inspect}."]
57
+ end
58
+
59
+ [passed, matches, matches.find { |k, v, actual, passed, *| !passed }]
60
+ end
61
+
62
+ def test_equal(expected, actual)
63
+ expected == actual
64
+ end
65
+
66
+ def test_true(expected, actual)
67
+ !! expected
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,58 @@
1
+ module Trailblazer
2
+ module Test
3
+ module Assertion
4
+ module AssertFail
5
+ module_function
6
+
7
+ extend AssertPass::Utils
8
+
9
+ # {expected_errors} can be nil when using the {#assert_fail} block syntax.
10
+ def call(activity, ctx, expected_errors=nil, test:, invoke:, **kws)
11
+ signal, ctx, _ = invoke.(activity, ctx)
12
+
13
+ assert_fail_with_model(signal, ctx, expected_errors: expected_errors, test: test, operation: activity, **kws)
14
+ end
15
+
16
+ # @private
17
+ def assert_fail_with_model(signal, ctx, test:, **options)
18
+ assert_after_call(ctx, **options) do |ctx|
19
+
20
+ test.assert_equal *arguments_for_assert_fail(signal), error_message_for_assert_fail_after_call(signal, ctx, **options)
21
+
22
+ if options[:expected_errors]
23
+ # TODO: allow error messages from somewhere else.
24
+ # only test _if_ errors are present, not the content.
25
+ colored_errors = AssertPass::Errors.colored_errors_for(ctx)
26
+
27
+ test.assert_equal *arguments_for_assert_contract_errors(signal, ctx, contract_name: :default, **options), "Actual contract errors: #{colored_errors}"
28
+ end
29
+ end
30
+ end
31
+
32
+ def arguments_for_assert_fail(signal)
33
+ return false, Assertion::SUCCESS_TERMINI.include?(signal.to_h[:semantic]) # FIXME: same logic as in {#assert_pass}.
34
+ end
35
+
36
+ def arguments_for_assert_contract_errors(signal, ctx, contract_name:, expected_errors:, **)
37
+ with_messages = expected_errors.is_a?(Hash)
38
+
39
+ raise ExpectedErrorsTypeError, "expected_errors has to be an Array or Hash" unless expected_errors.is_a?(Array) || with_messages # TODO: test me!
40
+
41
+ errors = ctx[:"contract.#{contract_name}"].errors.messages # TODO: this will soon change with the operation Errors object.
42
+
43
+ if with_messages
44
+ expected_errors = expected_errors.collect { |k, v| [k, Array(v)] }.to_h
45
+
46
+ return expected_errors, errors
47
+ else
48
+ return expected_errors.sort, errors.keys.sort
49
+ end
50
+ end
51
+
52
+ def error_message_for_assert_fail_after_call(signal, ctx, operation:, **)
53
+ %{{#{operation}} didn't fail, it passed}
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,101 @@
1
+ module Trailblazer
2
+ module Test
3
+ module Assertion
4
+ module AssertPass
5
+ module_function
6
+
7
+ def call(activity, ctx, invoke:, **options)
8
+ signal, ctx, _ = invoke.(activity, ctx)
9
+
10
+ assert_pass_with_model(signal, ctx, operation: activity, **options)
11
+ end
12
+
13
+ def assert_pass_with_model(signal, ctx, **options)
14
+ assert_after_call(ctx, **options) do |ctx|
15
+ Passed.new.call(signal, ctx, **options)
16
+ PassedWithAttributes.new.call(signal, ctx, **options)
17
+ end
18
+ end
19
+
20
+ class Passed
21
+ # Check if the operation terminates on {:success}.
22
+ # @semi-public Used in rspec-trailblazer
23
+ def call(signal, ctx, **options)
24
+ expected_outcome, actual_outcome = arguments_for_assertion(signal)
25
+ error_msg = error_message(signal, ctx, **options) # DISCUSS: compute error message before there was an error?
26
+
27
+ outcome = assertion(expected_outcome, actual_outcome, error_msg, **options)
28
+ return outcome, error_msg
29
+ end
30
+
31
+ # What needs to be compared?
32
+ def arguments_for_assertion(signal)
33
+ return true, Assertion::SUCCESS_TERMINI.include?(signal.to_h[:semantic])
34
+ end
35
+
36
+ def error_message(signal, ctx, operation:, **)
37
+ colored_errors = Errors.colored_errors_for(ctx)
38
+
39
+ %{{#{operation}} failed: #{colored_errors}} # FIXME: only if contract's there!
40
+ end
41
+
42
+ def assertion(expected_outcome, actual_outcome, error_msg, test:, **)
43
+ test.assert_equal(
44
+ expected_outcome,
45
+ actual_outcome,
46
+ error_msg
47
+ )
48
+ end
49
+ end
50
+
51
+ # @semi-public Used in rspec-trailblazer
52
+ class PassedWithAttributes
53
+ def call(signal, ctx, **options)
54
+ model = model_for(ctx, **options)
55
+
56
+ outcome, error_msg = assertion(ctx, **options, model: model)
57
+ return outcome, error_msg
58
+ end
59
+
60
+ # DISCUSS: should we default options like {:model_at} here?
61
+ def model_for(ctx, model_at: :model, **)
62
+ ctx[model_at]
63
+ end
64
+
65
+ def assertion(ctx, model:, expected_model_attributes:, test:, **)
66
+ test.assert_exposes(model, expected_model_attributes)
67
+ end
68
+ end
69
+
70
+ module Utils
71
+ # @private
72
+ def assert_after_call(ctx, user_block:, **kws)
73
+ yield(ctx)
74
+
75
+ user_block.call(ctx) if user_block
76
+
77
+ ctx
78
+ end
79
+ end # Utils
80
+
81
+ module Errors
82
+ module_function
83
+
84
+ def colored_errors_for(ctx)
85
+ # TODO: generic errors object "finding"
86
+ errors =
87
+ if ctx[:"contract.default"]
88
+ ctx[:"contract.default"].errors.messages.inspect
89
+ else
90
+ ""
91
+ end
92
+
93
+ colored_errors = %{\e[33m#{errors}\e[0m}
94
+ end
95
+ end
96
+
97
+ extend Utils
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,114 @@
1
+ module Trailblazer
2
+ module Test
3
+ # Top-level entry points for end users.
4
+ # These methods expose the end user syntax, not the logic.
5
+ module Assertion
6
+ def self.module!(receiver, activity: false, suite: false, spec: true)
7
+ modules = [Helper::MockStep, AssertExposes]
8
+ if suite
9
+ modules += [Suite, Suite::Spec] if spec
10
+ modules += [Suite, Suite::Test] if suite && !spec
11
+ else
12
+ modules += [Assertion]
13
+ end
14
+
15
+ modules += [Assertion::Activity] if activity
16
+
17
+ receiver.include(*modules.reverse)
18
+ end
19
+
20
+ SUCCESS_TERMINI = [:success, :pass_fast] # DISCUSS: where should this be defined?
21
+
22
+ # @private
23
+ # Invoker for Operation
24
+ def self.invoke_operation(operation, ctx)
25
+ result = operation.call(ctx)
26
+
27
+ return result.terminus, result # translate the holy {Operation::Result} object back to a normal "circuit interface" return value.
28
+ end
29
+
30
+ # @private
31
+ # Invoker with debugging for Operation
32
+ def self.invoke_operation_with_wtf(operation, ctx)
33
+ result = operation.wtf?(ctx)
34
+
35
+ return result.terminus, result
36
+ end
37
+
38
+ # Evaluate value if it's a lambda, and let the caller know whether we need an
39
+ # assert_equal or an assert.
40
+ def self.expected(asserted, value, actual)
41
+ value.is_a?(Proc) ? [value.(actual: actual, asserted: asserted), false] : [value, true]
42
+ end
43
+
44
+ # # Read the actual value from the asserted object (e.g. a model).
45
+ def self.actual(asserted, reader, name)
46
+ reader ? asserted.public_send(reader, name) : asserted.public_send(name)
47
+ end
48
+
49
+ # DISCUSS: move to Assertion::Minitest?
50
+ # Test case instance method. Specific to Minitest.
51
+ def assert_pass(activity, options, invoke: Assertion.method(:invoke_operation), model_at: :model, **kws, &block)
52
+ # DISCUSS: {:model_at} and {:invoke_method} block actual attributes.
53
+ AssertPass.(activity, options,
54
+ test: self,
55
+ user_block: block,
56
+ expected_model_attributes: kws,
57
+ model_at: model_at,
58
+ invoke: invoke,
59
+ ) # Forward {#assert_pass} to {AssertPass.call} or wherever your implementation sits.
60
+ end
61
+
62
+ # DISCUSS: move to Assertion::Minitest?
63
+ # Test case instance method. Specific to Minitest.
64
+ def assert_fail(activity, options, *args, invoke: Assertion.method(:invoke_operation), **kws, &block)
65
+ AssertFail.(activity, options, *args, test: self, user_block: block, invoke: invoke, **kws) # Forward {#assert_fail} to {AssertFail.call} or wherever your implementation sits.
66
+ end
67
+
68
+ def assert_pass?(*args, **options, &block)
69
+ assert_pass(*args, **options, invoke: Assertion.method(:invoke_operation_with_wtf), &block)
70
+ end
71
+
72
+ def assert_fail?(*args, **options, &block)
73
+ assert_fail(*args, **options, invoke: Assertion.method(:invoke_operation_with_wtf), &block)
74
+ end
75
+
76
+ # Assertions for Activity, not for Operation.
77
+ module Activity
78
+ def self.invoke_activity(activity, ctx)
79
+ signal, (ctx, _) = activity.call([ctx, {}]) # call with circuit interface. https://trailblazer.to/2.1/docs/operation/#operation-internals-circuit-interface
80
+
81
+ return signal, ctx
82
+ end
83
+
84
+ def self.invoke_activity_with_task_wrap(activity, ctx)
85
+ signal, (ctx, _) = ::Trailblazer::Activity::TaskWrap.invoke(activity, [ctx, {}]) # call with circuit interface. https://trailblazer.to/2.1/docs/operation/#operation-internals-circuit-interface
86
+
87
+ return signal, ctx
88
+ end
89
+
90
+ def self.invoke_activity_with_tracing(activity, ctx)
91
+ signal, (ctx, _) = Developer::Wtf.invoke(activity, [ctx, {}])
92
+
93
+ return signal, ctx
94
+ end
95
+
96
+ def assert_pass(*args, invoke: Activity.method(:invoke_activity_with_task_wrap), **options, &block)
97
+ super(*args, **options, invoke: invoke, &block)
98
+ end
99
+
100
+ def assert_fail(*args, invoke: Activity.method(:invoke_activity_with_task_wrap), **options, &block)
101
+ super(*args, **options, invoke: invoke, &block)
102
+ end
103
+
104
+ def assert_pass?(*args, **options, &block)
105
+ assert_pass(*args, **options, invoke: Activity.method(:invoke_activity_with_tracing), &block)
106
+ end
107
+
108
+ def assert_fail?(*args, **options, &block)
109
+ assert_fail(*args, **options, invoke: Activity.method(:invoke_activity_with_tracing), &block)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,5 @@
1
+ module Trailblazer::Test
2
+ class Context < Hash
3
+ # TODO: override {#inspect}
4
+ end
5
+ end
@@ -0,0 +1,42 @@
1
+ module Trailblazer
2
+ module Test
3
+ # DISCUSS: this is not really endpoint related, it's more like setting a "global" invocation mechanism.
4
+ module Endpoint
5
+ # DISCUSS: not sure this is the final "technique" to use the global endpoint invoker.
6
+ def self.module!(receiver, invoke_method:, invoke_method_wtf:)
7
+ receiver.class_eval do
8
+ @@INVOKE_METHOD = invoke_method
9
+ @@INVOKE_METHOD_WTF = invoke_method_wtf
10
+
11
+ def trailblazer_test_invoke_method
12
+ @@INVOKE_METHOD
13
+ end
14
+
15
+ def trailblazer_test_invoke_method_wtf
16
+ @@INVOKE_METHOD_WTF
17
+ end
18
+ end
19
+
20
+ Assertion
21
+ end
22
+
23
+ module Assertion
24
+ def assert_pass(*args, invoke: trailblazer_test_invoke_method, **options, &block)
25
+ super(*args, **options, invoke: invoke, &block)
26
+ end
27
+
28
+ def assert_fail(*args, invoke: trailblazer_test_invoke_method, **options, &block)
29
+ super(*args, **options, invoke: invoke, &block)
30
+ end
31
+
32
+ def assert_pass?(*args, **options, &block)
33
+ assert_pass(*args, **options, invoke: trailblazer_test_invoke_method_wtf, &block)
34
+ end
35
+
36
+ def assert_fail?(*args, **options, &block)
37
+ assert_fail(*args, **options, invoke: trailblazer_test_invoke_method_wtf, &block)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,19 @@
1
+ module Trailblazer::Test
2
+ module Helper
3
+ module MockStep
4
+ def mock_step(activity, path:, &block)
5
+ raise ArgumentError, "Missing block: `#mock_step` requires a block." unless block_given?
6
+
7
+ mocked_step_id, path = path.last, path[0..-2]
8
+
9
+ mock_step = ->(ctx, **) { yield(ctx) }
10
+ mock_instruction = -> { step mock_step, replace: mocked_step_id }
11
+
12
+
13
+ Trailblazer::Activity::DSL::Linear::Patch.(activity, path, mock_instruction)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ # [:delete_assets] => -> { step Destroy.method(:tidy_storage), before: :rm_uploads }