trailblazer-test 0.1.1 → 1.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 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 }