diff --git a/README.md b/README.md index 952a98d..9875de6 100644 --- a/README.md +++ b/README.md @@ -310,10 +310,86 @@ You can also remember JSON inline: Then the JSON response at "0/first_name" should be %{FIRST_NAME} ``` +MiniTest +-------- + +json_spec matchers can be used in MiniTest tests. To use json_spec in your tests you must use the minitest-matchers gem. In your `test_helper.rb` you must: + +```ruby +require "minitest/autorun" +require "minitest/matchers" +require "json_spec" + +class MiniTest::Unit::TestCase + include JsonSpec::Matchers +end +``` + +The matchers are now available in MiniTest's spec DSL as follows: + +```ruby +describe User, :to_json do + let(:user) { User.create! first_name: "Steve", last_name: "Richert" } + let(:names) { %({"first_name":"Steve","last_name":"Richert"}) } + + it "includes names" do + user.to_json.must be_json_eql(names).excluding("friends") + end + + it "includes the ID" do + user.to_json.must have_json_path("id") + user.to_json.must have_json_type(Integer).at_path("id") + end + + it "includes friends" do + user.to_json.must have_json_size(0).at_path("friends") + + friend = User.create! first_name: "Catie", last_name: "Richert" + user.friends << friend + + user.to_json.must have_json_size(1).at_path("friends") + user.to_json.must include_json(friend.to_json).at_path("friends") + end +end +``` + +The matchers are also available through MiniTest's classic assertions as follows: + +```ruby +class UserToJsonTest < MiniTest::Unit::TestCase + def setup + @user = User.create! first_name: "Steve", last_name: "Richert" + @names = %({"first_name":"Steve","last_name":"Richert"}) + end + + def test_includes_names + assert_must be_json_eql(@names).excluding("friends"), @user.to_json + end + + def test_includes_id + assert_have_json_path @user.to_json, "id" + assert_must have_json_path("id"), @user.to_json + + assert_must have_json_type(Integer).at_path("id"), @user.to_json + end + + def test_includes_friends + assert_must have_json_size(0).at_path("friends"), @user.to_json + + friend = User.create! first_name: "Catie", last_name: "Richert" + @user.friends << friend + + assert_must have_json_size(1).at_path("friends"), @user.to_json + assert_must include_json(friend.to_json).at_path("friends"), @user.to_json + end +end +``` + ### More Check out the [specs](https://github.com/collectiveidea/json_spec/blob/master/spec) -and [features](https://github.com/collectiveidea/json_spec/blob/master/features) to see all the +and [features](https://github.com/collectiveidea/json_spec/blob/master/features) +and [tests](https://github.com/collectiveidea/json_spec/blob/master/test) to see all the various ways you can use json_spec. Contributing diff --git a/features/support/env.rb b/features/support/env.rb index 5a497c1..038189e 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,5 +1,6 @@ $: << File.expand_path("../../../lib", __FILE__) +require "rspec" require "json_spec/cucumber" JsonSpec.directory = File.expand_path("../../../spec/support/files", __FILE__) diff --git a/json_spec.gemspec b/json_spec.gemspec index 61d2456..8599f83 100644 --- a/json_spec.gemspec +++ b/json_spec.gemspec @@ -12,9 +12,12 @@ Gem::Specification.new do |gem| gem.license = "MIT" gem.add_dependency "multi_json", "~> 1.0" - gem.add_dependency "rspec", ">= 2.0", "< 4.0" - gem.add_development_dependency "bundler", "~> 1.0" + gem.add_development_dependency "rspec", "~> 2.0", "< 4.0" + gem.add_development_dependency "cucumber", "~> 1.1", ">= 1.1.1" + gem.add_development_dependency "rake", "~> 0.9" + gem.add_development_dependency "minitest", "~> 4.0" + gem.add_development_dependency "minitest-matchers", "~> 1.2" gem.files = `git ls-files`.split($\) gem.test_files = gem.files.grep(/^(features|spec)/) diff --git a/lib/json_spec.rb b/lib/json_spec.rb index 8044741..decf0a1 100644 --- a/lib/json_spec.rb +++ b/lib/json_spec.rb @@ -1,5 +1,4 @@ require "json" -require "rspec" require "json_spec/errors" require "json_spec/configuration" require "json_spec/exclusion" diff --git a/lib/json_spec/matchers.rb b/lib/json_spec/matchers.rb index cf58e89..efbcf26 100644 --- a/lib/json_spec/matchers.rb +++ b/lib/json_spec/matchers.rb @@ -25,9 +25,19 @@ def have_json_type(type) def have_json_size(size) JsonSpec::Matchers::HaveJsonSize.new(size) end + + def self.included base + if base.respond_to? :register_matcher + instance_methods.each do |name| + base.register_matcher name, name + end + end + end end end -RSpec.configure do |config| - config.include JsonSpec::Matchers +if defined?(RSpec) + RSpec.configure do |config| + config.include JsonSpec::Matchers + end end diff --git a/lib/json_spec/matchers/include_json.rb b/lib/json_spec/matchers/include_json.rb index a341f2e..5826261 100644 --- a/lib/json_spec/matchers/include_json.rb +++ b/lib/json_spec/matchers/include_json.rb @@ -14,14 +14,10 @@ def matches?(actual_json) actual = parse_json(actual_json, @path) expected = exclude_keys(parse_json(@expected_json)) - case actual - when Hash then actual.values.map{|v| exclude_keys(v) }.include?(expected) - when Array then actual.map{|e| exclude_keys(e) }.include?(expected) - when String then actual.include?(expected) - else false - end + included_in_json?( actual, expected ) end + def at_path(path) @path = path self @@ -53,6 +49,29 @@ def failure_message_for_should_not def description message_with_path("include JSON") end + + private + def included_in_json?( actual, expected ) + case actual + when Hash then included_in_hash?(actual, expected) or actual.values.any?{ |v| included_in_json?(v, expected) } + when Array then included_in_array?(actual, expected) + else actual == expected + end + end + + def included_in_array?( actual_array, expected) + if expected.is_a? Array + (expected - actual_array).empty? + else + actual_array.include? expected + end + end + + def included_in_hash?( actual_hash, expected ) + return false unless expected.is_a? Hash + expected == actual_hash.select{|k,_| expected.has_key? k} + end + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ff72e42..8fedbfb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,4 @@ +require "rspec" require "json_spec" RSpec.configure do |config| diff --git a/test/assertions_test.rb b/test/assertions_test.rb new file mode 100644 index 0000000..959ad9d --- /dev/null +++ b/test/assertions_test.rb @@ -0,0 +1,29 @@ +require "test_helper" + +class UserToJsonTest < MiniTest::Unit::TestCase + def setup + @user = OpenStruct.new id: 42, first_name: "Steve", last_name: "Richert", friends: [] + @names = %({"first_name":"Steve","last_name":"Richert"}) + end + + def test_includes_names + assert_must be_json_eql(@names).excluding("friends"), @user.to_json + end + + def test_includes_id + assert_have_json_path @user.to_json, "id" + assert_must have_json_path("id"), @user.to_json + + assert_must have_json_type(Integer).at_path("id"), @user.to_json + end + + def test_includes_friends + assert_must have_json_size(0).at_path("friends"), @user.to_json + + friend = OpenStruct.new first_name: "Catie", last_name: "Richert" + @user.friends << friend + + assert_must have_json_size(1).at_path("friends"), @user.to_json + assert_must include_json(friend.to_json).at_path("friends"), @user.to_json + end +end diff --git a/test/expectations_test.rb b/test/expectations_test.rb new file mode 100644 index 0000000..3afef58 --- /dev/null +++ b/test/expectations_test.rb @@ -0,0 +1,38 @@ +require "test_helper" + +describe "User", :to_json do + let(:user) { OpenStruct.new id: 42, first_name: "Steve", last_name: "Richert", friends: [] } + let(:names) { %({"first_name":"Steve","last_name":"Richert"}) } + subject { user.to_json } + + it "includes names" do + user.to_json.must be_json_eql(names).excluding("friends") + end + + it { must be_json_eql(names).excluding("friends") } + must { be_json_eql(names).excluding("friends") } + + it "includes the ID" do + user.to_json.must have_json_path("id") + user.to_json.must have_json_type(Integer).at_path("id") + end + + it { must have_json_path("id") } + must { have_json_path("id") } + + it { must have_json_type(Integer).at_path("id") } + must { have_json_type(Integer).at_path("id") } + + it "includes friends" do + user.to_json.must have_json_size(0).at_path("friends") + + friend = OpenStruct.new first_name: "Catie", last_name: "Richert" + user.friends << friend + + user.to_json.must have_json_size(1).at_path("friends") + user.to_json.must include_json(friend.to_json).at_path("friends") + end + + it { must have_json_size(0).at_path("friends") } + must { have_json_size(0).at_path("friends") } +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..a9867a7 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,17 @@ +require "minitest/autorun" +require "minitest/matchers" +require "json_spec" + +# Make JsonSpec avaialble in tests +class MiniTest::Unit::TestCase + include JsonSpec::Matchers +end + +# Give OpenStruct support for to_json +require "ostruct" + +class OpenStruct + def to_json *args + table.to_json *args + end +end