Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Phpunit Json Assert Laravel Package

helmich/phpunit-json-assert

Adds concise JSON assertions to PHPUnit using JSONPath expressions and JSON Schema validation. Use the JsonAssertions trait to verify complex JSON/data structures with readable assert* helpers. Install via Composer and choose the branch matching your PHPUnit/PHP version.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require --dev helmich/phpunit-json-assert
    

    Add the trait to your test class:

    use Helmich\JsonAssert\JsonAssert;
    
    class MyTest extends TestCase
    {
        use JsonAssert;
    }
    
  2. First Use Case: Verify a JSON response matches expected structure:

    $actual = json_decode(file_get_contents('response.json'), true);
    $expected = ['key' => 'value', 'nested' => ['array' => true]];
    
    $this->assertJson($actual, $expected);
    
  3. Where to Look First:

    • README.md for core assertions.
    • src/JsonAssert.php for trait methods and customization hooks.
    • Tests for edge-case examples.

Implementation Patterns

Common Workflows

  1. API Response Validation:

    $response = $this->get('/api/users');
    $this->assertJson($response->json(), [
        'data' => [
            ['id' => 1, 'name' => 'John'],
            ['id' => 2, 'name' => 'Jane']
        ],
        'meta' => ['count' => 2]
    ]);
    
  2. Dynamic Assertions with Data Providers:

    public function providerTestCases()
    {
        return [
            ['valid' => true, 'expected' => ['status' => 'success']],
            ['valid' => false, 'expected' => ['status' => 'error']],
        ];
    }
    
    public function testDynamicJson($valid, $expected)
    {
        $this->assertJson($this->getJsonResponse($valid), $expected);
    }
    
  3. Partial Matching:

    $this->assertJsonPartial([
        'id' => 1,
        'name' => 'John'
    ], $actual);
    
  4. Schema-Like Validation:

    $this->assertJsonSchema([
        'type' => 'object',
        'properties' => [
            'id' => ['type' => 'integer'],
            'name' => ['type' => 'string']
        ],
        'required' => ['id', 'name']
    ], $actual);
    

Integration Tips

  • Laravel HTTP Tests: Combine with Laravel\Sanctum\Sanctum for authenticated API tests:

    $response = $this->actingAs($user)->get('/api/profile');
    $this->assertJson($response->json(), ['name' => 'Test User']);
    
  • Factories + JSON Asserts: Use factories to generate test data, then assert against expected JSON:

    $user = User::factory()->create();
    $this->assertJson($user->toArray(), [
        'id' => $user->id,
        'email_verified_at' => null
    ]);
    
  • Custom Matchers: Extend the trait for domain-specific assertions:

    trait CustomJsonAsserts
    {
        protected function assertJsonHasPaginatedStructure(array $actual)
        {
            $this->assertJson($actual, [
                'data' => $this->isArray(),
                'meta' => [
                    'current_page' => $this->isInteger(),
                    'per_page' => $this->isInteger()
                ]
            ]);
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Strict Typing:

    • JSON assertions are strict by default. Floating-point numbers (e.g., 1.0) will fail if compared to integers (1).
    • Fix: Use assertJsonLoose() for lenient comparisons or normalize data:
      $this->assertJsonLoose($actual, $expected);
      
  2. Nested Arrays/Objects:

    • Order matters for arrays. Use assertJsonArrayOrder() to ignore order:
      $this->assertJsonArrayOrder(['id', 'name'], $actual['users']);
      
  3. Null vs. Missing Keys:

    • null and missing keys are treated differently. Explicitly include null in expectations:
      $this->assertJson(['key' => null], $actual); // Passes if key exists and is null
      $this->assertJson(['key' => $this->isMissing()], $actual); // Passes if key is missing
      
  4. Circular References:

    • Deeply nested or circular JSON will cause JSON_ERROR_UTF8 or stack overflows.
    • Fix: Use json_decode($json, true, 512, JSON_THROW_ON_ERROR) or limit depth in tests.
  5. Laravel Collections:

    • Collections are not JSON-serializable by default. Convert to array first:
      $this->assertJson($user->toArray(), ['name' => 'Test']);
      

Debugging Tips

  1. Diff Output: Enable detailed diffs for failed assertions:

    $this->assertJson($actual, $expected, 'Custom error message', true); // $showDiff = true
    
  2. Pretty-Print JSON: Use json_encode($actual, JSON_PRETTY_PRINT) to inspect complex structures.

  3. Custom Assertion Messages:

    $this->assertJson(
        $actual,
        $expected,
        'Response must include `data` key with user details'
    );
    

Extension Points

  1. Custom Assertion Methods: Add methods to the trait for reusable logic:

    protected function assertJsonHasRequiredFields(array $fields, array $actual)
    {
        foreach ($fields as $field) {
            $this->assertArrayHasKey($field, $actual, "Missing required field: {$field}");
        }
    }
    
  2. Override Default Behavior: Extend the trait and override methods like assertJson():

    trait ExtendedJsonAsserts
    {
        use JsonAssert;
    
        protected function assertJson(array $actual, array $expected, string $message = '', bool $showDiff = false)
        {
            // Custom logic (e.g., trim whitespace from strings)
            $actual = array_map(function ($value) {
                return is_string($value) ? trim($value) : $value;
            }, $actual);
            parent::assertJson($actual, $expected, $message, $showDiff);
        }
    }
    
  3. Integration with Laravel Exceptions: Throw custom exceptions for JSON validation failures:

    try {
        $this->assertJson($response->json(), $expected);
    } catch (JsonAssertionFailedError $e) {
        throw new \RuntimeException("API validation failed: " . $e->getMessage(), 0, $e);
    }
    
  4. Performance:

    • For large JSON payloads, cache decoded responses:
      private $cachedJson;
      
      protected function getJsonResponse(): array
      {
          return $this->cachedJson ??= json_decode($this->get('/api/large-data'), true);
      }
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport