PHPackages                             fesor/json\_matcher - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. fesor/json\_matcher

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

fesor/json\_matcher
===================

Collection of JSON matchers for painless usage

0.2.3(10y ago)25119.9k↓25%2[3 issues](https://github.com/fesor/json_matcher/issues)2MITPHPPHP &gt;=5.4.0CI failing

Since Jan 2Pushed 6y ago4 watchersCompare

[ Source](https://github.com/fesor/json_matcher)[ Packagist](https://packagist.org/packages/fesor/json_matcher)[ RSS](/packages/fesor-json-matcher/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (3)Versions (9)Used By (2)

Json Matcher
============

[](#json-matcher)

[![Build Status](https://camo.githubusercontent.com/b662ce20cc5ca68e0c178f00ca88fd8c175570578c80acb3a54d5d7fc298e582/68747470733a2f2f7472617669732d63692e6f72672f6665736f722f6a736f6e5f6d6174636865722e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/fesor/json_matcher)[![Latest Stable Version](https://camo.githubusercontent.com/072eb9ad5df83efdd897cf1341f27b904aca00457f8faf79397f622353bf9ba5/68747470733a2f2f706f7365722e707567782e6f72672f6665736f722f6a736f6e5f6d6174636865722f762f737461626c652e737667)](https://packagist.org/packages/fesor/json_matcher)[![Latest Unstable Version](https://camo.githubusercontent.com/26f0ef054cfb028252fa61b2469c7d789b065c945c1487fcab27a0c731b88351/68747470733a2f2f706f7365722e707567782e6f72672f6665736f722f6a736f6e5f6d6174636865722f762f756e737461626c652e737667)](https://packagist.org/packages/fesor/json_matcher)[![License](https://camo.githubusercontent.com/9f92f72467f48b69c311aee4038ee6e04fd7180597c0f3b064c572a3c28221f9/68747470733a2f2f706f7365722e707567782e6f72672f6665736f722f6a736f6e5f6d6174636865722f6c6963656e73652e737667)](https://packagist.org/packages/fesor/json_matcher)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/68f6aa5c01309315b1b28482e9341472dab201665f955f69105cfde56ffd92b9/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6665736f722f6a736f6e5f6d6174636865722f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/fesor/json_matcher/?branch=master)[![Total Downloads](https://camo.githubusercontent.com/a2227be1d95a157347f8de7bc33e5bd875075ed2f8908a25f6f9b0057023ac54/68747470733a2f2f706f7365722e707567782e6f72672f6665736f722f6a736f6e5f6d6174636865722f646f776e6c6f6164732e737667)](https://packagist.org/packages/fesor/json_matcher)

Assertion library for simplifying JSON data and structure verification in your tests. It's framework-agnostic, so you can use it with PhpUnit, PhpSpec, Peridot or whatever framework you use.

Why another JSON assertion library?
-----------------------------------

[](#why-another-json-assertion-library)

If you tried to test your JSON based REST APIs, then you probably faced a several issues:

- You can't simply check is a response is equal to given string as there are things like server-generated IDs and timestamps.
- Key ordering should be the same both for your API and for expected JSON.
- Matching the whole responses breaks DRY for the tests

All these issues can be solved with two simple things: JSON normalization and key exclusion on matching. This is what this library does. It provides you a way to verify data in given JSON in multiple steps instead of one big assertion.

For example we are developing an friend list feature for our API for. What we want to check is only is given user presents in response, we don't want to check whole response, it could be done via json schema validation or on another test cases.

```
$alice = new User('Alice', 'Miller');
$john = new User('John', 'Smith');
$alice->addFriend($john);

$json = JsonMatcher::create(
    json_encode($alice->toArrayIncludingFriends()), ['id', 'created_at']
);
```

In above example we just created an `JsonMatcher` instance and specified excluded-by-default keys (`id` and `created_at`). Excluded keys will be removed from JSON and it's values will not interfere in equality assertion. You can also override this list of keys via matching `excluding` and `including` options.

Then we can check is John presents in Alice's friend list at some specific position via json paths:

```
$json->equal(json_encode($john->toArray()), ['at' => 'friends/0']);
```

Or if we don't know specific position, we can just check is John just presents in our friendlist.

```
$json->includes(json_encode($john->toArray()), ['at' => 'friends']);
```

Or we can just verify is any John presents in Alice's friend list:

```
$json->includes('{"first_name": "John"}'), ['at' => 'friends']);
```

Getting started
---------------

[](#getting-started)

You can install this library via composer:

```
composer require fesor/json_matcher

```

Then you will need an `JsonMatcher` instance to be created. To do this, you can:

- manually create instance with all dependencies and set subject
- use named constructor `JsonMatcher::create` as static factory-method. It will handle all dependencies for you.
- use JsonMatcherFactory. This is useful when you have some IoC container in your test framework (Behat for example). In this case you'll need to register this class as a service.

Subject on which assertion will be preformed is setted up in matcher consturctor. If you want to reuse the same instance of matcher for every assertions, you can just change subject via `setSubject` method.

Example:

```
$jsonResponse = JsonMatcher::create($response->getContent());

// or you can use factory instead
$jsonResponse = $matcherFactory->create($response->getContent());

// and there you go, for example you may use something like this
// for your gherkin steps implementations
$jsonResponse
    ->hasSize(1, ['at' => 'friends']) // checks that list of friends was incremented
    ->includes($friend, ['at' => 'friends']) // checks that correct record contained in collection
;
```

You can provide list of excluded-by-default keys as second argument in constructors:

```
$matcher = JsonMatcher::create($subject, ['id', 'created_at']);
```

Please note, that `id` key will be ignored by default.

Matchers
--------

[](#matchers)

All matchers are supports fluent interface, negative matching and some options. See detailed description for more information about what options each matcher has.

### equal

[](#equal)

This is most commonly used matcher. You take two json strings and compare them. Except that before compassion this matcher will normalize structure of both JSON strings, reorder keys, exclude some of them (this is configurable) and then will simply assert that both strings are equal. You can specify list of excluded keys with `excluding` options:

```
$actualJson = '["id": 1, "json": "spec"]';
$expectedJson = '["json": "spec"]';
$matcher
    ->setSubject($actualJson)
    ->equal($expectedJson, ['excluding' => ['id']])
;
```

If you have some keys, which contains some time dependent value of some server-generated IDs it is more convenient to specify list of excluded-by-default keys when you construct matcher object:

```
$matcher = JsonMatcher::create($subject, ['id', 'created_at', 'updated_at']);
```

If you want the values for these keys to be taken into account during the matching, you can specify list of included keys with `including` options

```
$matcher = JsonMatcher::create($response->getContent(), ['id', 'created_at', 'updated_at']);
$jsonResponseSubject->equal($expectedJson, ['including' => ['id']]);
```

Also you can specify json path on which matching should be done via `at` options. We will back to this later since all matchers supports this option.

### includes

[](#includes)

This matcher works a little different from `equal` matcher. What it does is recursively scan subject JSON and tries to find any inclusions of JSON subset. This is useful for cases when you checking that some record exists in collection and you do not know or don't want to know specific path to it.

```
$json = includes('{"name": "Bar"}', ['at' => 'collection'])
    // checks is json presents in collection
    ->includes('{"name": "Bar", "value": "FooBar"}', ['at' => 'collection'])
;
```

Since this matcher works the same way as `equal` matcher, it accepts same options.

### hasPath

[](#haspath)

This matcher checks if given JSON have specific path ot not.

```
$json =  'collection'])
;
```

### hasType

[](#hastype)

```
$json =  'collection'])
    ->hasType('object', ['at' => 'collection/0'])
    ->hasType('string', ['at' => 'collection/1'])
    ->hasType('integer', ['at' => 'collection/2'])
    ->hasType('float', ['at' => 'collection/3'])
;
```

### Negative matching

[](#negative-matching)

To invert expectations just call matcher methods with `not` prefix:

```
$matcher
    ->setSubject($json)
    ->notEqual($expected)
    ->notIncludes($part)
;
```

### Json Path

[](#json-path)

Also all methods have option, which specifies path which should be performed matching. For example:

```
$actual = equal($expected, ['at' => 'collection/0'])
;
```

Contribution
------------

[](#contribution)

Please welcome to contribute!

###  Health Score

34

—

LowBetter than 77% of packages

Maintenance18

Infrequent updates — may be unmaintained

Popularity39

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~73 days

Total

5

Last Release

3861d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/736e9d33560d4c01cd2b9dfb70bbcbd8219d4b61967f98ffa09d35101ceeaac8?d=identicon)[fesor](/maintainers/fesor)

---

Top Contributors

[![fesor](https://avatars.githubusercontent.com/u/172247?v=4)](https://github.com/fesor "fesor (44 commits)")

---

Tags

assertion-libraryassertionsjsonjson-matcherjson-schemajsonpath

### Embed Badge

![Health badge](/badges/fesor-json-matcher/health.svg)

```
[![Health](https://phpackages.com/badges/fesor-json-matcher/health.svg)](https://phpackages.com/packages/fesor-json-matcher)
```

###  Alternatives

[kenjis/ci3-to-4-upgrade-helper

Help upgrade from CodeIgniter3 to CodeIgniter4

695.9k](/packages/kenjis-ci3-to-4-upgrade-helper)[anerg2046/helper

some helper libaray function

2313.9k2](/packages/anerg2046-helper)[shrink0r/monatic

Fiddling with the monad concept in php

245.3k2](/packages/shrink0r-monatic)[purplespider/mypswd-tweaks

Custom SilverStripe tweaks to keep things tidy.

181.4k](/packages/purplespider-mypswd-tweaks)[innmind/git

Git abstraction

141.4k1](/packages/innmind-git)[dvizh/yii2-field

yii2-field add fields to your model

111.7k](/packages/dvizh-yii2-field)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
