trailblazer-test 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 +7 -0
- data/.gitignore +9 -0
- data/.rubocop-https---raw-githubusercontent-com-trailblazer-meta-master-rubocop-yml +115 -0
- data/.rubocop.yml +17 -0
- data/.travis.yml +16 -0
- data/CHANGES.md +8 -0
- data/Gemfile +4 -0
- data/README.md +211 -0
- data/Rakefile +13 -0
- data/lib/trailblazer/test.rb +12 -0
- data/lib/trailblazer/test/assertions.rb +37 -0
- data/lib/trailblazer/test/deprecation/operation/assertions.rb +42 -0
- data/lib/trailblazer/test/deprecation/operation/helper.rb +28 -0
- data/lib/trailblazer/test/operation/assertions.rb +89 -0
- data/lib/trailblazer/test/operation/helper.rb +38 -0
- data/lib/trailblazer/test/operation/policy_assertions.rb +13 -0
- data/lib/trailblazer/test/version.rb +5 -0
- data/trailblazer-test.gemspec +29 -0
- metadata +144 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 02bdfafb7d0c3648980cf33724a89d9954428fbd8466fd0f58df7fe0366b8d25
         | 
| 4 | 
            +
              data.tar.gz: 2753cb581aa889d898f5b23bff1daa44e802150e877087d32faf7e3a46357f90
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 9e999f603f7944601d56d17c18e1cbfebe43234fa539e5c7ce9176ca5cf3e1aa2e211bcc1097569b372776020a9b63c6fb86a0f8a350968bea4b0dc755a2eafb
         | 
| 7 | 
            +
              data.tar.gz: 4701ebcfbb62202dcac8bbcc13149779c63add90ab9471484f1495a5a3a7ca682ee2e17c9210e8c70543f0707939edb3c4bda9d2de46283a54e9e91e5f0a024f
         | 
    
        data/.gitignore
    ADDED
    
    
| @@ -0,0 +1,115 @@ | |
| 1 | 
            +
            AllCops:
         | 
| 2 | 
            +
              TargetRubyVersion: 2.5.0
         | 
| 3 | 
            +
              DisplayCopNames: true
         | 
| 4 | 
            +
            Layout/CaseIndentation:
         | 
| 5 | 
            +
              IndentOneStep: true
         | 
| 6 | 
            +
            Layout/FirstArrayElementLineBreak:
         | 
| 7 | 
            +
              Enabled: true
         | 
| 8 | 
            +
            Layout/FirstHashElementLineBreak:
         | 
| 9 | 
            +
              Enabled: true
         | 
| 10 | 
            +
            Layout/FirstMethodArgumentLineBreak:
         | 
| 11 | 
            +
              Enabled: true
         | 
| 12 | 
            +
            Layout/FirstMethodParameterLineBreak:
         | 
| 13 | 
            +
              Enabled: true
         | 
| 14 | 
            +
            Layout/MultilineAssignmentLayout:
         | 
| 15 | 
            +
              Enabled: true
         | 
| 16 | 
            +
              EnforcedStyle: same_line
         | 
| 17 | 
            +
            Layout/SpaceInsideHashLiteralBraces:
         | 
| 18 | 
            +
              EnforcedStyle: no_space
         | 
| 19 | 
            +
            Metrics/LineLength:
         | 
| 20 | 
            +
              Max: 130
         | 
| 21 | 
            +
            Metrics/ParameterLists:
         | 
| 22 | 
            +
              Max: 5
         | 
| 23 | 
            +
            Naming/VariableNumber:
         | 
| 24 | 
            +
              EnforcedStyle: snake_case
         | 
| 25 | 
            +
            Style/AndOr:
         | 
| 26 | 
            +
              EnforcedStyle: conditionals
         | 
| 27 | 
            +
            Style/AutoResourceCleanup:
         | 
| 28 | 
            +
              Enabled: true
         | 
| 29 | 
            +
            Style/CollectionMethods:
         | 
| 30 | 
            +
              Enabled: true
         | 
| 31 | 
            +
            Style/Documentation:
         | 
| 32 | 
            +
              Enabled: false
         | 
| 33 | 
            +
            Style/EmptyLiteral:
         | 
| 34 | 
            +
              Enabled: false
         | 
| 35 | 
            +
            Style/EmptyMethod:
         | 
| 36 | 
            +
              EnforcedStyle: expanded
         | 
| 37 | 
            +
            Style/FormatStringToken:
         | 
| 38 | 
            +
              EnforcedStyle: template
         | 
| 39 | 
            +
            Style/ImplicitRuntimeError:
         | 
| 40 | 
            +
              Enabled: true
         | 
| 41 | 
            +
            Style/MethodCalledOnDoEndBlock:
         | 
| 42 | 
            +
              Enabled: true
         | 
| 43 | 
            +
            Style/MethodDefParentheses:
         | 
| 44 | 
            +
              EnforcedStyle: require_parentheses
         | 
| 45 | 
            +
            Style/MissingElse:
         | 
| 46 | 
            +
              Enabled: true
         | 
| 47 | 
            +
              EnforcedStyle: case
         | 
| 48 | 
            +
            Style/NumericLiterals:
         | 
| 49 | 
            +
              Enabled: false
         | 
| 50 | 
            +
            Style/OptionHash:
         | 
| 51 | 
            +
              Enabled: true
         | 
| 52 | 
            +
            Style/PercentLiteralDelimiters:
         | 
| 53 | 
            +
              PreferredDelimiters:
         | 
| 54 | 
            +
                "%w": "[]"
         | 
| 55 | 
            +
                "%W": "[]"
         | 
| 56 | 
            +
                "%i": "[]"
         | 
| 57 | 
            +
                "%I": "[]"
         | 
| 58 | 
            +
                "%r": "()"
         | 
| 59 | 
            +
            Style/ReturnNil:
         | 
| 60 | 
            +
              Enabled: true
         | 
| 61 | 
            +
            Style/SafeNavigation:
         | 
| 62 | 
            +
              Enabled: false
         | 
| 63 | 
            +
            Style/Send:
         | 
| 64 | 
            +
              Enabled: true
         | 
| 65 | 
            +
            Style/SignalException:
         | 
| 66 | 
            +
              EnforcedStyle: semantic
         | 
| 67 | 
            +
            Style/StringLiterals:
         | 
| 68 | 
            +
              EnforcedStyle: double_quotes
         | 
| 69 | 
            +
            Style/StringLiteralsInInterpolation:
         | 
| 70 | 
            +
              EnforcedStyle: double_quotes
         | 
| 71 | 
            +
            Style/StringMethods:
         | 
| 72 | 
            +
              Enabled: true
         | 
| 73 | 
            +
            Style/SymbolArray:
         | 
| 74 | 
            +
              Enabled: true
         | 
| 75 | 
            +
            # this allows in rspec to have expect { } with multiple lines
         | 
| 76 | 
            +
            Style/BlockDelimiters:
         | 
| 77 | 
            +
              EnforcedStyle: braces_for_chaining
         | 
| 78 | 
            +
            Layout/EndOfLine:
         | 
| 79 | 
            +
              Enabled: false
         | 
| 80 | 
            +
            # don't need these checks in test folders
         | 
| 81 | 
            +
            Metrics/ModuleLength:
         | 
| 82 | 
            +
              Exclude:
         | 
| 83 | 
            +
                - "spec/**/*"
         | 
| 84 | 
            +
                - "test/**/*"
         | 
| 85 | 
            +
            Metrics/BlockLength:
         | 
| 86 | 
            +
              Exclude:
         | 
| 87 | 
            +
                - "spec/**/*"
         | 
| 88 | 
            +
                - "test/**/*"
         | 
| 89 | 
            +
                - "*.gemspec" # definitely not in the gemspec
         | 
| 90 | 
            +
            Metrics/MethodLength:
         | 
| 91 | 
            +
              Max: 20
         | 
| 92 | 
            +
            Lint/UnreachableCode:
         | 
| 93 | 
            +
              Description: 'Unreachable code.'
         | 
| 94 | 
            +
              Enabled: false
         | 
| 95 | 
            +
            Lint/Void:
         | 
| 96 | 
            +
              Enabled: false
         | 
| 97 | 
            +
            Layout/AlignHash:
         | 
| 98 | 
            +
              EnforcedLastArgumentHashStyle: ignore_implicit
         | 
| 99 | 
            +
            Metrics/AbcSize:
         | 
| 100 | 
            +
              Max: 25
         | 
| 101 | 
            +
            Style/LambdaCall:
         | 
| 102 | 
            +
              Enabled: false
         | 
| 103 | 
            +
            Style/Semicolon:
         | 
| 104 | 
            +
              Enabled: false
         | 
| 105 | 
            +
            Naming/UncommunicativeMethodParamName:
         | 
| 106 | 
            +
              Enabled: false
         | 
| 107 | 
            +
            Style/ClassAndModuleChildren:
         | 
| 108 | 
            +
              Enabled: false
         | 
| 109 | 
            +
            Layout/LeadingCommentSpace:
         | 
| 110 | 
            +
              Exclude:
         | 
| 111 | 
            +
                - 'test/docs/**/*'
         | 
| 112 | 
            +
            Layout/AlignHash:
         | 
| 113 | 
            +
              EnforcedHashRocketStyle: table
         | 
| 114 | 
            +
            Style/FrozenStringLiteralComment:
         | 
| 115 | 
            +
              Enabled: false
         | 
    
        data/.rubocop.yml
    ADDED
    
    | @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            inherit_from:
         | 
| 2 | 
            +
              - https://raw.githubusercontent.com/trailblazer/meta/master/rubocop.yml
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Style/SignalException:
         | 
| 5 | 
            +
              Exclude:
         | 
| 6 | 
            +
                - lib/trailblazer/test/operation/assertions.rb
         | 
| 7 | 
            +
                - lib/trailblazer/test/operation/helper.rb
         | 
| 8 | 
            +
                - lib/trailblazer/test/deprecation/operation/helper.rb
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Metrics/ParameterLists:
         | 
| 11 | 
            +
              Exclude:
         | 
| 12 | 
            +
                - lib/trailblazer/test/operation/assertions.rb
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            Metrics/LineLength:
         | 
| 15 | 
            +
              Exclude:
         | 
| 16 | 
            +
                - lib/trailblazer/test/operation/assertions.rb
         | 
| 17 | 
            +
             | 
    
        data/.travis.yml
    ADDED
    
    | @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            language: ruby
         | 
| 2 | 
            +
            before_install:
         | 
| 3 | 
            +
              - gem install bundler
         | 
| 4 | 
            +
            matrix:
         | 
| 5 | 
            +
              include:
         | 
| 6 | 
            +
                - rvm: 2.1
         | 
| 7 | 
            +
                  gemfile: Gemfile
         | 
| 8 | 
            +
                - rvm: 2.2
         | 
| 9 | 
            +
                  gemfile: Gemfile
         | 
| 10 | 
            +
                - rvm: 2.3.1
         | 
| 11 | 
            +
                  gemfile: Gemfile
         | 
| 12 | 
            +
                - rvm: 2.4.1
         | 
| 13 | 
            +
                  gemfile: Gemfile
         | 
| 14 | 
            +
                - rvm: 2.5.0
         | 
| 15 | 
            +
                  gemfile: Gemfile
         | 
| 16 | 
            +
                  script: bundle exec rake test && rake rubocop
         | 
    
        data/CHANGES.md
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,211 @@ | |
| 1 | 
            +
            # Trailblazer::Test
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            [](https://travis-ci.org/trailblazer/trailblazer-test)
         | 
| 4 | 
            +
            [](http://badge.fury.io/rb/trailblazer-test)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            ## Installation
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            Add this line to your application's Gemfile:
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ```ruby
         | 
| 11 | 
            +
            gem 'trailblazer-test'
         | 
| 12 | 
            +
            ```
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            And then execute:
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                $ bundle
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Or install it yourself as:
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                $ gem install trailblazer-test
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ## Usage
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            Add in your test `_helper` the following modules:
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            ```ruby
         | 
| 27 | 
            +
            include Trailblazer::Test::Assertions
         | 
| 28 | 
            +
            include Trailblazer::Test::Operation::Assertions
         | 
| 29 | 
            +
            ```
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            If you are using Trailblazer v2.0 you need to add also:
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            ```ruby
         | 
| 34 | 
            +
            require "trailblazer/test/deprecation/operation/assertions"
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            include Trailblazer::Test::Deprecation::Operation::Assertions # in your test class
         | 
| 37 | 
            +
            ```
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            To be able to test an operation we need 3 auxiliary methods which have to be defined at the start of your tests:
         | 
| 40 | 
            +
            * `default_params` (**required**): hash of params which will be always passed to the operation unless overriden by `params` or `ctx`
         | 
| 41 | 
            +
            * `expected_attrs` (**required**): hash always used to assert model attributes
         | 
| 42 | 
            +
            * `default_options` (**required if using `ctx`**): hash of options which will be always passed to the operation unless overriden by `ctx`
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            We are also providing 2 helper methods:
         | 
| 45 | 
            +
            * `params(new_params)`
         | 
| 46 | 
            +
            * `ctx(new_params, options)`
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            Those will merge params and options for you and return the final inputs which then can be passed to the operation under testing.
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            Pass `deep_merge: false` to the helper methods to disable the default deep merging of params and options.
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            *Same API for Trailblazer v2.0 and v2.1.*
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            Finally, using the built-in assertions you are able to test your operations in a fast and easy way:
         | 
| 55 | 
            +
            * `assert_pass` -> your operation is successful and model has the correct attributes
         | 
| 56 | 
            +
            * `assert_fail` -> your operation fails and returns some specific errors
         | 
| 57 | 
            +
            * `assert_policy_fail` -> your operation fails because policy fails
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            #### params
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            `params` accepts one argument which is merged into `default_params`.
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            ```ruby
         | 
| 64 | 
            +
            let(:default_params) { { title: 'My title' } }
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            params(artist: 'My Artist') -> { params: { title: 'My title', artist: 'My Artist' } }
         | 
| 67 | 
            +
            params(title: 'Other one') -> { params: { title: 'Other one' } }
         | 
| 68 | 
            +
            ```
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            #### ctx
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            `ctx` accepts 2 arguments, first one will be merged into the `default_params` and the second one will be merged into `default_options`
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            ```ruby
         | 
| 75 | 
            +
            let(:default_params)  { { title: 'My title' } }
         | 
| 76 | 
            +
            let(:default_options) { { current_user: 'me' } }
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            ctx(artist: 'My Artist') -> { params: { title: 'My title', artist: 'My Artist' }, current_user: 'me' }
         | 
| 79 | 
            +
            ctx({title: 'Other one'}, current_user: 'you') -> { params: { title: 'Other one' }, current_user: 'you' }
         | 
| 80 | 
            +
            ```
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            ### assert_pass
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            ```ruby
         | 
| 85 | 
            +
            assert_pass(operation, ctx, expected_attributes)
         | 
| 86 | 
            +
            ```
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            Example:
         | 
| 89 | 
            +
            ```ruby
         | 
| 90 | 
            +
            let(:default_params) { { band: 'The Chats'} }
         | 
| 91 | 
            +
            let(:default_options) { { current_user: user} }
         | 
| 92 | 
            +
            let(:expected_attrs) { { band: 'The Chats'} }
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            it { assert_pass MyOp, ctx(title: 'Smoko'), title: 'Smoko' }
         | 
| 95 | 
            +
            ```
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            Pass `deep_merge: false` to disable the deep merging of the third argument `expected_attributes` and the auxiliary method `expected_attrs`.
         | 
| 98 | 
            +
             | 
| 99 | 
            +
            It's also possible to test in a more detailed way using a block:
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            ```ruby
         | 
| 102 | 
            +
            assert_pass MyOp, ctx(title: 'Smoko'), {} do |result|
         | 
| 103 | 
            +
              assert_equal "Smoko", result[:model].title
         | 
| 104 | 
            +
            end
         | 
| 105 | 
            +
            ```
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            ### assert_fail
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            ```ruby
         | 
| 110 | 
            +
            assert_fail(operation, ctx)
         | 
| 111 | 
            +
            ```
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            Example:
         | 
| 114 | 
            +
            ```ruby
         | 
| 115 | 
            +
            let(:default_params) { { band: 'The Chats'} }
         | 
| 116 | 
            +
            let(:default_options) { { current_user: user} }
         | 
| 117 | 
            +
            let(:expected_attrs) { { band: 'The Chats'} }
         | 
| 118 | 
            +
             | 
| 119 | 
            +
            it { assert_fail MyOp, ctx(title: 'Smoko') }
         | 
| 120 | 
            +
            ```
         | 
| 121 | 
            +
             | 
| 122 | 
            +
            This will just test that the operation fails instead passing `expected_errors` as an array of symbols will also test that specific attribute has an error:
         | 
| 123 | 
            +
             | 
| 124 | 
            +
            ```ruby
         | 
| 125 | 
            +
            assert_fail MyOp, ctx(band: 'Justing Beaver'), expected_errors: [:band] # definitely wrong!!!!
         | 
| 126 | 
            +
            ```
         | 
| 127 | 
            +
             | 
| 128 | 
            +
            Using the block here will allow to test the error message:
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            ```ruby
         | 
| 131 | 
            +
            assert_fail MyOp, ctx(band: 'Justing Beaver') do |result|
         | 
| 132 | 
            +
              assert_equal 'You cannot listen Justing Beaver', result['contract.default'].errors.messages[:band]
         | 
| 133 | 
            +
            end
         | 
| 134 | 
            +
            ```
         | 
| 135 | 
            +
             | 
| 136 | 
            +
            Change contract name using `contract_name`.
         | 
| 137 | 
            +
             | 
| 138 | 
            +
            *We will improve this part and allowing to the test message directly without using a block*
         | 
| 139 | 
            +
             | 
| 140 | 
            +
             | 
| 141 | 
            +
            ### assert_policy_fail
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            Add this in your test file to be able to use it:
         | 
| 144 | 
            +
            ```ruby
         | 
| 145 | 
            +
            include Trailblazer::Test::Operation::PolicyAssertions
         | 
| 146 | 
            +
            ```
         | 
| 147 | 
            +
             | 
| 148 | 
            +
            ```ruby
         | 
| 149 | 
            +
            assert_policy_fail(operation, ctx)
         | 
| 150 | 
            +
            ```
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            This will test that the operation fails due to a policy failure.
         | 
| 153 | 
            +
             | 
| 154 | 
            +
            Example:
         | 
| 155 | 
            +
            ```ruby
         | 
| 156 | 
            +
            let(:default_params) { { band: 'The Chats'} }
         | 
| 157 | 
            +
            let(:default_options) { { current_user: user} }
         | 
| 158 | 
            +
             | 
| 159 | 
            +
            it { assert_policy_fail MyOp, ctx({title: 'Smoko'}, current_user: another) }
         | 
| 160 | 
            +
            ```
         | 
| 161 | 
            +
            Change policy name using `policy_name`.
         | 
| 162 | 
            +
             | 
| 163 | 
            +
            ## Test Setup
         | 
| 164 | 
            +
             | 
| 165 | 
            +
            It is obviously crucial to test your operation in the correct test enviroment calling operation instead of using `FactoryBot` or simply `Model.create`.
         | 
| 166 | 
            +
             | 
| 167 | 
            +
            To do so we provide 2 helper methods:
         | 
| 168 | 
            +
            * `call`: will call the operation and **will not raise** an error in case of failure
         | 
| 169 | 
            +
            * `factory`: will call the operation and **will raise** an error in case of failure returning also the trace and a validate error message in case exists
         | 
| 170 | 
            +
             | 
| 171 | 
            +
            ### Usage
         | 
| 172 | 
            +
             | 
| 173 | 
            +
            Add this in your test `_helper.rb`:
         | 
| 174 | 
            +
             | 
| 175 | 
            +
            ```ruby
         | 
| 176 | 
            +
            include Trailblazer::Test::Operation::Helper
         | 
| 177 | 
            +
            ```
         | 
| 178 | 
            +
             | 
| 179 | 
            +
            In case you use are Trailblazer v2.0, you need to add this instead:
         | 
| 180 | 
            +
             | 
| 181 | 
            +
            ```ruby
         | 
| 182 | 
            +
            require "trailblazer/test/deprecation/operation/helper"
         | 
| 183 | 
            +
             | 
| 184 | 
            +
            include Trailblazer::Test::Deprecation::Operation::Helper
         | 
| 185 | 
            +
            ```
         | 
| 186 | 
            +
             | 
| 187 | 
            +
            *Same API for both Trailblazer v2.0 and v2.1*
         | 
| 188 | 
            +
             | 
| 189 | 
            +
            Examples:
         | 
| 190 | 
            +
            ```ruby
         | 
| 191 | 
            +
            # call
         | 
| 192 | 
            +
            let(:user) { call(User::Create, params: params)[:model] }
         | 
| 193 | 
            +
             | 
| 194 | 
            +
            # call with block
         | 
| 195 | 
            +
            let(:user) do
         | 
| 196 | 
            +
              call User::Create, params: params do |result|
         | 
| 197 | 
            +
                # run some code to reproduce some async jobs (for example)
         | 
| 198 | 
            +
              end[:model]
         | 
| 199 | 
            +
            end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
            # factory - this will raise an error if User::Create fails
         | 
| 202 | 
            +
            let(:user) { factory(User::Create, params: params)[:model] }
         | 
| 203 | 
            +
             | 
| 204 | 
            +
            # factory - this will raise an error if User::Create fails
         | 
| 205 | 
            +
            let(:user) do
         | 
| 206 | 
            +
              factory User::Create, params: params do |result|
         | 
| 207 | 
            +
                # this block will be yield only if User::Create is successful
         | 
| 208 | 
            +
                # run some code to reproduce some async jobs (for example)
         | 
| 209 | 
            +
              end[:model]
         | 
| 210 | 
            +
            end
         | 
| 211 | 
            +
            ```
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            require "bundler/gem_tasks"
         | 
| 2 | 
            +
            require "rake/testtask"
         | 
| 3 | 
            +
            require "rubocop/rake_task"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RuboCop::RakeTask.new(:rubocop)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Rake::TestTask.new(:test) do |t|
         | 
| 8 | 
            +
              t.libs << "test"
         | 
| 9 | 
            +
              t.libs << "lib"
         | 
| 10 | 
            +
              t.test_files = FileList["test/**/*_test.rb"]
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            task default: :test
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            require "trailblazer/test/version"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Trailblazer
         | 
| 4 | 
            +
              module Test
         | 
| 5 | 
            +
                # Your code goes here...
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
            end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            require "trailblazer/test/assertions"
         | 
| 10 | 
            +
            require "trailblazer/test/operation/helper"
         | 
| 11 | 
            +
            require "trailblazer/test/operation/assertions"
         | 
| 12 | 
            +
            require "trailblazer/test/operation/policy_assertions"
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            # module MiniTest::Assertions
         | 
| 2 | 
            +
            module Trailblazer
         | 
| 3 | 
            +
              module Test
         | 
| 4 | 
            +
                # Evaluate value if it's a lambda, and let the caller know whether we need an
         | 
| 5 | 
            +
                # assert_equal or an assert.
         | 
| 6 | 
            +
                def self.expected(asserted, value, actual)
         | 
| 7 | 
            +
                  value.is_a?(Proc) ? [value.(actual: actual, asserted: asserted), false] : [value, true]
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # Read the actual value from the asserted object (e.g. a model).
         | 
| 11 | 
            +
                def self.actual(asserted, reader, name)
         | 
| 12 | 
            +
                  reader ? asserted.public_send(reader, name) : asserted.public_send(name)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                module Assertions
         | 
| 16 | 
            +
                  module_function
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  # tuples = defaults.merge(overrides) # FIXME: merge with above!
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  # Test if all `tuples` values on `asserted` match the expected values.
         | 
| 21 | 
            +
                  # @param asserted Object Object that exposes attributes to test
         | 
| 22 | 
            +
                  # @param tuples Hash Key/value attribute pairs to test
         | 
| 23 | 
            +
                  # @param options Hash Default :reader is `asserted.{name}`,
         | 
| 24 | 
            +
                  # TODO: test err msgs!
         | 
| 25 | 
            +
                  def assert_exposes(asserted, tuples, reader: nil)
         | 
| 26 | 
            +
                    tuples.each do |k, v|
         | 
| 27 | 
            +
                      actual          = Test.actual(asserted, reader, k)
         | 
| 28 | 
            +
                      expected, is_eq = Test.expected(asserted, v, actual)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                      is_eq ? assert_equal(expected, actual, "Property [#{k}] mismatch") : assert(expected, "Actual: #{actual.inspect}.")
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
            # Trailblazer::Operation::Result.infect_an_assertion :assert_result_matches, :must_match, :do_not_flip
         | 
| 37 | 
            +
            # Object.infect_an_assertion :assert_exposes, :must_expose, :do_not_flip
         | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            module Trailblazer::Test
         | 
| 2 | 
            +
              module Deprecation
         | 
| 3 | 
            +
                module Operation
         | 
| 4 | 
            +
                  module Assertions
         | 
| 5 | 
            +
                    include Trailblazer::Test::Operation::Assertions
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    # @needs default_params
         | 
| 8 | 
            +
                    # @needs default_options
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    def params(default_params: self.default_params, deep_merge: true, **new_params)
         | 
| 11 | 
            +
                      [merge_for(default_params, new_params, deep_merge), {}]
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    def ctx(new_params, *options)
         | 
| 15 | 
            +
                      # need *options to allow user to do something like:
         | 
| 16 | 
            +
                      # ctx({yeah: 'nah'}, "current_user" => Object, some: 'other' )
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                      # this is not greate but seems necessary using *options
         | 
| 19 | 
            +
                      new_options = options.first || {}
         | 
| 20 | 
            +
                      deep_merge = new_options[:deep_merge].nil? ? true : deep_merge
         | 
| 21 | 
            +
                      new_options.delete(:deep_merge)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                      ctx = merge_for(_default_options, options.first || {}, deep_merge)
         | 
| 24 | 
            +
                      [merge_for(params[0], new_params, deep_merge), ctx]
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    def _default_options(options: default_options)
         | 
| 28 | 
            +
                      options
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    # compatibility call for TRB 2.0
         | 
| 32 | 
            +
                    def _call_operation(operation_class, *args)
         | 
| 33 | 
            +
                      operation_class.(args[0][0], args[0][1])
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    def _model(result)
         | 
| 37 | 
            +
                      result["model"]
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            module Trailblazer::Test
         | 
| 2 | 
            +
              module Deprecation
         | 
| 3 | 
            +
                module Operation
         | 
| 4 | 
            +
                  module Helper
         | 
| 5 | 
            +
                    def call(operation_class, *args, &block)
         | 
| 6 | 
            +
                      call!(operation_class, args, &block)
         | 
| 7 | 
            +
                    end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    def factory(operation_class, *args, &block)
         | 
| 10 | 
            +
                      call!(operation_class, args, raise_on_failure: true, &block)
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    # @private
         | 
| 14 | 
            +
                    def call!(operation_class, args, raise_on_failure: false)
         | 
| 15 | 
            +
                      operation_class.(*args).tap do |result|
         | 
| 16 | 
            +
                        unless result.success?
         | 
| 17 | 
            +
                          yield result if block_given?
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                          raise OperationFailedError, "factory(#{operation_class}) failed." if raise_on_failure
         | 
| 20 | 
            +
                        end
         | 
| 21 | 
            +
                      end
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                class OperationFailedError < RuntimeError; end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,89 @@ | |
| 1 | 
            +
            require "hashie"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Trailblazer::Test::Operation
         | 
| 4 | 
            +
              module Assertions
         | 
| 5 | 
            +
                # @needs default_params
         | 
| 6 | 
            +
                # @needs default_options
         | 
| 7 | 
            +
                # @needs expected_attrs
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def params(default_params: self.default_params, deep_merge: true, **new_params)
         | 
| 10 | 
            +
                  {params: merge_for(default_params, new_params, deep_merge)}
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def ctx(new_params, default_options: self.default_options, deep_merge: true, **options)
         | 
| 14 | 
            +
                  new_params  = merge_for(params[:params], new_params, deep_merge)
         | 
| 15 | 
            +
                  new_options = merge_for(default_options, options, deep_merge)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  {params: new_params, **new_options}
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def assert_pass(operation_class, operation_inputs, expected_attributes, default_attributes: expected_attrs, deep_merge: true, &block)
         | 
| 21 | 
            +
                  expected_attributes = merge_for(default_attributes, expected_attributes, deep_merge)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  assert_pass_with_model(operation_class, operation_inputs, expected_model_attributes: expected_attributes, &block)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def assert_fail(operation_class, operation_inputs, expected_errors: nil, contract_name: "default", &block)
         | 
| 27 | 
            +
                  assert_fail_with_model(operation_class, operation_inputs, expected_errors: expected_errors, contract_name: contract_name, &block)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                # @private
         | 
| 31 | 
            +
                # TODO: test expected_attributes default param and explicit!
         | 
| 32 | 
            +
                def assert_pass_with_model(operation_class, operation_inputs, expected_model_attributes: {}, &user_block)
         | 
| 33 | 
            +
                  _assert_call(operation_class, operation_inputs, user_block: user_block) do |result|
         | 
| 34 | 
            +
                    assert_equal true, result.success?
         | 
| 35 | 
            +
                    assert_exposes(_model(result), expected_model_attributes)
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # @private
         | 
| 40 | 
            +
                def assert_fail_with_model(operation_class, operation_inputs, expected_errors: nil, contract_name: raise, &user_block)
         | 
| 41 | 
            +
                  _assert_call(operation_class, operation_inputs, user_block: user_block) do |result|
         | 
| 42 | 
            +
                    assert_equal true, result.failure?
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    raise ExpectedErrorsTypeError, "expected_errors has to be an Array" unless expected_errors.is_a?(Array)
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    # only test _if_ errors are present, not the content.
         | 
| 47 | 
            +
                    errors = result["contract.#{contract_name}"].errors.messages # TODO: this will soon change with the operation Errors object.
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    assert_equal expected_errors.sort, errors.keys.sort
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                # @private
         | 
| 54 | 
            +
                def _assert_call(operation_class, operation_inputs, user_block: raise)
         | 
| 55 | 
            +
                  result = _call_operation(operation_class, operation_inputs)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  return user_block.call(result) if user_block # DISCUSS: result or model?
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  yield(result)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  result
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                # @private
         | 
| 65 | 
            +
                class ExpectedErrorsTypeError < RuntimeError; end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                # @private
         | 
| 68 | 
            +
                class CtxHash < Hash
         | 
| 69 | 
            +
                  include Hashie::Extensions::DeepMerge
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                # @private
         | 
| 73 | 
            +
                def merge_for(dest, source, deep_merge)
         | 
| 74 | 
            +
                  return dest.merge(source) unless deep_merge
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  CtxHash[dest].deep_merge(CtxHash[source])
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                # @private
         | 
| 80 | 
            +
                def _call_operation(operation_class, operation_inputs)
         | 
| 81 | 
            +
                  operation_class.(operation_inputs)
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                # @private
         | 
| 85 | 
            +
                def _model(result)
         | 
| 86 | 
            +
                  result[:model]
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
              end
         | 
| 89 | 
            +
            end
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            module Trailblazer::Test::Operation
         | 
| 2 | 
            +
              module Helper
         | 
| 3 | 
            +
                def call(operation_class, **args, &block)
         | 
| 4 | 
            +
                  call!(operation_class, args, &block)
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def factory(operation_class, **args, &block)
         | 
| 8 | 
            +
                  call!(operation_class, args.merge(raise_on_failure: true), &block)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                # @private
         | 
| 12 | 
            +
                def call!(operation_class, raise_on_failure: false, **args)
         | 
| 13 | 
            +
                  operation_class.trace(**args).tap do |result|
         | 
| 14 | 
            +
                    unless result.success?
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                      msg = "factory(#{operation_class}) has failed"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                      unless result["contract.default"].nil? # should we allow to change contract name?
         | 
| 19 | 
            +
                        if result["contract.default"].errors.messages.any?
         | 
| 20 | 
            +
                          msg += " due to validation errors: #{result["contract.default"].errors.messages}"
         | 
| 21 | 
            +
                        end
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                      if raise_on_failure
         | 
| 25 | 
            +
                        result.wtf?
         | 
| 26 | 
            +
                        raise OperationFailedError, msg
         | 
| 27 | 
            +
                      end
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    yield result if block_given?
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    result
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                class OperationFailedError < RuntimeError; end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            module Trailblazer::Test::Operation
         | 
| 2 | 
            +
              module PolicyAssertions
         | 
| 3 | 
            +
                include Assertions
         | 
| 4 | 
            +
                # @needs params_pass
         | 
| 5 | 
            +
                # @needs options_pass
         | 
| 6 | 
            +
                def assert_policy_fail(operation_class, ctx, policy_name: "default")
         | 
| 7 | 
            +
                  _assert_call(operation_class, ctx, user_block: nil) do |result|
         | 
| 8 | 
            +
                    assert_equal true, result.failure?
         | 
| 9 | 
            +
                    assert_equal true, result["result.policy.#{policy_name}"].failure?
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            lib = File.expand_path("lib", __dir__)
         | 
| 2 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 3 | 
            +
            require "trailblazer/test/version"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Gem::Specification.new do |spec|
         | 
| 6 | 
            +
              spec.name          = "trailblazer-test"
         | 
| 7 | 
            +
              spec.version       = Trailblazer::Test::VERSION
         | 
| 8 | 
            +
              spec.authors       = ["Nick Sutterer"]
         | 
| 9 | 
            +
              spec.email         = ["apotonick@gmail.com"]
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              spec.summary       = "Assertions, matchers, and helpers to test Trailblazer code."
         | 
| 12 | 
            +
              spec.description   = "Assertions, matchers, and helpers to test Trailblazer code."
         | 
| 13 | 
            +
              spec.homepage      = "http://trailblazer.to"
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              spec.files         = `git ls-files -z`.split("\x0").reject do |f|
         | 
| 16 | 
            +
                f.match(%r{^(test|spec|features)/})
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              spec.bindir        = "exe"
         | 
| 19 | 
            +
              spec.executables   = spec.files.grep(%r(^exe/)) { |f| File.basename(f) }
         | 
| 20 | 
            +
              spec.require_paths = ["lib"]
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              spec.add_dependency "hashie"
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              spec.add_development_dependency "bundler", "~> 1.15"
         | 
| 25 | 
            +
              spec.add_development_dependency "minitest", "~> 5.0"
         | 
| 26 | 
            +
              spec.add_development_dependency "rake"
         | 
| 27 | 
            +
              spec.add_development_dependency "rubocop"
         | 
| 28 | 
            +
              spec.add_development_dependency "simplecov"
         | 
| 29 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,144 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: trailblazer-test
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Nick Sutterer
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: exe
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2018-12-02 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: hashie
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">="
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">="
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: bundler
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '1.15'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '1.15'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: minitest
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - "~>"
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '5.0'
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - "~>"
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '5.0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: rake
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '0'
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            +
              name: rubocop
         | 
| 71 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            +
                requirements:
         | 
| 73 | 
            +
                - - ">="
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: '0'
         | 
| 76 | 
            +
              type: :development
         | 
| 77 | 
            +
              prerelease: false
         | 
| 78 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
                requirements:
         | 
| 80 | 
            +
                - - ">="
         | 
| 81 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            +
                    version: '0'
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: simplecov
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - ">="
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '0'
         | 
| 90 | 
            +
              type: :development
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - ">="
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '0'
         | 
| 97 | 
            +
            description: Assertions, matchers, and helpers to test Trailblazer code.
         | 
| 98 | 
            +
            email:
         | 
| 99 | 
            +
            - apotonick@gmail.com
         | 
| 100 | 
            +
            executables: []
         | 
| 101 | 
            +
            extensions: []
         | 
| 102 | 
            +
            extra_rdoc_files: []
         | 
| 103 | 
            +
            files:
         | 
| 104 | 
            +
            - ".gitignore"
         | 
| 105 | 
            +
            - ".rubocop-https---raw-githubusercontent-com-trailblazer-meta-master-rubocop-yml"
         | 
| 106 | 
            +
            - ".rubocop.yml"
         | 
| 107 | 
            +
            - ".travis.yml"
         | 
| 108 | 
            +
            - CHANGES.md
         | 
| 109 | 
            +
            - Gemfile
         | 
| 110 | 
            +
            - README.md
         | 
| 111 | 
            +
            - Rakefile
         | 
| 112 | 
            +
            - lib/trailblazer/test.rb
         | 
| 113 | 
            +
            - lib/trailblazer/test/assertions.rb
         | 
| 114 | 
            +
            - lib/trailblazer/test/deprecation/operation/assertions.rb
         | 
| 115 | 
            +
            - lib/trailblazer/test/deprecation/operation/helper.rb
         | 
| 116 | 
            +
            - lib/trailblazer/test/operation/assertions.rb
         | 
| 117 | 
            +
            - lib/trailblazer/test/operation/helper.rb
         | 
| 118 | 
            +
            - lib/trailblazer/test/operation/policy_assertions.rb
         | 
| 119 | 
            +
            - lib/trailblazer/test/version.rb
         | 
| 120 | 
            +
            - trailblazer-test.gemspec
         | 
| 121 | 
            +
            homepage: http://trailblazer.to
         | 
| 122 | 
            +
            licenses: []
         | 
| 123 | 
            +
            metadata: {}
         | 
| 124 | 
            +
            post_install_message: 
         | 
| 125 | 
            +
            rdoc_options: []
         | 
| 126 | 
            +
            require_paths:
         | 
| 127 | 
            +
            - lib
         | 
| 128 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 129 | 
            +
              requirements:
         | 
| 130 | 
            +
              - - ">="
         | 
| 131 | 
            +
                - !ruby/object:Gem::Version
         | 
| 132 | 
            +
                  version: '0'
         | 
| 133 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 134 | 
            +
              requirements:
         | 
| 135 | 
            +
              - - ">="
         | 
| 136 | 
            +
                - !ruby/object:Gem::Version
         | 
| 137 | 
            +
                  version: '0'
         | 
| 138 | 
            +
            requirements: []
         | 
| 139 | 
            +
            rubyforge_project: 
         | 
| 140 | 
            +
            rubygems_version: 2.7.7
         | 
| 141 | 
            +
            signing_key: 
         | 
| 142 | 
            +
            specification_version: 4
         | 
| 143 | 
            +
            summary: Assertions, matchers, and helpers to test Trailblazer code.
         | 
| 144 | 
            +
            test_files: []
         |