PHPackages                             duxet/json\_spec - 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. [Testing &amp; Quality](/categories/testing)
4. /
5. duxet/json\_spec

ActiveLibrary[Testing &amp; Quality](/categories/testing)

duxet/json\_spec
================

Easily handle JSON Structures with PhpSpec and Behat

1.3.0(3y ago)248.1k↓17.2%2MITPHPPHP &gt;=5.4.0

Since Aug 14Pushed 3y ago1 watchersCompare

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

READMEChangelog (5)Dependencies (4)Versions (13)Used By (0)

Json Spec
=========

[](#json-spec)

[![Scrutinizer Code Quality](https://camo.githubusercontent.com/b2ff60574cccf8fd03b05fd8045683a832aa6ef4d06b3f4218e32c8a6b54a1c8/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6665736f722f6a736f6e5f737065632f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/fesor/json_spec/?branch=master) [![Build Status](https://camo.githubusercontent.com/2364244adce15141ce66db4db5ca0226fbf9121060b706515f087baf4819f39a/68747470733a2f2f7472617669732d63692e6f72672f6665736f722f6a736f6e5f737065632e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/fesor/json_spec)

Json Spec provides set of easy-to-use matcher that should help you to validate data in JSON responses from your api with less pain.

If you working with JSON-based REST APIs there are several issues:

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

`json_spec` solves this problems as it normalize JSON before match it.

Let's see simple example:

  ```

{
   "id": 1421,
   "created_at": "1977-05-25 00:00:00"
   "last_name": "Skywalker",
   "first_name": "Luke",
}

```

  ```

{
   "first_name": "Luke",
   "last_name": "Skywalker"
}

```

  `json_spec` will assume that this JSON documents are equal. Before asserting, `json_spec` will exclude keys `id`, `created_at` and `updated_at` from response JSON (List of excluded keys is configurable). Then it will normalize JSON (reorder keys, pretty-print) and after, just check for string equality. That's all. Also you can match JSON by given path instead of describing whole response in your specification, check is JSON collection contains some record and many more.

Installation
------------

[](#installation)

To install `json_spec` you may want to use composer:

```
composer require --dev fesor/json_spec

```

After that you should enable `json_spec` behat extension and optionally add context provided with json\_spec in your `behat.yml`. For example:

```
default:
    suites:
        default:
            contexts:
                - FeatureContext
                - json_spec
    extensions:
        JsonSpec\Behat\Extension: ~

```

Usage
-----

[](#usage)

json\_spec provides you two ways of how you can use matchers:

- Using json\_spec context, which implements steps for verifying json responses. This approach best fits for cases, when developers uses feature specs as API documentation and tests.
- Inject `JsonMatcherFactory` into your context, so you can use it in your step definitions. This approach preferable since you can practice BDD with it. For more information about how to write feature specs please read [Modeling by examples](http://everzet.com/post/99045129766/introducing-modelling-by-example).

### Using `json_spec` Context

[](#using-json_spec-context)

json\_spec provides Behat context which implements steps utilizing all matchers provided by `json_matcher`. This is perfect for testing your app's JSON API.

One note. `json_spec` should have access to responses. If you are using Mink, that it's just fine. `json_spec` will get responses from Mink. This means that all you need to do to start working, is just to enable MinkExtension in your `behat.yml`:

```
default:
    suites:
        default:
            contexts:
                - FeatureContext
                - json_spec
    extensions:
        JsonSpec\Behat\Extension: ~
        Behat\MinkExtension:
            base_url:  'http://localhost:8047'
            sessions:
                default:
                    goutte: ~

```

That's all, now `json_spec` have access to all responses. You may also want to use `behatch:rest` context from [sanpii/behatch-contexts](https://github.com/sanpii/behatch-contexts) instead of mink context.

If you are using your own context, which not using Mink, then just implement `JsonHolderAware` interface for your context:

```
use \JsonSpec\Behat\Context\JsonHolderAware;
use \Behat\Behat\Context\Context;

class MyRestApiFeatureContext implements Context, JsonHolderAware
{
    /**
     * @var \JsonSpec\Behat\JsonProvider\JsonHolder
     */
    private $jsonHolder;

    /**
     * @When /^I request "([^"]*)"$/
     */
    public function iRequest($pageUrl)
    {
        // ... make request and get response body as string
        $this->jsonHolder->setJson($responseBody);
    }
}
```

Now, you can use the json\_spec steps in your features:

```
Feature: User API
  Background:
    Given the following users exist:
      | id | first_name | last_name |
      | 1  | Steve      | Richert   |
      | 2  | Catie      | Richert   |
    And "Steve Richert" is friends with "Catie Richert"

  Scenario: Index action
    When I visit "/users.json"
    Then the JSON response should have 2 users
    And the JSON response at "0/id" should be 1
    And the JSON response at "1/id" should be 2

  Scenario: Show action
    When I visit "/users/1.json"
    Then the JSON response at "first_name" should be "Steve"
    And the JSON response at "last_name" should be "Richert"
    And the JSON response should have "created_at"
    And the JSON response at "created_at" should be a string
    And the JSON response at "friends" should be:
      """
      [
        {
          "id": 2,
          "first_name": "Catie",
          "last_name": "Richert"
        }
      ]
      """

```

The background steps above and the "visit" steps aren't provided by json\_spec. The remaining steps, json\_spec provides. They're versatile and can be used in plenty of different formats:

```
Then the JSON should be:
  """
  {
    "key": "value"
  }
  """
Then the JSON at "path" should be:
  """
  [
    "entry",
    "entry"
  ]
  """

Then the JSON should be {"key":"value"}
Then the JSON at "path" should be {"key":"value"}
Then the JSON should be ["entry","entry"]
Then the JSON at "path" should be ["entry","entry"]
Then the JSON at "path" should be "string"
Then the JSON at "path" should be 10
Then the JSON at "path" should be 10.0
Then the JSON at "path" should be 1e+1
Then the JSON at "path" should be true
Then the JSON at "path" should be false
Then the JSON at "path" should be null

Then the JSON should include:
  """
  {
    "key": "value"
  }
  """
Then the JSON at "path" should include:
  """
  [
    "entry",
    "entry"
  ]
  """

Then the JSON should include {"key":"value"}
Then the JSON at "path" should include {"key":"value"}
Then the JSON should include ["entry","entry"]
Then the JSON at "path" should include ["entry","entry"]
Then the JSON should include "string"
Then the JSON at "path" should include "string"
Then the JSON should include 10
Then the JSON at "path" should include 10
Then the JSON should include 10.0
Then the JSON at "path" should include 10.0
Then the JSON should include 1e+1
Then the JSON at "path" should include 1e+1
Then the JSON should include true
Then the JSON at "path" should include true
Then the JSON should include false
Then the JSON at "path" should include false
Then the JSON should include null
Then the JSON at "path" should include null

Then the JSON should have "path"

Then the JSON should be a hash
Then the JSON at "path" should be an array
Then the JSON at "path" should be a float

Then the JSON should have 1 entry
Then the JSON at "path" should have 2 entries
Then the JSON should have 3 keys
Then the JSON should have 4 whatevers

```

All instances of "should" above could be followed by "not" and all instances of "JSON" could be downcased and/or followed by "response."

### Table Format

[](#table-format)

Another step exists that uses Behat's table formatting and wraps two of the above steps:

Then the JSON should have the following:

```
  | path/0 | {"key":"value"}   |
  | path/1 | ["entry","entry"] |

```

Any number of rows can be given. The step above is equivalent to:

```
Then the JSON at "path/0" should be {"key":"value"}
And the JSON at "path/1" should be ["entry","entry"]

```

If only one column is given:

```
Then the JSON should have the following:
  | path/0 |
  | path/1 |

```

This is equivalent to:

```
Then the JSON should have "path/0"
And the JSON should have "path/1"

```

### JSON Memory

[](#json-memory)

There's one more Behat step that json\_spec provides which hasn't been used above. It's used to memorize JSON for reuse in later steps. You can "keep" all or a portion of the JSON by giving a name by which to remember it.

```
Feature: User API
  Scenario: Index action includes full user JSON
    Given the following user exists:
      | id | first_name | last_name |
      | 1  | Steve      | Richert   |
    And I visit "/users/1.json"
    And I keep the JSON response as "USER_1"
    When I visit "/users.json"
    Then the JSON response should be:
      """
      [
        {$USER_1}
      ]
      """

```

You can memorize JSON at a path:

```
Given I keep the JSON response at "first_name" as "FIRST_NAME"

```

You can remember JSON at a path:

```
Then the JSON response at "0/first_name" should be:
  """
  {$FIRST_NAME}
  """

```

You can also remember JSON inline:

```
Then the JSON response at "0/first_name" should be {$FIRST_NAME}

```

Also starting from version `0.2.3` you can inject memory helper into your feature context to define some variables. To do so, your context should implement `MemoryHelperAware` interface.

#### More Examples

[](#more-examples)

Check out the [features](https://github.com/fesor/json_spec/blob/master/features) to see all the various ways you can use json\_spec.

### Using json matcher in your step definitions

[](#using-json-matcher-in-your-step-definitions)

To inject JsonMatcherFactory you can just implement `JsonMatcherAware` interface in your context, or just use `JsonMatcherAwareTrait`:

```
Scenario: User should be able to add another user in friend list
    Given I signed in as Bob
      And I view Alice's profile
    When I add her to my friends list
    Then Alice should appear in my friend list
```

```
use JsonMatcherAwareTrait;

/**
 * @Then :user should appear in my friend list
 */
function userShouldAppearInFriendList(User $user)
{
    $this
       ->json($this->lastResponse)
       ->haveSize(1)
       ->includes($this->serialize($user, ['short_profile'])
    ;
}
```

Contributing
------------

[](#contributing)

If you come across any issues, please [tell me](https://github.com/fesor/json_spec/issues) . Pull requests (with tests) are appreciated. No pull request is too small. Please help with:

- Reporting bugs
- Suggesting features
- Writing or improving documentation
- Fixing typos
- Cleaning whitespace
- Refactoring code
- Adding tests
- Closing [issues](https://github.com/fesor/json_spec/issues)

If you report a bug and don't include a fix, please include a failing test.

Credits
-------

[](#credits)

- [json\_spec](https://github.com/collectiveidea/json_spec) - Ruby's gem for handling JSON in RSpec and Cucumber. This library is mainly just php port of this great library.

###  Health Score

36

—

LowBetter than 82% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity32

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 78.1% 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 ~266 days

Recently: every ~563 days

Total

12

Last Release

1365d ago

Major Versions

v0.2.3 → v1.0.02015-07-05

### Community

Maintainers

![](https://www.gravatar.com/avatar/942ef68ae7066a013c4876a6066635315c5cf91b2db8b7360d000fa63178dc87?d=identicon)[duxet](/maintainers/duxet)

---

Top Contributors

[![fesor](https://avatars.githubusercontent.com/u/172247?v=4)](https://github.com/fesor "fesor (25 commits)")[![duxet](https://avatars.githubusercontent.com/u/821707?v=4)](https://github.com/duxet "duxet (6 commits)")[![itcreator](https://avatars.githubusercontent.com/u/928509?v=4)](https://github.com/itcreator "itcreator (1 commits)")

###  Code Quality

TestsBehat

### Embed Badge

![Health badge](/badges/duxet-json-spec/health.svg)

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

###  Alternatives

[phpspec/prophecy

Highly opinionated mocking framework for PHP 5.3+

8.5k551.7M682](/packages/phpspec-prophecy)[brianium/paratest

Parallel testing for PHP

2.5k118.8M754](/packages/brianium-paratest)[beberlei/assert

Thin assertion library for input validation in business models.

2.4k96.9M570](/packages/beberlei-assert)[mikey179/vfsstream

Virtual file system to mock the real file system in unit tests.

1.4k108.0M2.7k](/packages/mikey179-vfsstream)[orchestra/testbench

Laravel Testing Helper for Packages Development

2.2k39.1M32.1k](/packages/orchestra-testbench)[phpspec/phpspec

Specification-oriented BDD framework for PHP 7.1+

1.9k36.7M3.1k](/packages/phpspec-phpspec)

PHPackages © 2026

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