Skip to content

Commit

Permalink
Ignore JSON keys order when stubbing a request fixes bblimke#485
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan van der Pas committed Sep 12, 2016
1 parent a4aad22 commit 73ff562
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 7 deletions.
12 changes: 12 additions & 0 deletions lib/webmock/request_pattern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def with(options = {}, &block)
def matches?(request_signature)
content_type = request_signature.headers['Content-Type'] if request_signature.headers
content_type = content_type.split(';').first if content_type

@method_pattern.matches?(request_signature.method) &&
@uri_pattern.matches?(request_signature.uri) &&
(@body_pattern.nil? || @body_pattern.matches?(request_signature.body, content_type || "")) &&
Expand Down Expand Up @@ -235,6 +236,17 @@ def matches?(body, content_type = "")
matching_hashes?(body_as_hash(body, content_type), @pattern)
elsif (@pattern).is_a?(WebMock::Matchers::HashIncludingMatcher)
@pattern == body_as_hash(body, content_type)
elsif @pattern.is_a?(String) && BODY_FORMATS[content_type] == :json
begin
# Would have used WebMock::Util::JSON.parse in the #body_as_hash method,
# but it doesn't raise on invalid JSON, e.g. "foo bar".
actual = normalize_hash(JSON.parse(body))
expected = normalize_hash(JSON.parse(@pattern))
rescue JSON::ParserError
return matches?(body)
end

matching_hashes?(actual, expected)
else
empty_string?(@pattern) && empty_string?(body) ||
@pattern == body ||
Expand Down
55 changes: 48 additions & 7 deletions spec/unit/request_pattern_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

describe WebMock::RequestPattern do

before(:all) do
WebMock::RequestPattern.send(:alias_method, :match, :matches?)
end

describe "describing itself" do
it "should report string describing itself" do
expect(WebMock::RequestPattern.new(:get, "www.example.com",
Expand Down Expand Up @@ -62,13 +66,6 @@
end
end


class WebMock::RequestPattern
def match(request_signature)
self.matches?(request_signature)
end
end

describe "when matching" do

it "should match if uri matches and method matches" do
Expand Down Expand Up @@ -506,6 +503,50 @@ def match(request_signature)
not_to match(signature)
end
end

describe "when body in pattern is declared as a JSON string" do
let(:body_json) do
JSON.generate({ :a => '1', :b => 'five', 'c' => { 'd' => ['e', 'f'] } })
end

describe "for request with json body and content type is set to json" do
it "should match if JSON body matches body" do
expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_json)).
to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: 'application/json'},
body: '{"a":"1","b":"five","c":{"d":["e","f"]}}'))
end

it "should match when JSON body matches body in different order" do
expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_json)).
to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: 'application/json'},
body: '{"a":"1","c":{"d":["e","f"]},"b":"five"}'))
end

it "should not match when body is not json" do
expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_json)).
not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
headers: {content_type: 'application/json'}, body: "foo bar"))
end

it "should not match if request body is different" do
expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: JSON.generate({a: 1, b: 2}))).
not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
headers: {content_type: 'application/json'}, body: '{"a":1,"c":null}'))
end

it "should not match if request body is has less params than pattern" do
expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: JSON.generate({a: 1, b: 2}))).
not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
headers: {content_type: 'application/json'}, body: '{"a":1}'))
end

it "should not match if request body is has more params than pattern" do
expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: JSON.generate({a: 1}))).
not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
headers: {content_type: 'application/json'}, body: '{"a":1,"c":1}'))
end
end
end
end

it "should match if pattern and request have the same headers" do
Expand Down

0 comments on commit 73ff562

Please sign in to comment.