dalziel 0.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
+ SHA1:
3
+ metadata.gz: 6944cdfc4fdc1dd2a028bfb9c6fe2583daf677a9
4
+ data.tar.gz: 2da11520a936a1a849d3309273f65f50ff65a992
5
+ SHA512:
6
+ metadata.gz: 3ad60a04ed570187c166d925c6da42758d0b306860edce7966ff76f5146840f07b80a2e8e6bbd0de9e4b91b1b09952271546abca82c89cc2f09dc2983c428741
7
+ data.tar.gz: ab6de7d98900481fad52bb34684327050f3f90953ee8a149a254ebcea0869d392c9fde3a39bd5ada610639e9c38df5808929cec926bc64f24f334b9351871c12
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.14.4
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dalziel.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # Dalziel
2
+
3
+ Convenience library for testing JSON API calls in RSpec.
4
+ Uses [WebMock](https://github.com/bblimke/webmock) and
5
+ [JSON Expressions](https://github.com/chancancode/json_expressions).
6
+
7
+ * Easily specify JSON responses for stubbed calls with WebMock.
8
+ * Verify that the request you've sent contains the right data.
9
+ * Verify that you respond as a proper JSON API.
10
+ * Easy to read failure messages
11
+
12
+ ## Usage
13
+
14
+ Testing outgoing requests:
15
+
16
+ ``` ruby
17
+
18
+ it "makes the right request" do
19
+
20
+ # lightweight wrapper around webmock for stubbing JSON calls
21
+ request = stub_json_request(
22
+ :put,
23
+ "http://some-api-call"
24
+ user: {
25
+ id: 5,
26
+ name: "Pascoe"
27
+ }
28
+ )
29
+
30
+ call_your_code
31
+
32
+ # make sure you sent the right data to the external service
33
+ expect(request).to match_json_request(
34
+ user: {
35
+ name: "Pascoe",
36
+ password: String,
37
+ }.ignore_extra_keys!
38
+ )
39
+ end
40
+ ```
41
+
42
+ The other side of the request, verify that you behave as a JSON API:
43
+
44
+ ``` ruby
45
+ it "creates a user" do
46
+ post "/users", user: { name: "Pascoe" }
47
+
48
+ expect(User.count).to eq 1
49
+
50
+ expect(last_response).to match_json_response(
51
+ user: {
52
+ id: Integer,
53
+ name: String,
54
+ }.ignore_extra_keys!
55
+ ).status(201) # defaults to 200
56
+ end
57
+ ```
58
+
59
+ This tests your headers too.
60
+
61
+ ## Installation
62
+
63
+ Add this line to your application's Gemfile:
64
+
65
+ ```ruby
66
+ gem 'dalziel', group: :test
67
+ ```
68
+
69
+ ## Development
70
+
71
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
72
+ `rake spec` to run the tests. You can also run `bin/console` for an interactive
73
+ prompt that will allow you to experiment.
74
+
75
+ To install this gem onto your local machine, run `bundle exec rake install`.
76
+ To release a new version, update the version number in `version.rb`,
77
+ and then run `bundle exec rake release`, which will create a git tag
78
+ for the version, push git commits and tags, and push the `.gem` file to
79
+ [rubygems.org](https://rubygems.org).
80
+
81
+ ## License
82
+
83
+ The gem is available as open source under the terms of the [MIT
84
+ License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dalziel"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/dalziel.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dalziel/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dalziel"
8
+ spec.version = Dalziel::VERSION
9
+ spec.authors = ["iain"]
10
+ spec.email = ["iain@iain.nl"]
11
+
12
+ spec.summary = %q{Convenience gem for testing JSON API calls}
13
+ spec.description = %q{Convenience gem for testing JSON API calls}
14
+ spec.homepage = "https://github.com/iain/dalziel"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.14"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+
28
+ spec.add_dependency "json_expressions", "~> 0.8"
29
+ spec.add_dependency "webmock", "~> 2.3"
30
+ end
@@ -0,0 +1,3 @@
1
+ module Dalziel
2
+ VERSION = "0.1.0"
3
+ end
data/lib/dalziel.rb ADDED
@@ -0,0 +1,232 @@
1
+ require "dalziel/version"
2
+ require "json_expressions"
3
+ require "webmock"
4
+
5
+ module Dalziel
6
+
7
+ def self.format_headers(headers)
8
+ size = headers.keys.map(&:size).max
9
+ headers.map { |k,v| "%-#{size + 2}s %s" % [ "#{k}:", v ] }.join("\n")
10
+ end
11
+
12
+ def self.indent(string)
13
+ string.split("\n").map { |line| " #{line}" }.join("\n")
14
+ end
15
+
16
+ module Matchers
17
+
18
+ # Stubs outgoing JSON requests with WebMock.
19
+ #
20
+ # Usage:
21
+ #
22
+ # stub_json_request(:get, "url", user: { id: 1 })
23
+ def stub_json_request(verb, url, body, status = 200)
24
+ stub_request(verb, url).to_return(
25
+ headers: { content_type: "application/json" },
26
+ body: body.to_json,
27
+ status: status,
28
+ )
29
+ end
30
+
31
+
32
+ # Verifies outgoing request body stubbed with WebMock.
33
+ #
34
+ # Usage:
35
+ #
36
+ # req = stub_json_request(:get, "url", user: { id: 1 })
37
+ #
38
+ # act
39
+ #
40
+ # expect(req).to match_json_request(
41
+ # foo: {
42
+ # bar: Integer
43
+ # }
44
+ # )
45
+ def match_json_request(pattern)
46
+ RequestMatcher.new(pattern)
47
+ end
48
+
49
+ # Verifies that the response is a proper JSON response.
50
+ # Optionally you can chain `status` to verify the status code.
51
+ #
52
+ # Usage:
53
+ #
54
+ # get "/foo/bar"
55
+ # expect(last_response).to match_json_response(
56
+ # foo: {
57
+ # bar: Integer
58
+ # }
59
+ # )
60
+ def match_json_response(pattern)
61
+ ResponseMatcher.new(pattern)
62
+ end
63
+
64
+ # Replacement for the json_expression default matcher, shows prettier output.
65
+ #
66
+ # Usage:
67
+ #
68
+ # expect(json_or_hash).to match_json_expression(
69
+ # user: {
70
+ # id: Integer
71
+ # }
72
+ # )
73
+ def match_json_expression(pattern)
74
+ JSONPatternMatcher.new(pattern)
75
+ end
76
+
77
+ class JSONPatternMatcher
78
+
79
+ attr_reader :json_expression, :request, :body
80
+
81
+ def initialize(json_expression)
82
+ @json_expression = json_expression
83
+ end
84
+
85
+ def does_not_match?(*)
86
+ fail "Inverted matching is not implemented with this matcher"
87
+ end
88
+
89
+ def matches?(json)
90
+ @original = json
91
+ @hash = json.is_a?(String) ? JSON.parse(json) : json
92
+ matcher =~ @hash
93
+ rescue JSON::ParserError => error
94
+ @not_parsable_json = error
95
+ false
96
+ end
97
+
98
+ def failure_message
99
+ if @not_parsable_json
100
+ original = Dalziel.indent(@original.inspect)
101
+ error = "#{@not_parsable_json.class}: #{@not_parsable_json}"
102
+ "Couldn't parse the following:\n\n%s\n\n%s" % [ original, error ]
103
+ else
104
+ json = Dalziel.indent(JSON.pretty_generate(@hash))
105
+ type = @original.is_a?(String) ? "JSON" : @original.class.to_s
106
+ "Got the following %s:\n\n%s\n\n%s" % [ type, json, matcher.last_error ]
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ def matcher
113
+ @matcher ||= JsonExpressions::Matcher.new(json_expression)
114
+ end
115
+
116
+ end
117
+
118
+ class RequestMatcher
119
+
120
+ attr_reader :json_expression, :request, :body
121
+
122
+ def initialize(json_expression)
123
+ @json_expression = json_expression
124
+ end
125
+
126
+ def matches?(request_pattern)
127
+ @request = nil
128
+ all_stubbed_requests.each { |request_signature, _count|
129
+ if request_pattern.matches?(request_signature)
130
+ @request = request_signature
131
+ break
132
+ end
133
+ }
134
+ return false if @request.nil?
135
+
136
+ @body = JSON.parse(@request.body)
137
+ @accept = @request.headers["Accept"]
138
+
139
+ @is_json = @accept =~ /\bjson$/
140
+ @json_match = payload_matcher =~ @body
141
+
142
+ @is_json && @json_match
143
+ end
144
+
145
+ def does_not_match?(response)
146
+ fail "Inverted matching is not implemented with this matcher"
147
+ end
148
+
149
+ def failure_message
150
+ if @request == []
151
+ "No request matched"
152
+ elsif !@is_json
153
+ "Accept header is not JSON.\n\n%s\n\nAccept is %s" % [ show_request, @accept.inspect ]
154
+ else
155
+ "Request body did not match.\n\n%s\n\n%s" % [ show_request, payload_matcher.last_error ]
156
+ end
157
+ end
158
+
159
+ def show_request
160
+ headers = Dalziel.format_headers(request.headers)
161
+ Dalziel.indent "%s %s\n\n%s\n\n%s" % [ request.method.to_s.upcase, request.uri.to_s, headers, JSON.pretty_generate(body) ]
162
+ end
163
+
164
+ def payload_matcher
165
+ @payload_matcher ||= JsonExpressions::Matcher.new(json_expression)
166
+ end
167
+
168
+ def all_stubbed_requests
169
+ WebMock::RequestRegistry.instance.requested_signatures
170
+ end
171
+
172
+ end
173
+
174
+ class ResponseMatcher
175
+
176
+ attr_reader :json_expression, :response, :body
177
+
178
+ def initialize(json_expression)
179
+ @json_expression = json_expression
180
+ @status = 200
181
+ end
182
+
183
+ def matches?(response)
184
+ @response = response
185
+ @body = JSON.parse(response.body)
186
+ @content_type = response.headers["Content-Type"]
187
+
188
+ @is_json = (@content_type.to_s.split(";",2).first =~ /\bjson$/)
189
+ @json_match = (payload_matcher =~ @body)
190
+ @status_match = (@status == response.status)
191
+
192
+ @status_match && @is_json && @json_match
193
+ end
194
+
195
+ def does_not_match?(response)
196
+ fail "Inverted matching is not implemented with this matcher"
197
+ end
198
+
199
+ def failure_message
200
+ if !@is_json
201
+ "Content-Type is not JSON.\n\n%s\n\nContent-Type is %s" % [ show_response, @content_type.inspect ]
202
+ elsif !@status_match
203
+ "Unexpected response status.\n\n%s\n\nExpected response status to be %s, but was %s." % [ show_response, @status.inspect, response.status ]
204
+ else
205
+ "Response body did not match.\n\n%s\n\n%s" % [ show_response, payload_matcher.last_error ]
206
+ end
207
+ end
208
+
209
+ def payload_matcher
210
+ @payload_matcher ||= JsonExpressions::Matcher.new(json_expression)
211
+ end
212
+
213
+ def show_response
214
+ headers = Dalziel.format_headers(response.headers)
215
+ Dalziel.indent "HTTP/1.1 %s\n\n%s\n\n%s" % [ response.status, headers, JSON.pretty_generate(body) ]
216
+ end
217
+
218
+ def status(code)
219
+ @status = code
220
+ self
221
+ end
222
+
223
+ end
224
+
225
+ end
226
+ end
227
+
228
+ if defined?(RSpec)
229
+ RSpec.configure do |config|
230
+ config.include Dalziel::Matchers
231
+ end
232
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dalziel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - iain
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-03-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: json_expressions
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.8'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.3'
83
+ description: Convenience gem for testing JSON API calls
84
+ email:
85
+ - iain@iain.nl
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - dalziel.gemspec
99
+ - lib/dalziel.rb
100
+ - lib/dalziel/version.rb
101
+ homepage: https://github.com/iain/dalziel
102
+ licenses:
103
+ - MIT
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 2.5.1
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: Convenience gem for testing JSON API calls
125
+ test_files: []