Skip to content

Commit 422893b

Browse files
committed
feature #60105 [JsonPath] Add JsonPathAssertionsTrait and related constraints (alexandre-daubois)
This PR was merged into the 7.3 branch. Discussion ---------- [JsonPath] Add `JsonPathAssertionsTrait` and related constraints | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | - | License | MIT Let's leverage JsonPath in test cases. I propose to add a new trait to ease testing JSON strings against JsonPath: ```php use PHPUnit\Framework\TestCase; use Symfony\Component\JsonPath\Test\JsonPathAssertionsTrait; class MyApiTest extends TestCase { use JsonPathAssertionsTrait; public function testItFetchesAllUsers(): void { $json = self::fetchUserCollection(); $this->assertJsonPathCount(3, '$.users[*]', $json); $this->assertJsonPathSame(['Melchior'], '$.users[0].username', $json); $this->assertJsonPathEquals(['30'], '$.users[0].age', $json, 'should return the age as string or int'); } public function testItFetchesOneUser(): void { $json = self::fetchOneUser(); $this->assertJsonPathSame(['Melchior'], '$.user.username', $json); $this->assertJsonPathEquals(['30'], '$.user.age', $json, 'should return the age as string or int'); } /** * Hard-coded for the example, but in a real integration test, you would actually make the API call! */ private static function fetchUserCollection(): string { // Simulate fetching JSON data from an API return <<<JSON { "users": [ { "username": "Melchior", "age": 30 }, { "username": "Gaspard", "age": 50 }, { "username": "Balthazar", "age": 55 } ] } JSON; } private static function fetchOneUser(): string { // Simulate fetching JSON data from an API return <<<JSON { "user": { "username": "Melchior", "age": 30 } } JSON; } } ``` Commits ------- 60cba45 [JsonPath] Add `JsonPathAssertionsTrait` and related constraints
2 parents c11519a + 60cba45 commit 422893b

File tree

9 files changed

+557
-0
lines changed

9 files changed

+557
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\JsonPath\Test;
13+
14+
use PHPUnit\Framework\Assert;
15+
use PHPUnit\Framework\ExpectationFailedException;
16+
use Symfony\Component\JsonPath\JsonPath;
17+
18+
/**
19+
* @author Alexandre Daubois <alex.daubois@gmail.com>
20+
*
21+
* @experimental
22+
*/
23+
trait JsonPathAssertionsTrait
24+
{
25+
/**
26+
* @throws ExpectationFailedException
27+
*/
28+
final public static function assertJsonPathEquals(mixed $expectedValue, JsonPath|string $jsonPath, string $json, string $message = ''): void
29+
{
30+
Assert::assertThat($expectedValue, new JsonPathEquals($jsonPath, $json), $message);
31+
}
32+
33+
/**
34+
* @throws ExpectationFailedException
35+
*/
36+
final public static function assertJsonPathNotEquals(mixed $expectedValue, JsonPath|string $jsonPath, string $json, string $message = ''): void
37+
{
38+
Assert::assertThat($expectedValue, new JsonPathNotEquals($jsonPath, $json), $message);
39+
}
40+
41+
/**
42+
* @throws ExpectationFailedException
43+
*/
44+
final public static function assertJsonPathCount(int $expectedCount, JsonPath|string $jsonPath, string $json, string $message = ''): void
45+
{
46+
Assert::assertThat($expectedCount, new JsonPathCount($jsonPath, $json), $message);
47+
}
48+
49+
/**
50+
* @throws ExpectationFailedException
51+
*/
52+
final public static function assertJsonPathSame(mixed $expectedValue, JsonPath|string $jsonPath, string $json, string $message = ''): void
53+
{
54+
Assert::assertThat($expectedValue, new JsonPathSame($jsonPath, $json), $message);
55+
}
56+
57+
/**
58+
* @throws ExpectationFailedException
59+
*/
60+
final public static function assertJsonPathNotSame(mixed $expectedValue, JsonPath|string $jsonPath, string $json, string $message = ''): void
61+
{
62+
Assert::assertThat($expectedValue, new JsonPathNotSame($jsonPath, $json), $message);
63+
}
64+
65+
/**
66+
* @throws ExpectationFailedException
67+
*/
68+
final public static function assertJsonPathContains(mixed $expectedValue, JsonPath|string $jsonPath, string $json, bool $strict = true, string $message = ''): void
69+
{
70+
Assert::assertThat($expectedValue, new JsonPathContains($jsonPath, $json, $strict), $message);
71+
}
72+
73+
/**
74+
* @throws ExpectationFailedException
75+
*/
76+
final public static function assertJsonPathNotContains(mixed $expectedValue, JsonPath|string $jsonPath, string $json, bool $strict = true, string $message = ''): void
77+
{
78+
Assert::assertThat($expectedValue, new JsonPathNotContains($jsonPath, $json, $strict), $message);
79+
}
80+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\JsonPath\Test;
13+
14+
use PHPUnit\Framework\Constraint\Constraint;
15+
use Symfony\Component\JsonPath\JsonCrawler;
16+
use Symfony\Component\JsonPath\JsonPath;
17+
18+
/**
19+
* @author Alexandre Daubois <alex.daubois@gmail.com>
20+
*
21+
* @experimental
22+
*/
23+
class JsonPathContains extends Constraint
24+
{
25+
public function __construct(
26+
private JsonPath|string $jsonPath,
27+
private string $json,
28+
private bool $strict = true,
29+
) {
30+
}
31+
32+
public function toString(): string
33+
{
34+
return \sprintf('is found in elements at JSON path "%s"', $this->jsonPath);
35+
}
36+
37+
protected function matches(mixed $other): bool
38+
{
39+
$result = (new JsonCrawler($this->json))->find($this->jsonPath);
40+
41+
return \in_array($other, $result, $this->strict);
42+
}
43+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\JsonPath\Test;
13+
14+
use PHPUnit\Framework\Constraint\Constraint;
15+
use Symfony\Component\JsonPath\JsonCrawler;
16+
use Symfony\Component\JsonPath\JsonPath;
17+
18+
/**
19+
* @author Alexandre Daubois <alex.daubois@gmail.com>
20+
*
21+
* @experimental
22+
*/
23+
class JsonPathCount extends Constraint
24+
{
25+
public function __construct(
26+
private JsonPath|string $jsonPath,
27+
private string $json,
28+
) {
29+
}
30+
31+
public function toString(): string
32+
{
33+
return \sprintf('matches expected count of JSON path "%s"', $this->jsonPath);
34+
}
35+
36+
protected function matches(mixed $other): bool
37+
{
38+
return $other === \count((new JsonCrawler($this->json))->find($this->jsonPath));
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\JsonPath\Test;
13+
14+
use PHPUnit\Framework\Constraint\Constraint;
15+
use Symfony\Component\JsonPath\JsonCrawler;
16+
use Symfony\Component\JsonPath\JsonPath;
17+
18+
/**
19+
* @author Alexandre Daubois <alex.daubois@gmail.com>
20+
*
21+
* @experimental
22+
*/
23+
class JsonPathEquals extends Constraint
24+
{
25+
public function __construct(
26+
private JsonPath|string $jsonPath,
27+
private string $json,
28+
) {
29+
}
30+
31+
public function toString(): string
32+
{
33+
return \sprintf('equals JSON path "%s" result', $this->jsonPath);
34+
}
35+
36+
protected function matches(mixed $other): bool
37+
{
38+
return (new JsonCrawler($this->json))->find($this->jsonPath) == $other;
39+
}
40+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\JsonPath\Test;
13+
14+
use PHPUnit\Framework\Constraint\Constraint;
15+
use Symfony\Component\JsonPath\JsonCrawler;
16+
use Symfony\Component\JsonPath\JsonPath;
17+
18+
/**
19+
* @author Alexandre Daubois <alex.daubois@gmail.com>
20+
*
21+
* @experimental
22+
*/
23+
class JsonPathNotContains extends Constraint
24+
{
25+
public function __construct(
26+
private JsonPath|string $jsonPath,
27+
private string $json,
28+
private bool $strict = true,
29+
) {
30+
}
31+
32+
public function toString(): string
33+
{
34+
return \sprintf('is not found in elements at JSON path "%s"', $this->jsonPath);
35+
}
36+
37+
protected function matches(mixed $other): bool
38+
{
39+
$result = (new JsonCrawler($this->json))->find($this->jsonPath);
40+
41+
return !\in_array($other, $result, $this->strict);
42+
}
43+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\JsonPath\Test;
13+
14+
use PHPUnit\Framework\Constraint\Constraint;
15+
use Symfony\Component\JsonPath\JsonCrawler;
16+
use Symfony\Component\JsonPath\JsonPath;
17+
18+
/**
19+
* @author Alexandre Daubois <alex.daubois@gmail.com>
20+
*
21+
* @experimental
22+
*/
23+
class JsonPathNotEquals extends Constraint
24+
{
25+
public function __construct(
26+
private JsonPath|string $jsonPath,
27+
private string $json,
28+
) {
29+
}
30+
31+
public function toString(): string
32+
{
33+
return \sprintf('does not equal JSON path "%s" result', $this->jsonPath);
34+
}
35+
36+
protected function matches(mixed $other): bool
37+
{
38+
return (new JsonCrawler($this->json))->find($this->jsonPath) != $other;
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\JsonPath\Test;
13+
14+
use PHPUnit\Framework\Constraint\Constraint;
15+
use Symfony\Component\JsonPath\JsonCrawler;
16+
use Symfony\Component\JsonPath\JsonPath;
17+
18+
/**
19+
* @author Alexandre Daubois <alex.daubois@gmail.com>
20+
*
21+
* @experimental
22+
*/
23+
class JsonPathNotSame extends Constraint
24+
{
25+
public function __construct(
26+
private JsonPath|string $jsonPath,
27+
private string $json,
28+
) {
29+
}
30+
31+
public function toString(): string
32+
{
33+
return \sprintf('is not identical to JSON path "%s" result', $this->jsonPath);
34+
}
35+
36+
protected function matches(mixed $other): bool
37+
{
38+
return (new JsonCrawler($this->json))->find($this->jsonPath) !== $other;
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\JsonPath\Test;
13+
14+
use PHPUnit\Framework\Constraint\Constraint;
15+
use Symfony\Component\JsonPath\JsonCrawler;
16+
use Symfony\Component\JsonPath\JsonPath;
17+
18+
/**
19+
* @author Alexandre Daubois <alex.daubois@gmail.com>
20+
*
21+
* @experimental
22+
*/
23+
class JsonPathSame extends Constraint
24+
{
25+
public function __construct(
26+
private JsonPath|string $jsonPath,
27+
private string $json,
28+
) {
29+
}
30+
31+
public function toString(): string
32+
{
33+
return \sprintf('is identical to JSON path "%s" result', $this->jsonPath);
34+
}
35+
36+
protected function matches(mixed $other): bool
37+
{
38+
return (new JsonCrawler($this->json))->find($this->jsonPath) === $other;
39+
}
40+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy