{"id":13521122,"url":"https://github.com/PikachuEXE/rspec-json_matchers","last_synced_at":"2025-03-31T20:30:43.797Z","repository":{"id":34701162,"uuid":"38676915","full_name":"PikachuEXE/rspec-json_matchers","owner":"PikachuEXE","description":"A collection of RSpec matchers for testing JSON data.","archived":false,"fork":false,"pushed_at":"2024-12-26T00:40:03.000Z","size":158,"stargazers_count":30,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-22T16:03:00.714Z","etag":null,"topics":["gem","rspec","rspec-matchers","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PikachuEXE.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["PikachuEXE"]}},"created_at":"2015-07-07T09:15:05.000Z","updated_at":"2025-01-14T03:46:17.000Z","dependencies_parsed_at":"2024-12-01T02:24:42.545Z","dependency_job_id":"edfe7394-d7b7-493b-b5a2-7c30590eaddd","html_url":"https://github.com/PikachuEXE/rspec-json_matchers","commit_stats":{"total_commits":110,"total_committers":6,"mean_commits":"18.333333333333332","dds":"0.18181818181818177","last_synced_commit":"04ebe3e6957c1df55c7367d57f592550a5384db6"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PikachuEXE%2Frspec-json_matchers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PikachuEXE%2Frspec-json_matchers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PikachuEXE%2Frspec-json_matchers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PikachuEXE%2Frspec-json_matchers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PikachuEXE","download_url":"https://codeload.github.com/PikachuEXE/rspec-json_matchers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246215825,"owners_count":20741894,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gem","rspec","rspec-matchers","ruby"],"created_at":"2024-08-01T06:00:28.962Z","updated_at":"2025-03-31T20:30:43.774Z","avatar_url":"https://github.com/PikachuEXE.png","language":"Ruby","funding_links":["https://github.com/sponsors/PikachuEXE"],"categories":["Matchers"],"sub_categories":[],"readme":"# RSpec::JsonMatchers\n\nA collection of RSpec matchers for testing JSON data.\n\nThis gem provides a collection of RSpec matchers for testing JSON data.\nIt aims to make JSON testing flexible \u0026 easier, especially for testing multiple properties.\nIt does not and will not have anything related to JSON Schema.\n\nYou can read [the story of this project](https://github.com/PikachuEXE/rspec-json_matchers/blob/master/doc/Story.md) if you have time.\n\n\n## Status\n\n[![GitHub Build Status](https://img.shields.io/github/actions/workflow/status/PikachuEXE/rspec-json_matchers/tests.yaml?branch=master\u0026style=flat-square)](https://github.com/PikachuEXE/rspec-json_matchers/actions/workflows/tests.yaml)\n\n[![Gem Version](http://img.shields.io/gem/v/rspec-json_matchers.svg?style=flat-square)](http://badge.fury.io/rb/rspec-json_matchers)\n[![License](https://img.shields.io/github/license/PikachuEXE/rspec-json_matchers.svg?style=flat-square)](http://badge.fury.io/rb/rspec-json_matchers)\n\n[![Coverage Status](http://img.shields.io/coveralls/PikachuEXE/rspec-json_matchers.svg?style=flat-square)](https://coveralls.io/r/PikachuEXE/rspec-json_matchers)\n[![Code Climate](https://img.shields.io/codeclimate/maintainability/PikachuEXE/rspec-json_matchers.svg?style=flat-square)](https://codeclimate.com/github/PikachuEXE/rspec-json_matchers)\n[![Inch CI](https://inch-ci.org/github/PikachuEXE/rspec-json_matchers.svg?branch=master)](https://inch-ci.org/github/PikachuEXE/rspec-json_matchers)\n\n\u003e The above badges are generated by https://shields.io/\n\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\n# `require` can be set to `true` safely without too much side effect\n# (except having additional modules \u0026 classes defined which could be wasting memory).\n# But there is no point requiring it unless in test\n# Also maybe add it inside a \"group\"\ngem 'rspec-json_matchers', require: false\n```\n\nAnd then execute:\n\n```bash\n$ bundle\n```\n\nOr install it yourself as:\n\n```bash\n$ gem install rspec-json_matchers\n```\n\n## Usage\n\nTo include the new matchers in your examples,  \nadd the following code somewhere which will be loaded by `rails_helper`/`spec_helper`:\n```ruby\n# Remember the `required: false` suggested earlier?\n# Now is the time that it is actually \"required\"\nrequire \"rspec-json_matchers\"\n\n# This will include matcher methods globally for all spec\n# You can choose to include it conditionally, but you should decide yourself\n# Or just ignore this comment if you are just trying this out\nRSpec.configure do |config|\n  config.include RSpec::JsonMatchers::Matchers\nend\n```\n\n### Matcher `be_json`\n\nThis is the starting point of all new matchers.\nIt can be used alone to ensure that the input can be parsed by `JSON` without error.\n\n```ruby\nspecify { expect(\"{}\").to be_json } # =\u003e pass\nspecify { expect(\"[]\").to be_json } # =\u003e pass\nspecify { expect(\"\").to be_json }   # =\u003e fail\n```\n\n### Matcher `be_json.with_content`\n\nThis is perhaps the most flexible \u0026 powerful matcher in this gem.\n\n\n#### Content equivalence matching\n\nWhen passing in \"simple data values\" (that represents one of JSON data types),  \nit matches when they have equivalent values (using `==`).\n```ruby\nspecify { expect(\"{}\").to be_json.with_content(Hash.new) }    # =\u003e pass\nspecify { expect(\"[]\").to be_json.with_content(Array.new) }   # =\u003e pass\n\nspecify { expect(\"{}\").to be_json.with_content(Array.new) }    # =\u003e fail\nspecify { expect(\"[]\").to be_json.with_content(Hash.new) }   # =\u003e fail\n\n# The following line would fail when trying parse the input as JSON\n# So you can be sure the input is a valid JSON\nspecify { expect(\"\").to be_json.with_content(Hash.new) }      # =\u003e fail\n```\n\nSince it's common to have multiple \"properties\" in an object,  \nthe gem allows multiple key as well, instead of having to create multiple examples for all properties you want to test.\n```ruby\n# Ruby object + `to_json` + Symbol keys is used for easier typing in the following examples,\n# but the actual JSON string won't change.\n\n# Matching object with single key with String keys in expected\nspecify { expect({a: 1}.to_json).to be_json.with_content({\"a\" =\u003e 1}) }    # =\u003e pass\n# Matching object with single key with Symbol keys in expected\n# Symbol keys will be used in the remaining examples, String keys can also be used interchangeably\nspecify { expect({a: 1}.to_json).to be_json.with_content({a: 1}) }        # =\u003e pass\n\n# Obviously\nspecify { expect({a: 1}.to_json).to be_json.with_content({a: 2}) }        # =\u003e fail\n\n# The input can have more keys than expected without failing by default\nspecify { expect({a: 1, b: 2}.to_json).to be_json.with_content({a: 1}) }  # =\u003e pass\n# The actual cannot have less keys than expected or will fail the example all the time\nspecify { expect({a: 1}.to_json).to be_json.with_content({a: 1, b: 2}) }  # =\u003e fail\n```\n\nA \"path\" can also be specified for testing deeply nested data.\n\n```ruby\ncontext \"when input is an Hash (in Ruby)\" do\n  subject do\n    {\n      a: {\n        b: {\n          c: 1,\n        },\n      },\n    }.to_json\n  end\n\n  it { should be_json.with_content({a: {b: {c: 1}}}) }          # =\u003e pass\n\n  it { should be_json.with_content({b: {c: 1}}).at_path(\"a\") }  # =\u003e pass\n  it { should be_json.with_content({c: 1}).at_path(\"a.b\") }     # =\u003e pass\n  it { should be_json.with_content(1).at_path(\"a.b.c\") }        # =\u003e pass\n\n  # subject without data at path will cause the example to fail\n  it { should be_json.with_content(1).at_path(\"a.b.d\") }        # =\u003e fail\n  it { should be_json.with_content(1).at_path(\"a.b.c.d\") }      # =\u003e fail\n\n  # Invalid path will cause the gem to fail, `should` or `should_not`\n  # To avoid false positive when used with `should_not`\n  it { should be_json.with_content(\"whatever\").at_path(\".\") }     # =\u003e fail\n  it { should be_json.with_content(\"whatever\").at_path(\".a.\") }   # =\u003e fail\n  it { should be_json.with_content(\"whatever\").at_path(\"a..c\") }  # =\u003e fail\n\n  it { should_not be_json.with_content(\"whatever\").at_path(\".\") }     # =\u003e fail\n  it { should_not be_json.with_content(\"whatever\").at_path(\".a.\") }   # =\u003e fail\n  it { should_not be_json.with_content(\"whatever\").at_path(\"a..c\") }  # =\u003e fail\n\n  # Digits can be used as well in path\n  specify { expect({'1' =\u003e {'2' =\u003e 1}}.to_json).to be_json.with_content({'2' =\u003e 1}).at_path(\"1\") }\n  specify { expect({'1' =\u003e {'2' =\u003e 1}}.to_json).to be_json.with_content(1).at_path(\"1.2\") }\nend\n\ncontext \"when input is an Array (in Ruby)\" do\n  subject do\n    [\n      [\n        [\n          [1],\n        ],\n      ],\n    ].to_json\n  end\n\n  it { should be_json.with_content([[[1]]]) }          # =\u003e pass\n\n  it { should be_json.with_content([[1]]).at_path(\"0\") }        # =\u003e pass\n  it { should be_json.with_content([1]).at_path(\"0.0\") }        # =\u003e pass\n  it { should be_json.with_content(1).at_path(\"0.0.0\") }        # =\u003e pass\n\n  # subject without data at path will cause the example to fail\n  it { should be_json.with_content(1).at_path(\"0.0.1\") }        # =\u003e fail\n  it { should be_json.with_content(1).at_path(\"0.0.0.0\") }      # =\u003e fail\n\n  # Invalid path will cause the gem to fail, `should` or `should_not`\n  # To avoid false positive when used with `should_not`\n  it { should be_json.with_content(\"whatever\").at_path(\".\") }     # =\u003e fail\n  it { should be_json.with_content(\"whatever\").at_path(\".0.\") }   # =\u003e fail\n  it { should be_json.with_content(\"whatever\").at_path(\"0..0\") }  # =\u003e fail\n\n  it { should_not be_json.with_content(\"whatever\").at_path(\".\") }     # =\u003e fail\n  it { should_not be_json.with_content(\"whatever\").at_path(\".0.\") }   # =\u003e fail\n  it { should_not be_json.with_content(\"whatever\").at_path(\"0..0\") }  # =\u003e fail\n\n  # The following pass for `should_not`\n  # Since the matcher would not know the `actual` should match the path, not the reverse one\n  it { should be_json.with_content(\"whatever\").at_path(\"a\") }     # =\u003e fail\n\n  it { should_not be_json.with_content(\"whatever\").at_path(\"a\") } # =\u003e pass\nend\n```\n\n\n#### Special content matching\n\nBesides objects representing JSON data types, there are other objects that can be passed in as special expectation.\n\n```ruby\n# Pass when subject is a String \u0026 matches the Regex\ncontext \"when expected is a Regexp\" do\n  specify { expect({url: \"https://domain.com\"}.to_json).to be_json.with_content(url: %r|^https://|) } # =\u003e pass\n  specify { expect({url: \"http://domain.com\"}.to_json).to be_json.with_content(url: %r|^https://|) }  # =\u003e fail\n  specify { expect({url: 1}.to_json).to be_json.with_content(url: %r|^https://|) }                    # =\u003e fail\nend\n\n# Pass when subject is \"covered\" by the Range\ncontext \"when expected is a Range\" do\n  specify { expect({age: 1}.to_json).to be_json.with_content(age: (1...10)) }   # =\u003e pass\n  specify { expect({age: 10}.to_json).to be_json.with_content(age: (1...10)) }  # =\u003e fail\n  specify { expect({age: '1'}.to_json).to be_json.with_content(age: (1...10)) } # =\u003e fail\n\n  # Supports whatever Range supports, using #cover?\n  specify { expect({age: '1'}.to_json).to be_json.with_content(age: ('1'...'10')) } # =\u003e fail\nend\n\n# Pass when callable returns true\ncontext \"when expected is a callable\" do\n  class ExampleCallable\n    def self.call(v)\n      new.call(v)\n    end\n\n    def call(v)\n      true\n    end\n  end\n\n  specify { expect({a: \"whatever\"}.to_json).to be_json.with_content(a: proc { true }) }       # =\u003e pass\n  specify { expect({a: \"whatever\"}.to_json).to be_json.with_content(a: lambda {|_| true }) }  # =\u003e pass\n  specify { expect({a: \"whatever\"}.to_json).to be_json.with_content(a: -\u003e (_) { true }) }     # =\u003e pass\n\n  specify { expect({a: \"whatever\"}.to_json).to be_json.with_content(a: ExampleCallable) }     # =\u003e pass\n  specify { expect({a: \"whatever\"}.to_json).to be_json.with_content(a: ExampleCallable.new) } # =\u003e pass\n\n  specify { expect({a: \"whatever\"}.to_json).to be_json.with_content(a: -\u003e { true }) }         # =\u003e error\n  specify { expect({a: \"whatever\"}.to_json).to be_json.with_content(a: -\u003e (a, b) { true }) }  # =\u003e error\nend\n\n# Pass when subject's class (in Ruby form) inherits / same as expected\ncontext \"when expected is a callable\" do\n  specify { expect({a: 1}.to_json).to be_json.with_content(a: String) }   # =\u003e fail\n  specify { expect({a: 1}.to_json).to be_json.with_content(a: Integer) }  # =\u003e pass\n  specify { expect({a: 1}.to_json).to be_json.with_content(a: Numeric) }  # =\u003e pass\nend\n```\n\n\n#### Custom/Complex Expectations\n\nPassing in a `Range` like (e.g. `('a'..'c')`) is telling the example to pass\nonly when the actual value equals to any of the values represented by the Range `'a' / 'b' / 'c'`.  \n\nBut there is no way to specify other \"OR\" expectations easily (e.g. `'a' / 'c'`)\nsince `Array` is already used for data structure expectation.  \nSo the gem also provides a list of classes to represent these kinds of custom expectations to be used.  \n\n##### Setup\n\nFirst, it requires some setup.  \nYou can put the following code in any sensible place like a specific spec file or `rails_helper`.\n```ruby\nmodule Expectations\n  include RSpec::JsonMatchers::Expectations::Mixins::BuiltIn\nend\n```\n\nAlternatively, you can use `let` to define a module without name,\nto avoid creating top-namespaced constant  \n```ruby\nlet(:expectations) do\n  Module.new do\n    include RSpec::JsonMatchers::Expectations::Mixins::BuiltIn\n  end\nend\n```\n\nIf you really want to save typing `expectations::` and are not afraid of constant name conflicts,  \nYou can add the following somewhere.\nNote that you must use both `before(:each)` \u0026 `stub_const` to make this work.\nPlease tell us if you have other methods to achieve the same effect.\n```ruby\nbefore(:each) do\n  RSpec::JsonMatchers::Expectations::Mixins::BuiltIn.constants.each do |expectation_klass_name|\n    stub_const(\n      expectation_klass_name.to_s,\n      RSpec::JsonMatchers::Expectations::Mixins::BuiltIn.const_get(expectation_klass_name),\n    )\n  end\nend\n```\n\n##### Usage\n\nNow let's take a look at the actual expectation classes this gem provides:\n```ruby\n# `Anything` is an expectation that always passes\n# It has the same effect as passing `Object` in\n# Since every Ruby form of JSON data type is an `Object`\n# But this would be more verbose \u0026 clear\nspecify { expect({a: \"a\"  }.to_json).to be_json.with_content(a: expectations::Anything) }  # =\u003e pass\nspecify { expect({a: 1    }.to_json).to be_json.with_content(a: expectations::Anything) }  # =\u003e pass\nspecify { expect({a: 1.1  }.to_json).to be_json.with_content(a: expectations::Anything) }  # =\u003e pass\nspecify { expect({a: {}   }.to_json).to be_json.with_content(a: expectations::Anything) }  # =\u003e pass\nspecify { expect({a: []   }.to_json).to be_json.with_content(a: expectations::Anything) }  # =\u003e pass\nspecify { expect({a: true }.to_json).to be_json.with_content(a: expectations::Anything) }  # =\u003e pass\nspecify { expect({a: false}.to_json).to be_json.with_content(a: expectations::Anything) }  # =\u003e pass\nspecify { expect({a: nil  }.to_json).to be_json.with_content(a: expectations::Anything) }  # =\u003e pass\n\n\n# `PositiveNumber` is an expectation that passes when subject is a `Numeric` and larger than 0\nspecify { expect({a: 1    }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # =\u003e pass\nspecify { expect({a: 1.1  }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # =\u003e pass\nspecify { expect({a: 0    }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # =\u003e fail\nspecify { expect({a: 0.0  }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # =\u003e fail\nspecify { expect({a: -1   }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # =\u003e fail\nspecify { expect({a: -1.1 }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # =\u003e fail\n\n\n# `NegativeNumber` is an expectation that passes when subject is a `Numeric` and less than 0\nspecify { expect({a: 1    }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # =\u003e fail\nspecify { expect({a: 1.1  }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # =\u003e fail\nspecify { expect({a: 0    }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # =\u003e fail\nspecify { expect({a: 0.0  }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # =\u003e fail\nspecify { expect({a: -1   }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # =\u003e pass\nspecify { expect({a: -1.1 }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # =\u003e pass\n\n\n# `BooleanValue` is an expectation that passes when subject is a `TrueClass` or `FalseClass`\nspecify { expect({a: \"a\"  }.to_json).to be_json.with_content(a: expectations::BooleanValue) }  # =\u003e fail\nspecify { expect({a: 1    }.to_json).to be_json.with_content(a: expectations::BooleanValue) }  # =\u003e fail\nspecify { expect({a: 1.1  }.to_json).to be_json.with_content(a: expectations::BooleanValue) }  # =\u003e fail\nspecify { expect({a: {}   }.to_json).to be_json.with_content(a: expectations::BooleanValue) }  # =\u003e fail\nspecify { expect({a: []   }.to_json).to be_json.with_content(a: expectations::BooleanValue) }  # =\u003e fail\nspecify { expect({a: true }.to_json).to be_json.with_content(a: expectations::BooleanValue) }  # =\u003e pass\nspecify { expect({a: false}.to_json).to be_json.with_content(a: expectations::BooleanValue) }  # =\u003e pass\nspecify { expect({a: nil  }.to_json).to be_json.with_content(a: expectations::BooleanValue) }  # =\u003e fail\n\n\n# `ArrayOf` is an expectation that passes when subject is an `Array` and\n# **ALL** elements satisfy the expectation passed in\nspecify { expect({a: \"a\"  }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) }  # =\u003e fail\nspecify { expect({a: 1    }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) }  # =\u003e fail\nspecify { expect({a: 1.1  }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) }  # =\u003e fail\nspecify { expect({a: {}   }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) }  # =\u003e fail\nspecify { expect({a: []   }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) }  # =\u003e pass\nspecify { expect({a: true }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) }  # =\u003e fail\nspecify { expect({a: false}.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) }  # =\u003e fail\nspecify { expect({a: nil  }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) }  # =\u003e fail\n\n# As you see it allows empty array by default\n# Since {Enumerable#all?} returns `true` when collection is empty\n# You can make it fail using optional argument in {#allow_empty} or {#disallow_empty}\n# Notice that {#disallow_empty} has no optional argument to avoid reading as double negative\nspecify do\n  expect({a: []}.to_json).to be_json.\n    with_content(a: expectations::ArrayOf[expectations::Anything].allow_empty)\nend # =\u003e pass\nspecify do\n  expect({a: []}.to_json).to be_json.\n    with_content(a: expectations::ArrayOf[expectations::Anything].allow_empty(true))\nend # =\u003e pass\nspecify do\n  expect({a: []}.to_json).to be_json.\n    with_content(a: expectations::ArrayOf[expectations::Anything].allow_empty(false))\nend # =\u003e fail\nspecify do\n  expect({a: []}.to_json).to be_json.\n    with_content(a: expectations::ArrayOf[expectations::Anything].disallow_empty)\nend # =\u003e fail\n\n\n# `ArrayWithSize` is an expectation that passes when subject is an `Array` and\n# The size satisfies the `Fixnum`, `Bignum` or `Range` passed in\n# Passing \"expectation\" with unexpected type would simply fail the example\n# This also means using `should_not` with unexpected type of \"expectation\" always pass\nspecify do\n  expect({a: [1]}.to_json).to be_json.\n    with_content(a: expectations::ArrayWithSize[1])\nend # =\u003e pass\nspecify do\n  expect({a: [1]}.to_json).to be_json.\n    with_content(a: expectations::ArrayWithSize[0..2])\nend # =\u003e pass\nspecify do\n  expect({a: [1]}.to_json).to be_json.\n    with_content(a: expectations::ArrayWithSize[1.1])\nend # =\u003e error\n\n# You can pass more than 1 objects in as expectation\n# It will pass when ANY of them \"expects\" the size\nspecify do\n  expect({a: [1]}.to_json).to be_json.\n    with_content(a: expectations::ArrayWithSize[0, 1, 3])\nend # =\u003e pass\n\n\n# `NullableOf` is an expectation that works like `AnyOf`\n# Except it always passes when the subject is `nil`\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::NullableOf[1])\nend # =\u003e pass\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::NullableOf[0, 1, 2])\nend # =\u003e pass\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::NullableOf[false, expectations::Anything, false])\nend # =\u003e pass\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::NullableOf[false, false, false])\nend # =\u003e fail\nspecify do\n  expect({a: nil}.to_json).to be_json.\n    with_content(a: expectations::NullableOf[false, false, false])\nend # =\u003e fail\n\n\n# `AnyOf` is an expectation that passes when **any** of \"expectations\" passed in\n# \"expects\" the subject\n# It will convert non `Expectation` objects into `Expectation` objects,\n# just like using `with_content` alone\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::AnyOf[1])\nend # =\u003e pass\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::AnyOf[0, 1, 2])\nend # =\u003e pass\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::AnyOf[false, expectations::Anything, false])\nend # =\u003e pass\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::AnyOf[false, false, false])\nend # =\u003e fail\n\n\n# `AllOf` is an expectation that passes when **all** of \"expectations\" passed in\n# \"expects\" the subject\n# It will convert non `Expectation` objects into `Expectation` objects,\n# just like using `with_content` alone\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::AllOf[1])\nend # =\u003e pass\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::AllOf[1, (1..2), expectations::PositiveNumber])\nend # =\u003e pass\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::AllOf[0, 1, 2])\nend # =\u003e fail\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::AllOf[false, expectations::Anything, false])\nend # =\u003e fail\nspecify do\n  expect({a: 1}.to_json).to be_json.\n    with_content(a: expectations::AllOf[false, false, false])\nend # =\u003e fail\n```\n\nIt's possible to make examples fail when the object represented by JSON string in `subject`\ncontains more keys than that in expectation using `HashWithContent` \u0026 `#with_exact_keys`.  \n`HashWithContent` is the expectation class that is automatically used when a `Hash` is passed.\n\n\n```ruby\n# The spec can be set to fail when actual has more keys than expected\nspecify do\n  expect({a: 1, b: 2}.to_json).\n    to be_json.\n    with_content(\n      expectations::HashWithContent[{a: 1}].with_exact_keys\n    )\n  # =\u003e fail\nend\n```\n\n#### Custom/Complex Expectations NOT included on purpose\n\n##### Date\nIn [`airborne`](https://github.com/brooklynDev/airborne) you can validate the value as a \"date\" (and \"time\").  \nHowever \"date/time\" is not part of the JSON specification.  \nSome people use a string with a format specified in ISO to represent a time, but a [Unix time](https://en.wikipedia.org/wiki/Unix_time).  \nSo this gem does not try to be \"smart\" to have a \"generic\" expectation for \"date/time\".  \nNew expectations might be added in the future, to the core gem or a new extension gem, for common formats of \"date\" values.  \nThere is no clear schedule for the addition yet, so you should try to add your own expectation class to suit your application.  \n\n\n### Matcher `be_json.with_sizes`\n\nUsed to have in earlier alpha versions.\nIndended to ease the migration from other gems but \nit also makes the gem more difficult to maintain.\nRemoved in later alpha version(s).\n\nJust use `ArrayWithSize`\n\n\n```ruby\nspecify do\n  expect({a: [1]}.to_json).to be_json.\n    with_content(a: ArrayWithSize[1])\nend # =\u003e pass\nspecify do\n  expect({a: [1]}.to_json).to be_json.\n    with_content(a: ArrayWithSize[(0..2)])\nend # =\u003e pass\nspecify do\n  expect({a: [1]}.to_json).to be_json.\n    with_content(a: ArrayWithSize[1.1])\nend # =\u003e error\n```\n\n\n### Matcher `be_json.with_types`\n\nUnlike gems such as\n[`airborne`](https://github.com/brooklynDev/airborne) or\n[`json_spec`](https://github.com/collectiveidea/json_spec),\nthere is no such matcher.  \nJust use `be_json.with_content` with classes.  \n\n\n## Pitfalls\n\n### Error message colorized output in RubyMine\n\nAdd something like\n`-rawesome_print -e \"AwesomePrint.defaults={plain: true}\"` to `Ruby arguments`\nfor `Run/Debug Configurations =\u003e Defaults =\u003e RSpec`  \nThat way you could keep the color when running `rspec` from console\n\n\n## Some JSON related gems\nHere is a list of gems which I found and I have tried some of them.  \nBut eventually I am unsatisfied so I build this gem.  \n\n- [rspec-json_matcher](https://github.com/r7kamura/rspec-json_matcher)\n- [json_spec](https://github.com/collectiveidea/json_spec)\n- [json_matchers](https://github.com/thoughtbot/json_matchers)\n- [airborne](https://github.com/brooklynDev/airborne)\n- [json-schema](https://github.com/ruby-json-schema/json-schema)\n\n\n## Contributing\n\n1. Fork it ( https://github.com/PikachuEXE/rspec-json_matchers/fork )\n2. Create your branch (Preferred to be prefixed with `feature`/`fix`/other sensible prefixes)\n3. Commit your changes (No version related changes will be accepted)\n4. Push to the branch on your forked repo\n5. Create a new Pull Request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPikachuEXE%2Frspec-json_matchers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPikachuEXE%2Frspec-json_matchers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPikachuEXE%2Frspec-json_matchers/lists"}