jsonapi_rspec 0.2.1 → 0.2.2

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
  SHA1:
3
- metadata.gz: bd3c396ce463d2d0e5cc4eadb1388ed33f3904bf
4
- data.tar.gz: d9c1721e2d66bc797690e2b9b2617516c8a1044c
3
+ metadata.gz: 6f6a700c0770ee5ba9954b77fcc7818dce6274ae
4
+ data.tar.gz: cbd8512415d501c272add052d2b7ae9668ab5ca4
5
5
  SHA512:
6
- metadata.gz: 3efb55b570842c4e432b56ffeb62d3bb63c71cb8fe18d077d1bd6e7981e97058fe57d138a7934740b6afa3c809c5e13cd9947e9da4e0e76f47c673283f4d8b4d
7
- data.tar.gz: 9a36e27ecc06158474515f7aa8d2a170d4433a007e1c94673c0605ff51bce66a370c6594dd0445a4ab40e4831fa5b46a05b19832092b1c0d861ba5ed2ccd68e5
6
+ metadata.gz: 2a59ac4bda91aa5f2ec4c41096779803f1266c9e9d509a22c977b9d2b39145957864da2b8b0a8fb2a3948de1e24654f7e12084da0bbd1803375af8d54a4e783d
7
+ data.tar.gz: 9ecc45dad3f2f86d63c992c8c8aff538125c8d9e1a3f2241b5bb740c78aee641c388f036c3fa466a7212d5d9b6a346f371f4cd6ee7afaad6f2a193ca142e2dbd
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jsonapi_rspec (0.2.1)
4
+ jsonapi_rspec (0.2.2)
5
5
  activesupport (>= 4.2.8)
6
6
 
7
7
  GEM
@@ -1,4 +1,6 @@
1
1
  require 'jsonapi_rspec/version'
2
+ require 'jsonapi_rspec/failure_messages'
3
+ require 'jsonapi_rspec/be_json_api_response'
2
4
  require 'jsonapi_rspec/be_json_api_response_for'
3
5
 
4
6
  module JsonapiRspec
@@ -15,6 +17,69 @@ module JsonapiRspec
15
17
  end
16
18
  end
17
19
 
20
+ def failure_message
21
+ "#{@failure_message} - parsed response: #{pretty_response}"
22
+ end
23
+
24
+ def failure_message_when_negated
25
+ @failure_message = "handle method 'failure_message_when_negated' in custom_matchers.rb"
26
+ "#{@failure_message}: #{pretty_response}"
27
+ end
28
+
29
+ private
30
+
31
+ def pretty_response
32
+ JSON.pretty_generate(@parsed_response)
33
+ rescue JSON::GeneratorError
34
+ @parsed_response.to_s
35
+ end
36
+
37
+ def valid_response?(response)
38
+ return set_failure_message(FailureMessages::EMPTY) if response.body == ''
39
+ return set_failure_message(FailureMessages::NIL) if response.body.nil?
40
+ true
41
+ end
42
+
43
+ def required_top_level_sections?
44
+ valid = @parsed_response.dig('data') || @parsed_response.dig('errors') || @parsed_response.dig('meta')
45
+ return set_failure_message(FailureMessages::MISSING_REQ_TOP_LVL) unless valid
46
+ true
47
+ end
48
+
49
+ def conflicting_sections?
50
+ conflicting = false
51
+ if @parsed_response.dig('included')
52
+ # must have a data section
53
+ if @parsed_response.dig('data').nil?
54
+ conflicting = true
55
+ set_failure_message(FailureMessages::CONFLICTING_TOP_LVL)
56
+ end
57
+ end
58
+ conflicting
59
+ end
60
+
61
+ def valid_meta_section?
62
+ meta = @parsed_response.dig('meta')
63
+ return set_failure_message(FailureMessages::MISSING_META) unless meta.is_a?(Hash)
64
+ true
65
+ end
66
+
67
+ def response_is_error?
68
+ is_error = !@parsed_response.dig('errors').nil?
69
+ set_failure_message(FailureMessages::ERROR) if is_error
70
+ is_error
71
+ end
72
+
73
+ def valid_data_section?
74
+ data_section = @parsed_response.dig('data')
75
+ valid = data_section.is_a?(Hash) || data_section.is_a?(Array)
76
+ unless valid
77
+ return set_failure_message(FailureMessages::INVALID_DATA_SECTION)
78
+ end
79
+ true
80
+ end
81
+
82
+ # Autoload Section
18
83
  autoload :Configuration, 'jsonapi_rspec/configuration'
19
84
  end
20
85
 
@@ -0,0 +1,82 @@
1
+ require 'rspec/matchers'
2
+
3
+ require_relative 'string'
4
+
5
+ # Class BeJsonApiResponse provides custom RSpec matching for json:api
6
+ # responses in general.
7
+ #
8
+ # It expects a Rack::Response (or similar) response object
9
+ #
10
+ # Usage:
11
+ # expect(response).to BeJsonApiResponse.new
12
+ #
13
+ # @author Chris Blackburn <87a1779b@opayq.com>
14
+ #
15
+ class BeJsonApiResponse
16
+ include JsonapiRspec
17
+
18
+ def matches?(response)
19
+ return false unless valid_response?(response)
20
+
21
+ @parsed_response = JSON.parse(response.body)
22
+
23
+ return false if response_is_error?
24
+ return false unless required_top_level_sections?
25
+ return false if conflicting_sections?
26
+
27
+ if JsonapiRspec.configuration.meta_required
28
+ return false unless valid_meta_section?
29
+ end
30
+
31
+ @parsed_response.each_key do |key|
32
+ case key.to_sym
33
+ when :data
34
+ return false unless valid_data_section?
35
+ when :meta
36
+ return false unless valid_meta_section?
37
+ when :jsonapi
38
+ next # this can legally be anything
39
+ when :included
40
+ next # TODO: handle included objects
41
+ when :links
42
+ next # TODO: handle links objects
43
+ else
44
+ return set_failure_message(FailureMessages::UNEXPECTED_TOP_LVL_KEY % key)
45
+ end
46
+ end
47
+
48
+ true
49
+ end
50
+
51
+ private
52
+
53
+ # Set the failure message
54
+ #
55
+ # @param [String] msg Failure message
56
+ #
57
+ # @return [Boolean] always returns false
58
+ #
59
+ def set_failure_message(msg)
60
+ @failure_message = "#{FailureMessages::GENERAL_PREFIX} #{msg}"
61
+ false
62
+ end
63
+ end
64
+
65
+ # Usage:
66
+ # expect(response).to be_jsonapi_response
67
+ #
68
+ RSpec::Matchers.define :be_jsonapi_response do
69
+ match do |actual_response|
70
+ @instance = BeJsonApiResponse.new
71
+
72
+ def failure_message
73
+ @instance.failure_message
74
+ end
75
+
76
+ def failure_message_when_negated
77
+ @instance.failure_message
78
+ end
79
+
80
+ @instance.matches?(actual_response)
81
+ end
82
+ end
@@ -16,6 +16,8 @@ require_relative 'string'
16
16
  # @author Chris Blackburn <87a1779b@opayq.com>
17
17
  #
18
18
  class BeJsonApiResponseFor
19
+ include JsonapiRspec
20
+
19
21
  def initialize(object_instance, plural_form = nil)
20
22
  @object_instance = object_instance
21
23
  @plural_form = plural_form
@@ -42,32 +44,18 @@ class BeJsonApiResponseFor
42
44
  next # this can legally be anything
43
45
  when :included
44
46
  next # TODO: handle included objects
47
+ when :links
48
+ next # TODO: handle links objects
45
49
  else
46
- return set_failure_message("Unexpected key in response: '#{key}'")
50
+ return set_failure_message(FailureMessages::UNEXPECTED_TOP_LVL_KEY % key)
47
51
  end
48
52
  end
49
53
 
50
54
  true
51
55
  end
52
56
 
53
- def failure_message
54
- @failure_message ||= "Expected object [#{@object_instance}] to match"
55
- "#{@failure_message} - parsed response: #{pretty_response}"
56
- end
57
-
58
- def failure_message_when_negated
59
- @failure_message = "handle method 'failure_message_when_negated' in custom_matchers.rb"
60
- "#{@failure_message}: #{pretty_response}"
61
- end
62
-
63
57
  private
64
58
 
65
- def pretty_response
66
- JSON.pretty_generate(@parsed_response)
67
- rescue JSON::GeneratorError
68
- @parsed_response.to_s
69
- end
70
-
71
59
  # Set the failure message
72
60
  #
73
61
  # @param [String] msg Failure message
@@ -75,49 +63,21 @@ class BeJsonApiResponseFor
75
63
  # @return [Boolean] always returns false
76
64
  #
77
65
  def set_failure_message(msg)
78
- @failure_message = msg
66
+ @failure_message = "#{FailureMessages::OBJECT_PREFIX} #{msg}"
79
67
  false
80
68
  end
81
69
 
82
- def valid_response?(response)
83
- if response.body == ''
84
- return set_failure_message('Expected response to match an object instance but it is an empty string')
85
- end
86
- true
87
- end
88
-
89
- def valid_data_section?
90
- unless @parsed_response.dig('data').is_a?(Hash)
91
- return set_failure_message("The 'data' section is missing or invalid")
92
- end
93
- true
94
- end
95
-
96
70
  def valid_type?(data_type)
97
71
  object_type = @plural_form ||
98
72
  @object_instance.class.name.pluralize.underscore.dasherize
99
73
  unless data_type == object_type
100
- return set_failure_message("Expected data:type '#{data_type}' to match: '#{object_type}'")
101
- end
102
- true
103
- end
104
-
105
- def valid_meta_section?
106
- meta = @parsed_response.dig('meta')
107
- return set_failure_message("The 'meta' section is missing or invalid") unless meta.is_a?(Hash)
108
- return set_failure_message("The 'meta:version' is missing") if meta.dig('version').nil?
109
- unless meta.dig('copyright') =~ /^Copyright.+\d{4}/
110
- return set_failure_message("The 'meta:copyright' is missing or invalid - regex: '/^Copyright.+\\d{4}/'")
74
+ return set_failure_message(
75
+ format(FailureMessages::DATA_TYPE_MISMATCH, data_type, object_type)
76
+ )
111
77
  end
112
78
  true
113
79
  end
114
80
 
115
- def response_is_error?
116
- is_error = !@parsed_response.dig('errors').nil?
117
- set_failure_message('Response is an error') if is_error
118
- is_error
119
- end
120
-
121
81
  def match_attribute?(attr_name, json_val)
122
82
  obj_val = @object_instance.send(attr_name.to_sym)
123
83
  obj_val_class_name = obj_val.class.name
@@ -129,10 +89,8 @@ class BeJsonApiResponseFor
129
89
  matched = obj_val.to_i == DateTime.parse(json_val).to_i
130
90
  when 'Time'
131
91
  matched = obj_val.to_i == Time.parse(json_val).to_i
132
- when 'String', 'NilClass', 'TrueClass', 'FalseClass', 'Fixnum', 'Integer', 'Bignum'
133
- matched = obj_val == json_val
134
92
  else
135
- return set_failure_message("Fix 'match_attribute?' method to handle: '#{obj_val_class_name}'")
93
+ matched = obj_val == json_val
136
94
  end
137
95
 
138
96
  unless matched
@@ -153,7 +111,9 @@ class BeJsonApiResponseFor
153
111
  when :id
154
112
  object_id = @object_instance.send(key)
155
113
  unless object_id == value.to_i
156
- return set_failure_message("Expected '#{value}' to match object id: '#{object_id}'")
114
+ return set_failure_message(
115
+ format(FailureMessages::OBJECT_ID_MISMATCH, value, object_id)
116
+ )
157
117
  end
158
118
  when :type
159
119
  return false unless valid_type?(value)
@@ -0,0 +1,16 @@
1
+ module FailureMessages
2
+ GENERAL_PREFIX = 'Expected a json:api compliant success response but'.freeze
3
+ OBJECT_PREFIX = 'Expected a json:api response for an object instance but'.freeze
4
+
5
+ ERROR = 'it is an error'.freeze
6
+ EMPTY = 'it is empty'.freeze
7
+ NIL = 'it is nil'.freeze
8
+
9
+ MISSING_REQ_TOP_LVL = 'it is missing a required top-level section'.freeze
10
+ CONFLICTING_TOP_LVL = "it cannot contain 'included' without a 'data' section".freeze
11
+ UNEXPECTED_TOP_LVL_KEY = "it has an unexpected key: '%s'".freeze
12
+ INVALID_DATA_SECTION = "the 'data' section must be a Hash or an Array".freeze
13
+ DATA_TYPE_MISMATCH = "data:type '%s' doesn't match: '%s'".freeze
14
+ OBJECT_ID_MISMATCH = "data:id '%s' doesn't match object id: '%s'".freeze
15
+ MISSING_META = "the 'meta' section is missing or invalid".freeze
16
+ end
@@ -1,3 +1,3 @@
1
1
  module JsonapiRspec
2
- VERSION = '0.2.1'.freeze
2
+ VERSION = '0.2.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi_rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Blackburn
@@ -141,8 +141,10 @@ files:
141
141
  - bin/setup
142
142
  - jsonapi_rspec.gemspec
143
143
  - lib/jsonapi_rspec.rb
144
+ - lib/jsonapi_rspec/be_json_api_response.rb
144
145
  - lib/jsonapi_rspec/be_json_api_response_for.rb
145
146
  - lib/jsonapi_rspec/configuration.rb
147
+ - lib/jsonapi_rspec/failure_messages.rb
146
148
  - lib/jsonapi_rspec/string.rb
147
149
  - lib/jsonapi_rspec/version.rb
148
150
  homepage: https://github.com/midwire/jsonapi_rspec