Skip to content

Commit

Permalink
feat: Driver with JSONPath support
Browse files Browse the repository at this point in the history
  • Loading branch information
chr-hertel committed Apr 2, 2024
1 parent 4f37808 commit 39ac954
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 1 deletion.
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@
"symfony/yaml": "^5.2|^6.2|^7.0"
},
"require-dev": {
"softcreatr/jsonpath": "^0.9.0",
"spatie/pixelmatch-php": "dev-main",
"spatie/ray": "^1.37"
},
"suggest": {
"spatie/pixelmatch-php": "Required to use the image snapshot assertions"
"spatie/pixelmatch-php": "Required to use the image snapshot assertions",
"softcreatr/jsonpath": "Required to use the JSONPath assertions"
},
"autoload": {
"psr-4": {
Expand Down
40 changes: 40 additions & 0 deletions src/Drivers/JsonPathDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Spatie\Snapshots\Drivers;

use Exception;
use Flow\JSONPath\JSONPath;
use PHPUnit\Framework\Assert;

class JsonPathDriver extends JsonDriver
{
public function __construct(private array $placeholders = [])
{
}

public function match($expected, $actual): void
{
if (! class_exists(JSONPath::class)) {
throw new Exception('The softcreatr/jsonpath package is not installed. Please install it to enable JSONPath driver.');
}

if (is_string($actual)) {
$actual = json_decode($actual, false, 512, JSON_THROW_ON_ERROR);
}

$expected = json_decode($expected, false, 512, JSON_THROW_ON_ERROR);

$jpActual = new JSONPath($actual);
$jpExpected = new JSONPath($expected);
foreach ($this->placeholders as $path => $pattern) {
$expectedData = $jpExpected->find($path)->getData();
$actualData = $jpActual->find($path)->getData();
foreach ($actualData as $i => $data) {
Assert::assertMatchesRegularExpression($pattern, $data, 'Failed asserting that JSON path "'.$path.'" matches pattern "'.$pattern.'".');
$jpActual->offsetSet(str_replace('$.', '', $path), $expectedData[$i]);
}
}

Assert::assertJsonStringEqualsJsonString(json_encode($expected), json_encode($jpActual));
}
}
6 changes: 6 additions & 0 deletions src/MatchesSnapshots.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Spatie\Snapshots\Drivers\HtmlDriver;
use Spatie\Snapshots\Drivers\ImageDriver;
use Spatie\Snapshots\Drivers\JsonDriver;
use Spatie\Snapshots\Drivers\JsonPathDriver;
use Spatie\Snapshots\Drivers\ObjectDriver;
use Spatie\Snapshots\Drivers\TextDriver;
use Spatie\Snapshots\Drivers\XmlDriver;
Expand Down Expand Up @@ -94,6 +95,11 @@ public function assertMatchesJsonSnapshot(array|string|null|int|float|bool $actu
$this->assertMatchesSnapshot($actual, new JsonDriver());
}

public function assertMatchesJsonPathSnapshot(array|string|null|int|float|bool $actual, array $placeholders): void
{
$this->assertMatchesSnapshot($actual, new JsonPathDriver($placeholders));
}

public function assertMatchesObjectSnapshot($actual): void
{
$this->assertMatchesSnapshot($actual, new ObjectDriver());
Expand Down
46 changes: 46 additions & 0 deletions tests/Unit/Drivers/JsonPathDriverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace Spatie\Snapshots\Test\Unit\Drivers;

use Generator;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\TestCase;
use Spatie\Snapshots\Drivers\JsonPathDriver;

class JsonPathDriverTest extends TestCase
{
#[Test]
#[DataProvider('provideJsonData')]
public function it_can_replace_placeholders_in_json(string $pathExpected, string $pathActual, array $replacements): void
{
$expected = file_get_contents($pathExpected);
$actual = file_get_contents($pathActual);
$driver = new JsonPathDriver($replacements);

try {
$driver->match($expected, $actual);
$status = true;
} catch (ExpectationFailedException) {
$status = false;
}

$this->assertTrue($status);
}

public static function provideJsonData(): Generator
{
yield 'simple' => [
dirname(__DIR__).'/test_files/json_path_simpleA.json',
dirname(__DIR__).'/test_files/json_path_simpleB.json',
[
'$.id' => '@\d+@',
'$.cover' => '@https://bucket.foo/bar/\d+.[webp|jpg]@',
'$.createdAt' => '@\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[\+\-]\d{2}:\d{2}@',
]
];
}
}
10 changes: 10 additions & 0 deletions tests/Unit/test_files/json_path_simpleA.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": 123456,
"title": "Some Title",
"author": "Jane Doe",
"ISBN": "978-0-545-01022-1",
"cover": "https://bucket.foo/bar/123456.webp",
"published": 2017,
"createdAt": "2024-03-08T17:37:09+00:00",
"more": "values"
}
10 changes: 10 additions & 0 deletions tests/Unit/test_files/json_path_simpleB.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": 987654,
"title": "Some Title",
"author": "Jane Doe",
"ISBN": "978-0-545-01022-1",
"cover": "https://bucket.foo/bar/987654.webp",
"published": 2017,
"createdAt": "2024-04-02T22:33:44+55:11",
"more": "values"
}

0 comments on commit 39ac954

Please sign in to comment.