Skip to content

Commit 394a6db

Browse files
authored
Add assertExactJsonStructure method (#52311)
1 parent c2eb318 commit 394a6db

File tree

3 files changed

+111
-4
lines changed

3 files changed

+111
-4
lines changed

src/Illuminate/Testing/AssertableJsonString.php

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,29 +263,40 @@ public function assertPathCanonicalizing($path, $expect)
263263
*
264264
* @param array|null $structure
265265
* @param array|null $responseData
266+
* @param bool $exact
266267
* @return $this
267268
*/
268-
public function assertStructure(?array $structure = null, $responseData = null)
269+
public function assertStructure(?array $structure = null, $responseData = null, bool $exact = false)
269270
{
270271
if (is_null($structure)) {
271272
return $this->assertSimilar($this->decoded);
272273
}
273274

274275
if (! is_null($responseData)) {
275-
return (new static($responseData))->assertStructure($structure);
276+
return (new static($responseData))->assertStructure($structure, null, $exact);
277+
}
278+
279+
if ($exact) {
280+
PHPUnit::assertIsArray($this->decoded);
281+
282+
$keys = collect($structure)->map(fn ($value, $key) => is_array($value) ? $key : $value)->values();
283+
284+
if ($keys->all() !== ['*']) {
285+
PHPUnit::assertEquals($keys->sort()->values()->all(), collect($this->decoded)->keys()->sort()->values()->all());
286+
}
276287
}
277288

278289
foreach ($structure as $key => $value) {
279290
if (is_array($value) && $key === '*') {
280291
PHPUnit::assertIsArray($this->decoded);
281292

282293
foreach ($this->decoded as $responseDataItem) {
283-
$this->assertStructure($structure['*'], $responseDataItem);
294+
$this->assertStructure($structure['*'], $responseDataItem, $exact);
284295
}
285296
} elseif (is_array($value)) {
286297
PHPUnit::assertArrayHasKey($key, $this->decoded);
287298

288-
$this->assertStructure($structure[$key], $this->decoded[$key]);
299+
$this->assertStructure($structure[$key], $this->decoded[$key], $exact);
289300
} else {
290301
PHPUnit::assertArrayHasKey($value, $this->decoded);
291302
}

src/Illuminate/Testing/TestResponse.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,20 @@ public function assertJsonStructure(?array $structure = null, $responseData = nu
847847
return $this;
848848
}
849849

850+
/**
851+
* Assert that the response has the exact JSON structure.
852+
*
853+
* @param array|null $structure
854+
* @param array|null $responseData
855+
* @return $this
856+
*/
857+
public function assertExactJsonStructure(?array $structure = null, $responseData = null)
858+
{
859+
$this->decodeResponseJson()->assertStructure($structure, $responseData, true);
860+
861+
return $this;
862+
}
863+
850864
/**
851865
* Assert that the response JSON has the expected count of items at the given key.
852866
*

tests/Testing/TestResponseTest.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,88 @@ public function testAssertJsonStructure()
14621462
$response->assertJsonStructure(['*' => ['foo', 'bar', 'foobar']]);
14631463
}
14641464

1465+
public function testAssertExactJsonStructure()
1466+
{
1467+
$response = TestResponse::fromBaseResponse(new Response(new JsonSerializableMixedResourcesStub));
1468+
1469+
// Without structure
1470+
$response->assertExactJsonStructure();
1471+
1472+
// At root
1473+
try {
1474+
$response->assertExactJsonStructure(['foo']);
1475+
$failed = false;
1476+
} catch (AssertionFailedError $e) {
1477+
$failed = true;
1478+
}
1479+
1480+
$this->assertTrue($failed);
1481+
1482+
$response->assertExactJsonStructure(['foo', 'foobar', 0, 'bars', 'baz', 'barfoo', 'numeric_keys']);
1483+
1484+
// Nested
1485+
try {
1486+
$response->assertExactJsonStructure(['foobar' => ['foobar_foo'], 'foo', 0, 'bars', 'baz', 'barfoo', 'numeric_keys']);
1487+
$failed = false;
1488+
} catch (AssertionFailedError $e) {
1489+
$failed = true;
1490+
}
1491+
1492+
$this->assertTrue($failed);
1493+
1494+
$response->assertExactJsonStructure(['foobar' => ['foobar_foo', 'foobar_bar'], 'foo', 0, 'bars', 'baz', 'barfoo', 'numeric_keys']);
1495+
1496+
// Wildcard (repeating structure)
1497+
try {
1498+
$response->assertExactJsonStructure(['bars' => ['*' => ['bar']], 'foo', 'foobar', 0, 'baz', 'barfoo', 'numeric_keys']);
1499+
$failed = false;
1500+
} catch (AssertionFailedError $e) {
1501+
$failed = true;
1502+
}
1503+
1504+
$this->assertTrue($failed);
1505+
1506+
$response->assertExactJsonStructure(['bars' => ['*' => ['bar', 'foo']], 'foo', 'foobar', 0, 'baz', 'barfoo', 'numeric_keys']);
1507+
1508+
// Wildcard (numeric keys)
1509+
try {
1510+
$response->assertExactJsonStructure(['numeric_keys' => ['*' => ['bar']], 'foo', 'foobar', 0, 'bars', 'baz', 'barfoo']);
1511+
$failed = false;
1512+
} catch (AssertionFailedError $e) {
1513+
$failed = true;
1514+
}
1515+
1516+
$this->assertTrue($failed);
1517+
1518+
$response->assertExactJsonStructure(['numeric_keys' => ['*' => ['bar', 'foo']], 'foo', 'foobar', 0, 'bars', 'baz', 'barfoo']);
1519+
1520+
// Nested after wildcard
1521+
try {
1522+
$response->assertExactJsonStructure(['baz' => ['*' => ['foo', 'bar' => ['foo']]], 'foo', 'foobar', 0, 'bars', 'barfoo', 'numeric_keys']);
1523+
$failed = false;
1524+
} catch (AssertionFailedError $e) {
1525+
$failed = true;
1526+
}
1527+
1528+
$this->assertTrue($failed);
1529+
1530+
$response->assertExactJsonStructure(['baz' => ['*' => ['foo', 'bar' => ['foo', 'bar']]], 'foo', 'foobar', 0, 'bars', 'barfoo', 'numeric_keys']);
1531+
1532+
// Wildcard (repeating structure) at root
1533+
$response = TestResponse::fromBaseResponse(new Response(new JsonSerializableSingleResourceStub));
1534+
1535+
try {
1536+
$response->assertExactJsonStructure(['*' => ['foo', 'bar']]);
1537+
$failed = false;
1538+
} catch (AssertionFailedError $e) {
1539+
$failed = true;
1540+
}
1541+
1542+
$this->assertTrue($failed);
1543+
1544+
$response->assertExactJsonStructure(['*' => ['foo', 'bar', 'foobar']]);
1545+
}
1546+
14651547
public function testAssertJsonCount()
14661548
{
14671549
$response = TestResponse::fromBaseResponse(new Response(new JsonSerializableMixedResourcesStub));

0 commit comments

Comments
 (0)