Skip to content

Commit 443291c

Browse files
committed
add json assertions on the TestResponseHelper
Signed-off-by: Tonko Mulder <[email protected]>
1 parent e20ff4f commit 443291c

File tree

2 files changed

+145
-1
lines changed

2 files changed

+145
-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: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@
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\Modules\Books\Models\Author;
13+
use Tests\Tempest\Fixtures\Modules\Books\Models\Book;
914
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
1015

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

0 commit comments

Comments
 (0)