json_response_matchers 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f9d75ea0b51b5fe4ecbb1c396dfd73788d3b5c931d3c048f1b452b4f31fbda80
4
+ data.tar.gz: f7db535ebccc51e66eb9d41e6f24aca40d76226f5accd29300f34c9cdf042c13
5
+ SHA512:
6
+ metadata.gz: c129e180cac8ea2780c9135d217e25fada4bfc7f8269900fc14ac2997a1a5fd9c0a92620ae256e633cf5b498b0a71d50f5667668cf934d26f9dcc6cc37c3ca6f
7
+ data.tar.gz: 282bd1cb707e91d05fa1a05c058d52ccef806d53ecac35a335bc96748c78f2ba909386203452120037de6e6e77c4bff9db0fb0f92085d6dff11fda5637981cf7
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Appraisals ADDED
@@ -0,0 +1,25 @@
1
+ if RUBY_VERSION < '2.4'
2
+ appraise 'activesupport-4' do
3
+ gem 'activesupport', '4.0.6'
4
+ end
5
+ end
6
+
7
+ if RUBY_VERSION >= '2.3'
8
+ appraise 'activesupport-5' do
9
+ gem 'activesupport', '5.0.0'
10
+ end
11
+
12
+ appraise 'activesupport-5.2.2' do
13
+ gem 'activesupport', '5.2.2'
14
+ end
15
+ end
16
+
17
+ appraise 'rspec-3' do
18
+ gem 'rspec', '3.0.0'
19
+ gem 'activesupport', '4.0.6' if RUBY_VERSION < '2.3'
20
+ end
21
+
22
+ appraise 'rspec-3.8' do
23
+ gem 'rspec', '3.8.0'
24
+ gem 'activesupport', '4.0.6' if RUBY_VERSION < '2.3'
25
+ end
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in json_response_matchers.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Szijjártó Nagy Misu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # JsonResponseMatchers
2
+
3
+ [rspec](https://relishapp.com/rspec) matchers for testing json responses in a [rails](https://rubyonrails.org/) application.
4
+
5
+ ## Dependencies
6
+
7
+ * **ruby** `'>= 2.0.0'`
8
+ * **rspec** `'>= 3.0'` <!-- see composable matchers -->
9
+ * **activesupport** `'>= 4.0.6'` <!-- see https://github.com/rails/rails/pull/10887 -->
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ group :test do
17
+ gem 'json_response_matchers'
18
+ end
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ ## Usage
26
+
27
+ 1. include the matchers in your rspec config
28
+
29
+ ```ruby
30
+ # spec/rails_helper.rb
31
+ RSpec.configure do |config|
32
+ # you can include it in a general way
33
+ config.include JsonResponseMatchers
34
+ # but it is recommended to include it only for the request
35
+ config.include JsonResponseMatchers, type: :request
36
+ # or the request and controller specs
37
+ config.include JsonResponseMatchers, type: /request|controller/
38
+ end
39
+ ```
40
+
41
+ 2. write more concise request specs
42
+
43
+ ```ruby
44
+ # in your request spec examples
45
+ # instead of
46
+ item = JSON.parse(response.body)['item']
47
+ expect(item['name']).to eq 'item-name'
48
+ # use the #have_json_content matcher
49
+ expect(response).to have_json_content('item-name').at_key :item, :name
50
+
51
+ # instead of
52
+ items = JSON.parse(repsonse.body)['items']
53
+ expect(items.map { |item| item['id'] }).to match_array [ 1, 2, 3, 4, 5 ]
54
+ # use the #have_json_values matcher
55
+ expect(response).to have_json_values(1, 2, 3, 4, 5).for(:id).at_key :items
56
+ ```
57
+
58
+ ### general rules
59
+
60
+ The target of the matchers can be a json parsable string or an object with such a string at the method `#body` (like the test response in rails request tests).
61
+
62
+ ```ruby
63
+ expect('{"item":{"id":1,"name":"item-name"}}').to have_json_content('item-name').at_key :item, :name
64
+ # or if `response.body` contains the above json
65
+ expect(response).to have_json_content('item-name').at_key :item, :name
66
+ ```
67
+
68
+ The `#at_key` method is optional and can receive one or more `string`, `symbol` or `integer` keys.
69
+
70
+ ```ruby
71
+ expect('false').to have_json_content(false)
72
+
73
+ json = '{"items":[{"id":1,"name":"item-1"},{"id":2,"name":"item-2"}]}'
74
+ expect(json).to have_json_values(1, 2).for(:id).at_key 'items'
75
+ expect(json).to have_json_values(1, 2).for(:id).at_key :items
76
+ expect(json).to have_json_content('item-2').at_key :items, 1, 'name'
77
+ ```
78
+
79
+ Both matchers are [composable](https://relishapp.com/rspec/rspec-expectations/docs/composing-matchers).
80
+
81
+ ```ruby
82
+ expect('{"item":{"id":1},"user":{"name":"user"}}')
83
+ .to have_json_content(1).at_key(:item, :id)
84
+ .and have_json_values('user').at_key(:user, :name)
85
+
86
+ expect('{"items":[{"id":1},{"id":2}],"page":1}')
87
+ .to have_json_values(1, 2).for(:id).at_key(:item)
88
+ .and have_json_content(1).at_key(:page)
89
+ ```
90
+
91
+ ### #have_json_content
92
+
93
+ Checks single values.
94
+
95
+ * If expected value is not a `hash`, it checks equality
96
+
97
+ ```ruby
98
+ # all pass
99
+ expect('{"string":"string"}').to have_json_content('string').at_key :string
100
+ expect('{"number":123}').to have_json_content(123).at_key :number
101
+ expect('{"boolean":false}').to have_json_content(false).at_key :boolean
102
+ expect('{"array":["a",2]}').to have_json_content([ 'a', 2 ]).at_key :array
103
+ expect('{"null":null}').to have_json_content(nil).at_key :null
104
+ ```
105
+
106
+ * If expected value is a `hash`
107
+ * and `#with_full_match` is specified, it checks equality
108
+ * otherwise it checks inclusion
109
+ * accepts symbol keys
110
+
111
+ ```ruby
112
+ expect('{"id":1,"name":"i1"}').to have_json_content('id'=>1).with_full_match # fails
113
+ expect('{"id":1,"name":"i1"}').to have_json_content('id'=>1) # passes
114
+ expect('{"id":1,"name":"i1"}').to have_json_content(name: 'i1', id: 1).with_full_match # passes
115
+ ```
116
+
117
+
118
+ ### #have_json_values
119
+
120
+ Checks arrays. The expected values are passed as a parameter list (`*args`) to the matcher.
121
+
122
+ * the metod `#for` is required and can take a `string` or `symbol` value
123
+
124
+ ```ruby
125
+ items = [
126
+ { id: 1, name: 'item-1' },
127
+ { id: 2, name: 'item-2' },
128
+ { id: 3, name: 'item-3' }
129
+ ]
130
+ expect(items.to_json).to have_json_values(1, 2, 3).for('id') # passes
131
+ expect(items.to_json).to have_json_values(1, 2, 3).for(:id) # passes
132
+ expect(items.to_json).to have_json_values(*items) # fails with ArgumentError
133
+ ```
134
+
135
+ * checks order only if `#in_strict_order` is specified
136
+
137
+ ```ruby
138
+ expect(items.to_json).to have_json_values(1, 3, 2).for(:id) # passes
139
+ expect(items.to_json).to have_json_values(1, 3, 2).for(:id).in_strict_order # fails
140
+ ```
141
+
142
+ ## Contributing
143
+
144
+ Bug reports and pull requests are welcome on GitHub at https://github.com/SzNagyMisu/json_response_matchers.
145
+
146
+ ## License
147
+
148
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ DEFAULT_RUBY_VERSIONS = [ '2.0.0', '2.3.7', '2.5.1', '2.6.0-preview2' ].freeze
5
+
6
+ desc "Test against multiple ruby, activerecord and rspec versions - " +
7
+ "set RUBY_VERSIONS to the version(s) to test with (default: #{DEFAULT_RUBY_VERSIONS.join(',').inspect})"
8
+ task :full_test do
9
+ versions = ENV['RUBY_VERSIONS'] ? ENV['RUBY_VERSIONS'].split(',') : DEFAULT_RUBY_VERSIONS
10
+ started_at = Time.now
11
+
12
+ versions.each do |version|
13
+ sh "./bin/test #{version}"
14
+ end
15
+
16
+ time_elapsed = (Time.now - started_at).to_i
17
+ hours = time_elapsed / 3600
18
+ minutes = time_elapsed / 60 % 60
19
+ seconds = time_elapsed % 60
20
+ puts "\nTest suit complete\n" +
21
+ " ruby versions: #{versions.join(', ')}\n" +
22
+ " run in #{hours}h #{minutes}m #{seconds}s\n"
23
+ end
24
+
25
+ RSpec::Core::RakeTask.new(:spec)
26
+
27
+ task :default => :spec
data/bin/test ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ if [ $1 ]; then
6
+ # see https://rvm.io/workflow/scripting
7
+ if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then
8
+ source "$HOME/.rvm/scripts/rvm"
9
+ elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then
10
+ source "/usr/local/rvm/scripts/rvm"
11
+ else
12
+ printf "ERROR: An RVM installation was not found."
13
+ fi
14
+ rvm use $1
15
+ fi
16
+
17
+ bundle update
18
+ bundle exec appraisal update
19
+ bundle exec appraisal rspec
20
+
21
+ echo 'Success!'
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "4.0.6"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,56 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ json_response_matchers (1.1.0)
5
+ activesupport (>= 4.0.6)
6
+ rspec (~> 3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (4.0.6)
12
+ i18n (~> 0.6, >= 0.6.9)
13
+ minitest (~> 4.2)
14
+ multi_json (~> 1.3)
15
+ thread_safe (~> 0.1)
16
+ tzinfo (~> 0.3.37)
17
+ appraisal (2.2.0)
18
+ bundler
19
+ rake
20
+ thor (>= 0.14.0)
21
+ concurrent-ruby (1.1.4)
22
+ diff-lcs (1.3)
23
+ i18n (0.9.5)
24
+ concurrent-ruby (~> 1.0)
25
+ minitest (4.7.5)
26
+ multi_json (1.13.1)
27
+ rake (10.5.0)
28
+ rspec (3.8.0)
29
+ rspec-core (~> 3.8.0)
30
+ rspec-expectations (~> 3.8.0)
31
+ rspec-mocks (~> 3.8.0)
32
+ rspec-core (3.8.0)
33
+ rspec-support (~> 3.8.0)
34
+ rspec-expectations (3.8.2)
35
+ diff-lcs (>= 1.2.0, < 2.0)
36
+ rspec-support (~> 3.8.0)
37
+ rspec-mocks (3.8.0)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.8.0)
40
+ rspec-support (3.8.0)
41
+ thor (0.20.3)
42
+ thread_safe (0.3.6)
43
+ tzinfo (0.3.55)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ activesupport (= 4.0.6)
50
+ appraisal (~> 2.2)
51
+ bundler (~> 1.16)
52
+ json_response_matchers!
53
+ rake (~> 10.0)
54
+
55
+ BUNDLED WITH
56
+ 1.16.6
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "5.2.2"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,55 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ json_response_matchers (1.1.0)
5
+ activesupport (>= 4.0.6)
6
+ rspec (~> 3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (5.2.2)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 0.7, < 2)
14
+ minitest (~> 5.1)
15
+ tzinfo (~> 1.1)
16
+ appraisal (2.2.0)
17
+ bundler
18
+ rake
19
+ thor (>= 0.14.0)
20
+ concurrent-ruby (1.1.4)
21
+ diff-lcs (1.3)
22
+ i18n (1.5.3)
23
+ concurrent-ruby (~> 1.0)
24
+ minitest (5.11.3)
25
+ rake (10.5.0)
26
+ rspec (3.8.0)
27
+ rspec-core (~> 3.8.0)
28
+ rspec-expectations (~> 3.8.0)
29
+ rspec-mocks (~> 3.8.0)
30
+ rspec-core (3.8.0)
31
+ rspec-support (~> 3.8.0)
32
+ rspec-expectations (3.8.2)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.8.0)
35
+ rspec-mocks (3.8.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.8.0)
38
+ rspec-support (3.8.0)
39
+ thor (0.20.3)
40
+ thread_safe (0.3.6)
41
+ tzinfo (1.2.5)
42
+ thread_safe (~> 0.1)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ activesupport (= 5.2.2)
49
+ appraisal (~> 2.2)
50
+ bundler (~> 1.16)
51
+ json_response_matchers!
52
+ rake (~> 10.0)
53
+
54
+ BUNDLED WITH
55
+ 1.16.6
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "5.0.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,55 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ json_response_matchers (1.1.0)
5
+ activesupport (>= 4.0.6)
6
+ rspec (~> 3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (5.0.0)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (~> 0.7)
14
+ minitest (~> 5.1)
15
+ tzinfo (~> 1.1)
16
+ appraisal (2.2.0)
17
+ bundler
18
+ rake
19
+ thor (>= 0.14.0)
20
+ concurrent-ruby (1.1.4)
21
+ diff-lcs (1.3)
22
+ i18n (0.9.5)
23
+ concurrent-ruby (~> 1.0)
24
+ minitest (5.11.3)
25
+ rake (10.5.0)
26
+ rspec (3.8.0)
27
+ rspec-core (~> 3.8.0)
28
+ rspec-expectations (~> 3.8.0)
29
+ rspec-mocks (~> 3.8.0)
30
+ rspec-core (3.8.0)
31
+ rspec-support (~> 3.8.0)
32
+ rspec-expectations (3.8.2)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.8.0)
35
+ rspec-mocks (3.8.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.8.0)
38
+ rspec-support (3.8.0)
39
+ thor (0.20.3)
40
+ thread_safe (0.3.6)
41
+ tzinfo (1.2.5)
42
+ thread_safe (~> 0.1)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ activesupport (= 5.0.0)
49
+ appraisal (~> 2.2)
50
+ bundler (~> 1.16)
51
+ json_response_matchers!
52
+ rake (~> 10.0)
53
+
54
+ BUNDLED WITH
55
+ 1.16.6
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec", "3.8.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,55 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ json_response_matchers (1.1.0)
5
+ activesupport (>= 4.0.6)
6
+ rspec (~> 3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (5.2.2)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 0.7, < 2)
14
+ minitest (~> 5.1)
15
+ tzinfo (~> 1.1)
16
+ appraisal (2.2.0)
17
+ bundler
18
+ rake
19
+ thor (>= 0.14.0)
20
+ concurrent-ruby (1.1.4)
21
+ diff-lcs (1.3)
22
+ i18n (1.5.3)
23
+ concurrent-ruby (~> 1.0)
24
+ minitest (5.11.3)
25
+ rake (10.5.0)
26
+ rspec (3.8.0)
27
+ rspec-core (~> 3.8.0)
28
+ rspec-expectations (~> 3.8.0)
29
+ rspec-mocks (~> 3.8.0)
30
+ rspec-core (3.8.0)
31
+ rspec-support (~> 3.8.0)
32
+ rspec-expectations (3.8.2)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.8.0)
35
+ rspec-mocks (3.8.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.8.0)
38
+ rspec-support (3.8.0)
39
+ thor (0.20.3)
40
+ thread_safe (0.3.6)
41
+ tzinfo (1.2.5)
42
+ thread_safe (~> 0.1)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ appraisal (~> 2.2)
49
+ bundler (~> 1.16)
50
+ json_response_matchers!
51
+ rake (~> 10.0)
52
+ rspec (= 3.8.0)
53
+
54
+ BUNDLED WITH
55
+ 1.16.6
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec", "3.0.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,54 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ json_response_matchers (1.1.0)
5
+ activesupport (>= 4.0.6)
6
+ rspec (~> 3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (5.2.2)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 0.7, < 2)
14
+ minitest (~> 5.1)
15
+ tzinfo (~> 1.1)
16
+ appraisal (2.2.0)
17
+ bundler
18
+ rake
19
+ thor (>= 0.14.0)
20
+ concurrent-ruby (1.1.4)
21
+ diff-lcs (1.3)
22
+ i18n (1.5.3)
23
+ concurrent-ruby (~> 1.0)
24
+ minitest (5.11.3)
25
+ rake (10.5.0)
26
+ rspec (3.0.0)
27
+ rspec-core (~> 3.0.0)
28
+ rspec-expectations (~> 3.0.0)
29
+ rspec-mocks (~> 3.0.0)
30
+ rspec-core (3.0.4)
31
+ rspec-support (~> 3.0.0)
32
+ rspec-expectations (3.0.4)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.0.0)
35
+ rspec-mocks (3.0.4)
36
+ rspec-support (~> 3.0.0)
37
+ rspec-support (3.0.4)
38
+ thor (0.20.3)
39
+ thread_safe (0.3.6)
40
+ tzinfo (1.2.5)
41
+ thread_safe (~> 0.1)
42
+
43
+ PLATFORMS
44
+ ruby
45
+
46
+ DEPENDENCIES
47
+ appraisal (~> 2.2)
48
+ bundler (~> 1.16)
49
+ json_response_matchers!
50
+ rake (~> 10.0)
51
+ rspec (= 3.0.0)
52
+
53
+ BUNDLED WITH
54
+ 1.16.6
@@ -0,0 +1,39 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "json_response_matchers/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "json_response_matchers"
8
+ spec.version = JsonResponseMatchers::VERSION
9
+ spec.authors = ["Szijjártó Nagy Misu"]
10
+ spec.email = ["szijjartonagy.misu@gmail.com"]
11
+
12
+ spec.summary = 'rspec matchers to test http responses with json content in rails'
13
+ spec.description = 'Provides two matchers (#have_json_content and #have_json_values) to make testing the content of json responses easy.'
14
+ spec.homepage = 'https://github.com/SzNagyMisu/json_response_matchers'
15
+ spec.license = "MIT"
16
+
17
+ if spec.respond_to?(:metadata)
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = spec.homepage
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against " \
22
+ "public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -- lib/*`.split("\n") + %w[ README.md LICENSE.txt json_response_matchers.gemspec ]
26
+ spec.bindir = "bin"
27
+ spec.test_files = `git ls-files -- gemfiles/* spec/*`.split("\n") + %w[ Appraisals Gemfile Rakefile .rspec bin/test ]
28
+ spec.executables = []
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.required_ruby_version = ">= 2.0.0"
32
+
33
+ spec.add_dependency "rspec", "~> 3.0"
34
+ spec.add_dependency "activesupport", ">= 4.0.6"
35
+
36
+ spec.add_development_dependency "bundler", "~> 1.16"
37
+ spec.add_development_dependency "rake", "~> 10.0"
38
+ spec.add_development_dependency "appraisal", "~> 2.2"
39
+ end
@@ -0,0 +1,37 @@
1
+ require "json"
2
+ require 'active_support/core_ext/hash/keys'
3
+ require 'rspec'
4
+
5
+ module JsonResponseMatchers
6
+ class Base
7
+ attr_reader :expected, :actual
8
+
9
+ include RSpec::Matchers::Composable
10
+
11
+ def initialize expected
12
+ @expected = expected
13
+ end
14
+
15
+ def at_key *hash_keys
16
+ @keys = hash_keys
17
+ self
18
+ end
19
+
20
+ def diffable?
21
+ true
22
+ end
23
+
24
+
25
+ private
26
+
27
+ def extract_parsed_json_from json_or_response
28
+ json = json_or_response.respond_to?(:body) ? json_or_response.body : json_or_response
29
+ JSON.parse json
30
+ end
31
+
32
+ def fetch_from hash
33
+ ( @keys || [] ).each { |key| hash = hash.fetch(Integer === key ? key : key.to_s) }
34
+ hash
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ require "json_response_matchers/base"
2
+
3
+ module JsonResponseMatchers
4
+ class Content < Base
5
+ def initialize expected
6
+ super
7
+ @exact = true
8
+ if Hash === @expected
9
+ @expected.deep_stringify_keys!
10
+ @exact = false
11
+ end
12
+ end
13
+
14
+ def failure_message
15
+ "expected\n #{@actual}\nto #{@exact ? 'equal' : 'include'}\n #{@expected}"
16
+ end
17
+
18
+
19
+ def matches? actual
20
+ @actual = fetch_from extract_parsed_json_from actual
21
+ @exact ? @actual == @expected : hash_include?
22
+ end
23
+
24
+ def with_full_match
25
+ @exact = true
26
+ self
27
+ end
28
+
29
+
30
+ private
31
+
32
+ def hash_include?
33
+ @expected.all? { |key, expected_value| @actual[key.to_s] == expected_value }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,49 @@
1
+ require "json_response_matchers/base"
2
+
3
+ module JsonResponseMatchers
4
+ class Values < Base
5
+
6
+ def initialize expected
7
+ super
8
+ @check_order = false
9
+ end
10
+
11
+ def failure_message
12
+ "expected\n #{@actual}\nto #{@check_order ? 'equal' : 'match'}\n #{@expected}"
13
+ end
14
+
15
+
16
+ def matches? actual
17
+ raise ArgumentError, "You must set one or more attributes for mapping with #for:\n have_json_values(#{@expected}).for(attribute_name(s))" unless @for
18
+ @actual = fetch_from extract_parsed_json_from actual
19
+ @actual = @actual.map do |item|
20
+ @for.one? ? item[@for.first] : @for.map { |attribute| item[attribute] }
21
+ end
22
+ @check_order ? @actual == @expected : arrays_match?
23
+ end
24
+
25
+ def for *attributes
26
+ @for = attributes.map &:to_s
27
+ self
28
+ end
29
+
30
+ def in_strict_order
31
+ @check_order = true
32
+ self
33
+ end
34
+
35
+
36
+ private
37
+
38
+ def arrays_match?
39
+ expected = @expected.dup
40
+ all_matches = @actual.all? do |actual_value|
41
+ if expected.include? actual_value
42
+ expected.delete actual_value
43
+ true
44
+ end
45
+ end
46
+ all_matches && expected.empty?
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module JsonResponseMatchers
2
+ VERSION = "1.1.0"
3
+ end
@@ -0,0 +1,13 @@
1
+ require "json_response_matchers/version"
2
+ require "json_response_matchers/content"
3
+ require "json_response_matchers/values"
4
+
5
+ module JsonResponseMatchers
6
+ def have_json_values *values
7
+ Values.new values
8
+ end
9
+
10
+ def have_json_content parsed_content
11
+ Content.new parsed_content
12
+ end
13
+ end
@@ -0,0 +1,99 @@
1
+ RSpec.describe '#have_json_content' do
2
+ let(:item) { { item: { name: 'item 1', count: 2 } } }
3
+ let(:json) { item.to_json }
4
+ let(:nested) { { items: [ item ] }.to_json }
5
+ let(:response) { Struct.new(:body).new json }
6
+
7
+ describe 'the expected value' do
8
+ it 'can be a string.' do
9
+ expect({ string: 'string' }.to_json).to have_json_content('string').at_key(:string)
10
+ end
11
+
12
+ it 'can be a number.' do
13
+ expect({ number: 123 }.to_json).to have_json_content(123).at_key(:number)
14
+ end
15
+
16
+ it 'can be a boolean.' do
17
+ expect({ boolean: false }.to_json).to have_json_content(false).at_key(:boolean)
18
+ end
19
+
20
+ it 'can be an array.' do
21
+ expect({ array: [ :a, 2 ] }.to_json).to have_json_content([ 'a', 2 ]).at_key(:array)
22
+ end
23
+
24
+ it 'can be nil.' do
25
+ expect({ null: nil }.to_json).to have_json_content(nil).at_key(:null)
26
+ end
27
+
28
+ describe 'can be a hash' do
29
+ it 'with string keys.' do
30
+ expect(json).to have_json_content('name' => 'item 1', 'count' => 2).at_key('item')
31
+ end
32
+
33
+ it 'with symbol keys.'do
34
+ expect(json).to have_json_content(name: 'item 1', count: 2).at_key(:item)
35
+ end
36
+
37
+ it 'with symbol keys in deep nesting.' do
38
+ expect(nested).to have_json_content(items: [ item: { name: 'item 1', count: 2 } ])
39
+ end
40
+ end
41
+ end
42
+
43
+
44
+ it 'works for the response object.' do
45
+ expect(response).to have_json_content(name: 'item 1', count: 2).at_key(:item)
46
+ end
47
+
48
+ it 'works for the response body (json string).' do
49
+ expect(response.body).to have_json_content(name: 'item 1', count: 2).at_key(:item)
50
+ end
51
+
52
+ it 'works with no key passed.' do
53
+ expect(item[:item].to_json).to have_json_content(name: 'item 1', count: 2)
54
+ end
55
+
56
+ it 'works with multiple keys passed.' do
57
+ expect({ container: item }.to_json).to have_json_content(name: 'item 1', count: 2).at_key(:container, :item)
58
+ end
59
+
60
+ it 'works with symbol, string or integer key.' do
61
+ expect({ items: [ { name: 'item 1' } ] }.to_json).to have_json_content('item 1').at_key('items', 0, :name)
62
+ end
63
+
64
+ it 'checks inclusion by default.' do
65
+ expect(json).to have_json_content(name: 'item 1').at_key(:item)
66
+ expect(json).to have_json_content(count: 2).at_key(:item)
67
+ end
68
+
69
+ it 'checks equality if #with_full_match is set.' do
70
+ expect {
71
+ expect(json).to have_json_content(name: 'item 1').at_key(:item).with_full_match
72
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError
73
+ expect(json).to have_json_content(count: 2, name: 'item 1').at_key(:item)
74
+ end
75
+
76
+ it 'fails if additional key value pairs are passed as expected.' do
77
+ expect {
78
+ expect(json).to have_json_content(name: 'item 1', count: 2, price: 100).at_key(:item)
79
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError
80
+ expect {
81
+ expect(json).to have_json_content(name: 'item 1', count: 2, price: 100).at_key(:item).with_full_match
82
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError
83
+ end
84
+
85
+ it 'fails with error message giving information about order check, actual, expected (and diff).' do
86
+ expect {
87
+ expect(json).to have_json_content(name: 'item 2').at_key(:item)
88
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError, /expected\n \{"name"=>"item 1", "count"=>2\}\nto include\n \{"name"=>"item 2"\}/
89
+ expect {
90
+ expect(json).to have_json_content(name: 'item 1').at_key(:item).with_full_match
91
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError, /expected\n \{"name"=>"item 1", "count"=>2\}\nto equal\n \{"name"=>"item 1"\}/
92
+ end
93
+
94
+ it 'works as compound matcher.' do
95
+ expect(json).to have_json_content(name: 'item 1', count: 2).at_key(:item).and include('"item":')
96
+ expect(json).to have_json_content(name: 'item 2', count: 1).at_key(:item).or include('"item":')
97
+ expect(response).to have_json_content(count: 2).at_key(:item).and have_json_content('item 1').at_key :item, :name
98
+ end
99
+ end
@@ -0,0 +1,5 @@
1
+ RSpec.describe JsonResponseMatchers do
2
+ it "has a version number" do
3
+ expect(JsonResponseMatchers::VERSION).to eq '1.1.0'
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require "bundler/setup"
2
+ require "json_response_matchers"
3
+
4
+ RSpec.configure do |config|
5
+ # Enable flags like --only-failures and --next-failure
6
+ config.example_status_persistence_file_path = ".rspec_status" if RSpec::Core::Version::STRING >= '3.3.0'
7
+
8
+ # Disable RSpec exposing methods globally on `Module` and `main`
9
+ config.disable_monkey_patching!
10
+
11
+ config.expect_with :rspec do |c|
12
+ c.syntax = :expect
13
+ end
14
+
15
+ config.include JsonResponseMatchers
16
+ end
@@ -0,0 +1,94 @@
1
+ RSpec.describe '#have_json_values' do
2
+ let(:items) do
3
+ {
4
+ items: [
5
+ { name: 'item 1', count: 2 },
6
+ { name: 'item 2', count: 11 },
7
+ { name: 'item 3', count: 0 }
8
+ ]
9
+ }
10
+ end
11
+ let(:json) { items.to_json }
12
+ let(:response) { Struct.new(:body).new items.to_json }
13
+
14
+ it 'works with string keys.' do
15
+ expect(json).to have_json_values('item 1', 'item 2', 'item 3').for('name').at_key('items')
16
+ end
17
+
18
+ it 'works with symbol keys.' do
19
+ expect(json).to have_json_values('item 1', 'item 2', 'item 3').for(:name).at_key(:items)
20
+ end
21
+
22
+ it 'works with integer keys for array.' do
23
+ json_in_array = [ items ].to_json
24
+ expect(json_in_array).to have_json_values(2, 11, 0).for(:count).at_key 0, :items
25
+ end
26
+
27
+ it 'works for the response object.' do
28
+ expect(response).to have_json_values('item 1', 'item 2', 'item 3').for(:name).at_key(:items)
29
+ end
30
+
31
+ it 'works for the response body (json string).' do
32
+ expect(response.body).to have_json_values('item 1', 'item 2', 'item 3').for(:name).at_key(:items)
33
+ end
34
+
35
+ it 'works with no key passed.' do
36
+ expect(items[:items].to_json).to have_json_values('item 1', 'item 2', 'item 3').for(:name)
37
+ end
38
+
39
+ it 'works with multiple keys passed.' do
40
+ expect({ container: items }.to_json).to have_json_values('item 1', 'item 2', 'item 3').for(:name).at_key(:container, :items)
41
+ end
42
+
43
+ it 'fails if no :for passed' do
44
+ expect {
45
+ expect(json).to have_json_values('item 1', 'item 2', 'item 3').at_key(:items)
46
+ }.to raise_exception ArgumentError, /set one or more attributes/
47
+ end
48
+
49
+ it 'works with multiple :fors passed' do
50
+ expect(json).to have_json_values([ 'item 1', 2 ], [ 'item 2', 11 ], [ 'item 3', 0 ]).for(:name, :count).at_key(:items)
51
+ end
52
+
53
+ it 'works with falsy values too.' do
54
+ json = { items: [ { value: nil }, { value: false }, { value: true } ] }.to_json
55
+ expect(json).to have_json_values(nil, false, true).for(:value).at_key :items
56
+ end
57
+
58
+ it 'does not check array order by default.' do
59
+ expect(json).to have_json_values('item 2', 'item 1', 'item 3').for(:name).at_key(:items)
60
+ end
61
+
62
+ it 'checks array order if #in_strict_order is set.' do
63
+ expect {
64
+ expect(json).to have_json_values('item 2', 'item 1', 'item 3').in_strict_order.for(:name).at_key(:items)
65
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError
66
+ expect(json).to have_json_values('item 1', 'item 2', 'item 3').for(:name).at_key(:items).in_strict_order
67
+ end
68
+
69
+ it 'fails if additional elements are passed as expected.' do
70
+ expect {
71
+ expect(json).to have_json_values('item 1', 'item 2', 'item 3', 'item 4').for(:name).at_key(:items)
72
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError
73
+ expect {
74
+ expect(json).to have_json_values('item 1', 'item 2', 'item 3', 'item 4').for(:name).at_key(:items).in_strict_order
75
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError
76
+ end
77
+
78
+ it 'fails with error message giving information about order check, actual, expected (and diff).' do
79
+ expect {
80
+ expect(json).to have_json_values('item 1').for(:name).at_key(:items)
81
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError, /expected\n \["item 1", "item 2", "item 3"\]\nto match\n \["item 1"\]/
82
+ expect {
83
+ expect(json).to have_json_values('item 1').for(:name).at_key(:items).in_strict_order
84
+ }.to raise_exception RSpec::Expectations::ExpectationNotMetError, /expected\n \["item 1", "item 2", "item 3"\]\nto equal\n \["item 1"\]/
85
+ end
86
+
87
+ it 'works as compound matcher.' do
88
+ expect(json).to have_json_values('item 1', 'item 2', 'item 3').for(:name).at_key(:items).and include('"items":')
89
+ expect(json).to have_json_values('item 4', 'item 5', 'item 6').for(:name).at_key(:items).or include('"items":')
90
+ expect('{"items":[{"id":1},{"id":2}],"page":2}')
91
+ .to have_json_values(1, 2).for(:id).at_key(:items)
92
+ .and have_json_content(2).at_key(:page)
93
+ end
94
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: json_response_matchers
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Szijjártó Nagy Misu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-01-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 4.0.6
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 4.0.6
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: appraisal
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.2'
83
+ description: 'Provides two matchers (#have_json_content and #have_json_values) to
84
+ make testing the content of json responses easy.'
85
+ email:
86
+ - szijjartonagy.misu@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".rspec"
92
+ - Appraisals
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - bin/test
98
+ - gemfiles/activesupport_4.gemfile
99
+ - gemfiles/activesupport_4.gemfile.lock
100
+ - gemfiles/activesupport_5.2.2.gemfile
101
+ - gemfiles/activesupport_5.2.2.gemfile.lock
102
+ - gemfiles/activesupport_5.gemfile
103
+ - gemfiles/activesupport_5.gemfile.lock
104
+ - gemfiles/rspec_3.8.gemfile
105
+ - gemfiles/rspec_3.8.gemfile.lock
106
+ - gemfiles/rspec_3.gemfile
107
+ - gemfiles/rspec_3.gemfile.lock
108
+ - json_response_matchers.gemspec
109
+ - lib/json_response_matchers.rb
110
+ - lib/json_response_matchers/base.rb
111
+ - lib/json_response_matchers/content.rb
112
+ - lib/json_response_matchers/values.rb
113
+ - lib/json_response_matchers/version.rb
114
+ - spec/content_spec.rb
115
+ - spec/json_response_matchers_spec.rb
116
+ - spec/spec_helper.rb
117
+ - spec/values_spec.rb
118
+ homepage: https://github.com/SzNagyMisu/json_response_matchers
119
+ licenses:
120
+ - MIT
121
+ metadata:
122
+ homepage_uri: https://github.com/SzNagyMisu/json_response_matchers
123
+ source_code_uri: https://github.com/SzNagyMisu/json_response_matchers
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: 2.0.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.6
141
+ signing_key:
142
+ specification_version: 4
143
+ summary: rspec matchers to test http responses with json content in rails
144
+ test_files:
145
+ - gemfiles/activesupport_4.gemfile
146
+ - gemfiles/activesupport_4.gemfile.lock
147
+ - gemfiles/activesupport_5.2.2.gemfile
148
+ - gemfiles/activesupport_5.2.2.gemfile.lock
149
+ - gemfiles/activesupport_5.gemfile
150
+ - gemfiles/activesupport_5.gemfile.lock
151
+ - gemfiles/rspec_3.8.gemfile
152
+ - gemfiles/rspec_3.8.gemfile.lock
153
+ - gemfiles/rspec_3.gemfile
154
+ - gemfiles/rspec_3.gemfile.lock
155
+ - spec/content_spec.rb
156
+ - spec/json_response_matchers_spec.rb
157
+ - spec/spec_helper.rb
158
+ - spec/values_spec.rb
159
+ - Appraisals
160
+ - Gemfile
161
+ - Rakefile
162
+ - ".rspec"
163
+ - bin/test