Skip to content

Match nested json without a specific path #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ Easily handle JSON in RSpec and Cucumber
RSpec
--------------

json_spec defines five new RSpec matchers:
json_spec defines six new RSpec matchers:

* `be_json_eql`
* `include_json`
# `include_nested_json`
* `have_json_path`
* `have_json_type`
* `have_json_size`
Expand Down Expand Up @@ -40,6 +41,12 @@ describe User do
user.to_json.should have_json_size(1).at_path("friends")
user.to_json.should include_json(friend.to_json)
end

it "includes user id within response" do
new_user = User.create!(first_name: "Catie", last_name: "Richert")
users_json = User.page(1).to_json
users_json.should include_nested_json("{id: #{new_user.id}}")
end
end
end
```
Expand Down
5 changes: 5 additions & 0 deletions lib/json_spec/matchers.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "json_spec/matchers/be_json_eql"
require "json_spec/matchers/include_json"
require "json_spec/matchers/include_nested_json"
require "json_spec/matchers/have_json_path"
require "json_spec/matchers/have_json_type"
require "json_spec/matchers/have_json_size"
Expand All @@ -14,6 +15,10 @@ def include_json(json = nil)
JsonSpec::Matchers::IncludeJson.new(json)
end

def include_nested_json(json = nil)
JsonSpec::Matchers::IncludeNestedJson.new(json)
end

def have_json_path(path)
JsonSpec::Matchers::HaveJsonPath.new(path)
end
Expand Down
45 changes: 45 additions & 0 deletions lib/json_spec/matchers/include_nested_json.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module JsonSpec
module Matchers
class IncludeNestedJson < IncludeJson

def matches?(actual_json)
raise "Expected included JSON not provided" if @expected_json.nil?
actual = parse_json(actual_json)
matches_nested?(actual)
end

def matches_nested?(parsed_json)
case parsed_json
when Hash
parsed_json.values.map{|v| exclude_keys(v) }.include?(expected) ||
test_contained_enumerables(parsed_json.values)
when Array
parsed_json.map{|e| exclude_keys(e) }.include?(expected) ||
test_contained_enumerables(parsed_json)
when String then parsed_json.include?(expected)
else false
end
end

def test_contained_enumerables(values)
values.map do |value|
value.respond_to?(:each) && matches_nested?(value)
end.detect {|test| !!test }
end

def expected
@expected ||= exclude_keys(parse_json(@expected_json))
end

def failure_message_for_should
message_with_path("Expected 'actual' to include nested 'expected' JSON")
end

def failure_message_for_should_not
message_with_path("Expected 'actual' to not include nested 'expected' JSON")
end

undef at_path
end
end
end
24 changes: 24 additions & 0 deletions spec/json_spec/matchers/include_nested_json_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require "spec_helper"

describe JsonSpec::Matchers::IncludeNestedJson do

describe "matching nested values" do
json_strings = [
%({"fname":"jolly", "lname":"roger", "partners": [{"fname": "dread pirate", "lname": "roberts"}]}),
%({"fname":"jolly", "lname":"roger", "partner": {"fname": "dread pirate", "lname": "roberts"}}),
%({"fname":"jolly", "lname":"roger", "connections": {"partners": [{"fname": "dread pirate", "lname": "roberts"}]}})
]

it "matches values regardless of path depth" do
json_strings.each do |json_string|
json_string.should include_nested_json '{"fname": "dread pirate", "lname": "roberts"}'
end
end

it "does not match value split across depths" do
json_strings.each do |json_string|
json_string.should_not include_nested_json '{"fname": "dread pirate", "lname": "roger"}'
end
end
end
end