Skip to content

Commit 972335b

Browse files
committed
add json assertions on the TestResponseHelper
Signed-off-by: Tonko Mulder <[email protected]>
1 parent 966ab8d commit 972335b

File tree

2 files changed

+149
-1
lines changed

2 files changed

+149
-1
lines changed

src/Tempest/Framework/Testing/Http/TestResponseHelper.php

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66

77
use Closure;
88
use Generator;
9+
use JsonException;
910
use PHPUnit\Framework\Assert;
1011
use Tempest\Http\Cookie\CookieManager;
1112
use Tempest\Http\Response;
13+
use Tempest\Http\Responses\Invalid;
1214
use Tempest\Http\Session\Session;
1315
use Tempest\Http\Status;
1416
use Tempest\Validation\Rule;
@@ -219,9 +221,77 @@ public function assertNotSee(string $search): self
219221
return $this;
220222
}
221223

224+
public function assertJson(array $expected): self
225+
{
226+
Assert::assertNotNull($this->response->body);
227+
Assert::assertEquals($expected, $this->response->body);
228+
229+
return $this;
230+
}
231+
232+
public function assertJsonByKeys(array $expected, array $keys): self
233+
{
234+
$filteredBody = array_reduce(
235+
[$expected],
236+
function ($carry) use ($keys) {
237+
foreach ($keys as $key) {
238+
if (isset($this->response->body[$key])) {
239+
$carry[$key] = $this->response->body[$key];
240+
}
241+
242+
if (str_contains($key, '.') && substr_count($key, '.') === 1) {
243+
[$relation, $relatedKey] = explode('.', $key);
244+
$carry[$relation][$relatedKey] = $this->body[$relation][$relatedKey];
245+
}
246+
}
247+
248+
return $carry;
249+
},
250+
[],
251+
);
252+
253+
Assert::assertNotEmpty($filteredBody);
254+
Assert::assertEquals($expected, $filteredBody);
255+
256+
return $this;
257+
}
258+
259+
public function assertHasJsonValidationError(string $key, ?Closure $test = null): self
260+
{
261+
Assert::assertInstanceOf(Invalid::class, $this->response);
262+
263+
$validationErrors = array_map(function ($failingRules) use ($key) {
264+
try {
265+
$errors = json_decode($failingRules, true, 512, JSON_THROW_ON_ERROR);
266+
} catch (JsonException) {
267+
$errors = [];
268+
}
269+
270+
return arr($errors)->filter(fn (array $_error, $errorKey) => $errorKey === $key)->flatten()->first();
271+
}, $this->response->getHeader('x-validation')->values);
272+
273+
Assert::assertNotEmpty($validationErrors, message: 'no validation errors found');
274+
275+
if ($test !== null) {
276+
$test($validationErrors);
277+
}
278+
279+
return $this;
280+
}
281+
282+
public function assertHasNoJsonValidationErrors(): self
283+
{
284+
Assert::assertNotInstanceOf(Invalid::class, $this->response);
285+
286+
return $this;
287+
}
288+
222289
public function dd(): void
223290
{
224-
// @phpstan-ignore disallowed.function
291+
/**
292+
* @noinspection ForgottenDebugOutputInspection
293+
* @phpstan-ignore disallowed.function
294+
*/
225295
dd($this->response); // @mago-expect best-practices/no-debug-symbols
226296
}
227297
}

tests/Integration/Http/ValidationResponseTest.php

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44

55
namespace Tests\Tempest\Integration\Http;
66

7+
use Tempest\Database\Migrations\CreateMigrationsTable;
78
use Tempest\Http\Session\Session;
89
use Tests\Tempest\Fixtures\Controllers\ValidationController;
10+
use Tests\Tempest\Fixtures\Migrations\CreateAuthorTable;
11+
use Tests\Tempest\Fixtures\Migrations\CreateBookTable;
12+
use Tests\Tempest\Fixtures\Migrations\CreatePublishersTable;
13+
use Tests\Tempest\Fixtures\Modules\Books\Models\Author;
14+
use Tests\Tempest\Fixtures\Modules\Books\Models\Book;
915
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
1016

1117
use function Tempest\uri;
@@ -43,4 +49,76 @@ public function test_original_values(): void
4349
$this->assertEquals($values, $data);
4450
});
4551
}
52+
53+
public function test_assert_json_by_keys_assertion(): void
54+
{
55+
$this->migrate(
56+
CreateMigrationsTable::class,
57+
CreatePublishersTable::class,
58+
CreateAuthorTable::class,
59+
CreateBookTable::class,
60+
);
61+
62+
$author = Author::create(name: 'Homer');
63+
Book::create(title: 'The Odyssee', author: $author);
64+
65+
$this->http
66+
->get(uri([ValidationController::class, 'book'], book: 1))
67+
->assertHasNoJsonValidationErrors()
68+
->assertJson(['id' => 1, 'title' => 'The Odyssee', 'author' => ['id' => 1, 'name' => 'Homer']])
69+
->assertJsonByKeys(['id' => 1, 'title' => 'The Odyssee'], ['id', 'title'])
70+
->assertJsonByKeys(['author' => ['name' => 'Homer']], ['author.name']);
71+
}
72+
73+
public function test_update_book(): void
74+
{
75+
$this->migrate(
76+
CreateMigrationsTable::class,
77+
CreatePublishersTable::class,
78+
CreateAuthorTable::class,
79+
CreateBookTable::class,
80+
);
81+
82+
$book = Book::create(
83+
title: 'The Odyssee',
84+
author: Author::create(name: 'Homer'),
85+
);
86+
87+
$this->http
88+
->post(
89+
uri([ValidationController::class, 'updateBook'], book: 1),
90+
body: ['title' => 'Beyond the Odyssee'],
91+
)
92+
->assertOk();
93+
94+
$book->refresh();
95+
96+
$this->assertSame($book->title, 'Beyond the Odyssee');
97+
}
98+
99+
public function test_failing_post_request(): void
100+
{
101+
$this->migrate(
102+
CreateMigrationsTable::class,
103+
CreatePublishersTable::class,
104+
CreateAuthorTable::class,
105+
CreateBookTable::class,
106+
);
107+
108+
Book::create(
109+
title: 'The Odyssee',
110+
author: Author::create(name: 'Homer'),
111+
);
112+
113+
$this->http
114+
->post(
115+
uri([ValidationController::class, 'updateBook'], book: 1),
116+
body: ['book' => ['title' => 1]],
117+
)
118+
->assertHasJsonValidationError('title', function (array $errors): void {
119+
$this->assertContains('Value should be between 1 and 120', $errors);
120+
});
121+
122+
$this->assertSame('The Odyssee', Book::find(id: 1)->first()->title);
123+
}
46124
}

0 commit comments

Comments
 (0)