Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
timacdonald committed Jan 4, 2024
1 parent 260e70f commit c5dfb9a
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/Recorders/ValidationErrors.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ protected function parseJsonValidationErrors(Request $request, BaseResponse $res
! is_array($response->original) ||
! array_key_exists('errors', $response->original) ||
! is_array($response->original['errors']) ||
! array_is_list($response->original['errors'])
array_is_list($response->original['errors'])
) {
return null;
}
Expand Down
135 changes: 130 additions & 5 deletions tests/Feature/Recorders/ValidationErrorsTest.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<?php

use Illuminate\Http\JsonResponse as IlluminateJsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Route;
use Laravel\Pulse\Facades\Pulse;
use Laravel\Pulse\Recorders\ValidationErrors;
use Symfony\Component\HttpFoundation\JsonResponse as SymfonyJsonResponse;

use function Pest\Laravel\post;
use function Pest\Laravel\postJson;

beforeEach(fn () => Pulse::register([ValidationErrors::class => []]));

Expand All @@ -17,19 +20,46 @@

$response = post('users');

$response->assertStatus(302);
$response->assertInvalid('email');

$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(1);
expect($entries[0]->key)->toBe('["POST","\/users","Closure","email"]');

$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates->pluck('key')->all())->toBe(array_fill(0, 4, '["POST","\/users","Closure","email"]'));
expect($aggregates->pluck('aggregate')->all())->toBe(array_fill(0, 4, 'count'));
expect($aggregates->pluck('value')->all())->toBe(array_fill(0, 4, '1.00'));
});

it('captures one entry for field when multiple errors are present for the given field from the session', function () {
it('does not capture validation errors from redirects when there is no session', function () {
Route::post('users', fn () => Request::validate([
'email' => 'required',
]));

$response = post('users');

$response->assertStatus(302);
$response->assertInvalid('email');
$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(0);
$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates)->toHaveCount(0);
});

it('does not capture validation errors from redirects when the "errors" key is not a ViewErrorBag with session', function () {
Route::post('users', fn () => redirect()->back()->with('errors', 'Something happened!'))->middleware('web');

$response = post('users');

$response->assertStatus(302);
$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(0);
$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates)->toHaveCount(0);
});


it('captures one entry for a field when multiple errors are present for the given field from the session', function () {
Route::post('users', fn () => Request::validate([
'email' => 'string|min:5',
]))->middleware('web');
Expand All @@ -46,11 +76,9 @@
],
]);
$response->assertInvalid(['email' => 'The email field must be at least 5 characters.']);

$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(1);
expect($entries[0]->key)->toBe('["POST","\/users","Closure","email"]');

$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates->pluck('key')->all())->toBe(array_fill(0, 4, '["POST","\/users","Closure","email"]'));
expect($aggregates->pluck('aggregate')->all())->toBe(array_fill(0, 4, 'count'));
Expand All @@ -63,11 +91,108 @@
$response = post('users');

$response->assertStatus(422);
$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(1);
expect($entries[0]->key)->toBe('["POST","\/users","Closure","__unknown"]');
$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates->pluck('key')->all())->toBe(array_fill(0, 4, '["POST","\/users","Closure","__unknown"]'));
expect($aggregates->pluck('aggregate')->all())->toBe(array_fill(0, 4, 'count'));
expect($aggregates->pluck('value')->all())->toBe(array_fill(0, 4, '1.00'));
});

it('captures API validation errors', function () {
Route::post('users', fn () => Request::validate([
'email' => 'required',
]))->middleware('api');

$response = postJson('users');

$response->assertStatus(422);
$response->assertInvalid('email');
$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(1);
expect($entries[0]->key)->toBe('["POST","\/users","Closure","email"]');
$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates->pluck('key')->all())->toBe(array_fill(0, 4, '["POST","\/users","Closure","email"]'));
expect($aggregates->pluck('aggregate')->all())->toBe(array_fill(0, 4, 'count'));
expect($aggregates->pluck('value')->all())->toBe(array_fill(0, 4, '1.00'));
});

it('captures "unknown" API validation error for non Illuminate Json responses', function () {
Route::post('users', fn () => new SymfonyJsonResponse(['errors' => ['email' => 'Is required.']], 422))
->middleware('api');

$response = postJson('users');

$response->assertStatus(422);
$response->assertInvalid('email');
$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(1);
expect($entries[0]->key)->toBe('["POST","\/users","Closure","__unknown"]');
$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates->pluck('key')->all())->toBe(array_fill(0, 4, '["POST","\/users","Closure","__unknown"]'));
expect($aggregates->pluck('aggregate')->all())->toBe(array_fill(0, 4, 'count'));
expect($aggregates->pluck('value')->all())->toBe(array_fill(0, 4, '1.00'));
});

it('captures "unknown" API validation error for non array Json content', function () {
Route::post('users', fn () => new IlluminateJsonResponse('An error occurred.', 422))
->middleware('api');

$response = postJson('users');

$response->assertStatus(422);
$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(1);
expect($entries[0]->key)->toBe('["POST","\/users","Closure","__unknown"]');
$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates->pluck('key')->all())->toBe(array_fill(0, 4, '["POST","\/users","Closure","__unknown"]'));
expect($aggregates->pluck('aggregate')->all())->toBe(array_fill(0, 4, 'count'));
expect($aggregates->pluck('value')->all())->toBe(array_fill(0, 4, '1.00'));
});

it('captures "unknown" API validation error for array content mising "errors" key', function () {
Route::post('users', fn () => new IlluminateJsonResponse(['An error occurred.'], 422))
->middleware('api');

$response = postJson('users');

$response->assertStatus(422);
$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(1);
expect($entries[0]->key)->toBe('["POST","\/users","Closure","__unknown"]');
$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates->pluck('key')->all())->toBe(array_fill(0, 4, '["POST","\/users","Closure","__unknown"]'));
expect($aggregates->pluck('aggregate')->all())->toBe(array_fill(0, 4, 'count'));
expect($aggregates->pluck('value')->all())->toBe(array_fill(0, 4, '1.00'));
});

it('captures "unknown" API validation error for "errors" key that does not contain an array', function () {
Route::post('users', fn () => new IlluminateJsonResponse(['errors' => 'An error occurred.'], 422))
->middleware('api');

$response = postJson('users');

$response->assertStatus(422);
$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(1);
expect($entries[0]->key)->toBe('["POST","\/users","Closure","__unknown"]');
$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates->pluck('key')->all())->toBe(array_fill(0, 4, '["POST","\/users","Closure","__unknown"]'));
expect($aggregates->pluck('aggregate')->all())->toBe(array_fill(0, 4, 'count'));
expect($aggregates->pluck('value')->all())->toBe(array_fill(0, 4, '1.00'));
});

it('captures "unknown" API validation error for "errors" key that contains a list', function () {
Route::post('users', fn () => new IlluminateJsonResponse(['errors' => ['An error occurred.']], 422))
->middleware('api');

$response = postJson('users');

$response->assertStatus(422);
$entries = Pulse::ignore(fn () => DB::table('pulse_entries')->whereType('validation_error')->get());
expect($entries)->toHaveCount(1);
expect($entries[0]->key)->toBe('["POST","\/users","Closure","__unknown"]');
$aggregates = Pulse::ignore(fn () => DB::table('pulse_aggregates')->whereType('validation_error')->orderBy('period')->get());
expect($aggregates->pluck('key')->all())->toBe(array_fill(0, 4, '["POST","\/users","Closure","__unknown"]'));
expect($aggregates->pluck('aggregate')->all())->toBe(array_fill(0, 4, 'count'));
Expand Down

0 comments on commit c5dfb9a

Please sign in to comment.