salestation 4.1.0 → 4.2.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: 68e2a18e5e9afcefd5ebec1ff8ed6fce053049fc71dbc04ef863662810fbcc69
4
- data.tar.gz: 935756c02ffb2d60138c3be7b8506215ed0b9a720e85c6e606751eb71b13ebd9
3
+ metadata.gz: 95319eaf34503c8cdbe7c7ebbaefbd23e92090417ee6588fe394714981c87efe
4
+ data.tar.gz: 9ec9d477a27876759501d401981a5dcdcacc00d543c3af954da325fce42a8b08
5
5
  SHA512:
6
- metadata.gz: 2cb946c7702e75dc9c00f4bbf80f758a7ec5cde1501d6e7b36e6093a500a854ba5a209a1d62973c113aa7534cb7d620be82ad27f0cccad32b6adb774d8e5d26a
7
- data.tar.gz: 9aaf105fa50b0e82e3fcd613e53d2dba9023930ada4281edcf53cc1be5ee6cdb44966c02bedb5a0f6a6cb3bd306d9dd40dd56dcc2a6891679a23b2f139d0f9f7
6
+ metadata.gz: 85caaf8b2e31975fc302dff5492dabf42fb2affd681e4f038de544d48b9a3df4903a8eb11f2b2dbe3a244be13061a225e01f458ffcf5c6c008aab7ec0e61bef0
7
+ data.tar.gz: 11a0e53eea71d877032836b2b11762d4f20fabf42a86b2742ba4db6b8ad9b0ad26df3d3fadaa2d00231e0048bb9b288b118a2ef05f3d92ddf447cc8d7cca67ea
data/README.md CHANGED
@@ -184,6 +184,29 @@ You can configure per-request tags by defining `salestation.statsd.tags` in sina
184
184
  end
185
185
  ```
186
186
 
187
+ ## RSpec helpers
188
+
189
+
190
+ To use Salestation RSpec matchers you first need to include them:
191
+
192
+ ```
193
+ require 'salestation/rspec'
194
+
195
+ RSpec.configure do |config|
196
+ config.include Salestation::RSpec::Matchers
197
+ end
198
+ ```
199
+
200
+ After that it's possible to match against error results like this:
201
+
202
+ ```
203
+ expect(result).to be_failure
204
+ .with_conflict
205
+ .containing(message: 'Oh noes')
206
+ ```
207
+
208
+ See lib/salestation/rspec.rb for more examples.
209
+
187
210
  ## Development
188
211
 
189
212
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/expectations'
4
+ require 'salestation/app'
5
+
6
+ require_relative './rspec/failure_matcher'
7
+ require_relative './rspec/glia_input_validation_error_matcher'
8
+
9
+ module Salestation
10
+ module RSpec
11
+ # Usage:
12
+ #
13
+ # In your RSpec configuration first include the matchers:
14
+ #
15
+ # RSpec.configure do |config|
16
+ # config.include Salestation::RSpec::Matchers
17
+ # end
18
+ #
19
+ # Then you can use the matchers like this:
20
+ #
21
+ # expect(result).to be_failure
22
+ # .with_conflict
23
+ # .containing(message: 'Oh noes')
24
+ #
25
+ # or when using Glia Errors:
26
+ #
27
+ # expect(result).to be_failure
28
+ # .with_requested_resource_not_found
29
+ # .containing(Glia::Errors::ResourceNotFoundError.new(resource: :user))
30
+ #
31
+ # or when matching input errors from Glia Errors:
32
+ #
33
+ # expect(result).to be_failure
34
+ # .with_invalid_input
35
+ # .containing(glia_input_validation_error.on(:name).with_type(Glia::Errors::INVALID_VALUE_ERROR))
36
+ #
37
+ # or you could even match multiple input errors at the same time:
38
+ # expect(result).to be_failure
39
+ # .with_invalid_input
40
+ # .containing(
41
+ # glia_input_validation_error
42
+ # .on(:name).with_type(Glia::Errors::INVALID_VALUE_ERROR)
43
+ # .on(:email)
44
+ # .on(:phone_number).with_type(Glia::Errors::INVALID_FORMAT_ERROR)
45
+ # )
46
+ #
47
+ # Everything after be_failure is optional. You could also use `.containing`
48
+ # multiple times like this:
49
+ #
50
+ # expect(result).to be_failure
51
+ # .containing(Glia::Errors::ResourceNotFoundError.new(resource: :user))
52
+ # .containing(hash_including(message: 'Overriden message'))
53
+ #
54
+ module Matchers
55
+ def be_failure
56
+ FailureMatcher.new
57
+ end
58
+
59
+ def glia_input_validation_error
60
+ GliaInputValidationErrorMatcher.new
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/expectations'
4
+
5
+ module Salestation
6
+ module RSpec
7
+ class FailureMatcher
8
+ include ::RSpec::Matchers::Composable
9
+
10
+ attr_reader :expected, :actual, :failure_message
11
+
12
+ def initialize
13
+ @contents_matchers = []
14
+ end
15
+
16
+ def with(error_class)
17
+ @error_class = error_class
18
+ self
19
+ end
20
+
21
+ # From: active_support/inflector/methods.rb
22
+ def self.underscore(camel_cased_word)
23
+ return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
24
+ word = camel_cased_word.to_s.gsub("::", "/")
25
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
26
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
27
+ word.tr!("-", "_")
28
+ word.downcase!
29
+ word
30
+ end
31
+ private_class_method :underscore
32
+
33
+ # Defined methods using error class names:
34
+ # with_conflict
35
+ # with_invalid_input
36
+ # ...
37
+ Salestation::App::Errors.constants.each do |class_name|
38
+ define_method(:"with_#{underscore(class_name.to_s)}") do
39
+ with(Salestation::App::Errors.const_get(class_name))
40
+ self
41
+ end
42
+ end
43
+
44
+ def containing(matcher)
45
+ @contents_matchers << matcher
46
+ self
47
+ end
48
+
49
+ def matches?(actual)
50
+ check_failure(actual) &&
51
+ check_error_type(actual) &&
52
+ check_contents(actual)
53
+ end
54
+
55
+ def diffable?
56
+ true
57
+ end
58
+
59
+ private
60
+
61
+ def check_failure(actual)
62
+ return true if actual.class == Deterministic::Result::Failure
63
+
64
+ @failure_message = "Expected Failure(...), but got #{actual.inspect}"
65
+ @expected = Deterministic::Result::Failure
66
+ @actual = actual.class
67
+ false
68
+ end
69
+
70
+ def check_error_type(actual)
71
+ return true unless @error_class
72
+ return true if actual.value.class == @error_class
73
+
74
+ @failure_message = "Expected failure to include #{@error_class}, but got #{actual.value.inspect}"
75
+ @expected = @error_class
76
+ @actual = actual.value.class
77
+ false
78
+ end
79
+
80
+ def check_contents(actual)
81
+ return true if @contents_matchers.empty?
82
+
83
+ has_error = @contents_matchers.detect do |contents_matcher|
84
+ if contents_matcher.is_a?(Hash) || rspec_matcher?(contents_matcher)
85
+ verify_contents_using_regular_matcher!(contents_matcher, actual)
86
+ else
87
+ verify_contents_using_base_error!(contents_matcher, actual)
88
+ end
89
+ end
90
+
91
+ !has_error
92
+ end
93
+
94
+ # Returns true when error was detected
95
+ def verify_contents_using_regular_matcher!(contents_matcher, actual)
96
+ return false if values_match?(contents_matcher, actual.value.to_h)
97
+
98
+ @failure_message = "Contents in #{actual.value.class} do not match"
99
+ @expected = contents_matcher
100
+ @actual = actual.value.to_h
101
+
102
+ true
103
+ end
104
+
105
+ # Returns true when error was detected
106
+ def verify_contents_using_base_error!(contents_matcher, actual)
107
+ # Compare hashes if possible, otherwise expect it to respond to `#matches?`.
108
+ contents_matcher = contents_matcher.to_h if contents_matcher.respond_to?(:to_h)
109
+
110
+ return false if values_match?(contents_matcher, actual.value[:base_error])
111
+
112
+ @failure_message = "Expected failure to be based on #{contents_matcher}, but got #{actual.value.inspect}"
113
+ @expected = contents_matcher
114
+ @actual = actual.value[:base_error].to_h
115
+
116
+ true
117
+ end
118
+
119
+ def rspec_matcher?(matcher)
120
+ # Didn't find a better way to detect matchers like HashIncludingMatcher
121
+ matcher.class.to_s.start_with?('RSpec')
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/expectations'
4
+
5
+ module Salestation
6
+ module RSpec
7
+ class GliaInputValidationErrorMatcher
8
+ include ::RSpec::Matchers::Composable
9
+
10
+ attr_reader :expected, :actual, :failure_message
11
+
12
+ def initialize
13
+ @fields = []
14
+ @field_error_types = {}
15
+ end
16
+
17
+ def on(field)
18
+ @fields << field
19
+ self
20
+ end
21
+
22
+ def with_type(*types)
23
+ @field_error_types[@fields.last] = types
24
+ self
25
+ end
26
+
27
+ def matches?(actual)
28
+ @fields.all? do |field|
29
+ check_field_exists(field, actual) &&
30
+ check_field_error_types(field, actual)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def check_field_exists(field, actual)
37
+ actual[:error_details].key?(field)
38
+ end
39
+
40
+ def check_field_error_types(field, actual)
41
+ return true unless @field_error_types[field]
42
+
43
+ actual_error_types = actual[:error_details].fetch(field).map { |f| f.fetch(:type) }
44
+
45
+ (@field_error_types[field] - actual_error_types).empty?
46
+ end
47
+ end
48
+ end
49
+ end
data/salestation.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "salestation"
7
- spec.version = "4.1.0"
7
+ spec.version = "4.2.0"
8
8
  spec.authors = ["Glia TechMovers"]
9
9
  spec.email = ["techmovers@glia.com"]
10
10
 
@@ -23,6 +23,8 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rake", "~> 13.0"
24
24
  spec.add_development_dependency "rspec", "~> 3.0"
25
25
  spec.add_development_dependency "pry", "~> 0.10.4"
26
+ spec.add_development_dependency "glia-errors", "~> 0.8"
27
+ spec.add_development_dependency "dry-validation"
26
28
 
27
29
  spec.add_dependency 'deterministic'
28
30
  spec.add_dependency 'dry-struct'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: salestation
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Glia TechMovers
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-04 00:00:00.000000000 Z
11
+ date: 2021-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.10.4
69
+ - !ruby/object:Gem::Dependency
70
+ name: glia-errors
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: dry-validation
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'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: deterministic
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -128,6 +156,9 @@ files:
128
156
  - lib/salestation/app/input_verification.rb
129
157
  - lib/salestation/app/request.rb
130
158
  - lib/salestation/result_helper.rb
159
+ - lib/salestation/rspec.rb
160
+ - lib/salestation/rspec/failure_matcher.rb
161
+ - lib/salestation/rspec/glia_input_validation_error_matcher.rb
131
162
  - lib/salestation/web.rb
132
163
  - lib/salestation/web/active_record_connection_management.rb
133
164
  - lib/salestation/web/error_mapper.rb
@@ -143,7 +174,7 @@ homepage: ''
143
174
  licenses:
144
175
  - MIT
145
176
  metadata: {}
146
- post_install_message:
177
+ post_install_message:
147
178
  rdoc_options: []
148
179
  require_paths:
149
180
  - lib
@@ -158,8 +189,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
189
  - !ruby/object:Gem::Version
159
190
  version: '0'
160
191
  requirements: []
161
- rubygems_version: 3.0.6
162
- signing_key:
192
+ rubygems_version: 3.0.9
193
+ signing_key:
163
194
  specification_version: 4
164
195
  summary: ''
165
196
  test_files: []