Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion resources/js/Pages/Endpoints/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,19 @@ async function saveEndpoint() {
showOneTimeSecret(response.data.plain_secret)
} catch (error) {
if (error.response?.data?.errors) {
form.setError(error.response.data.errors)
// Laravel's JSON validation-error response shapes each field
// as an array of messages. A normal Inertia form submission
// flattens these before they reach the client, but this is a
// raw axios call, so it must be flattened here too — otherwise
// form.setError() stores the array itself and InputError.vue
// (which expects a string) renders it as a JSON blob.
const errors = Object.fromEntries(
Object.entries(error.response.data.errors).map(([field, messages]) => [
field,
Array.isArray(messages) ? messages[0] : messages,
])
)
form.setError(errors)
} else {
alert('Failed to save endpoint. Please try again.')
}
Expand Down
35 changes: 35 additions & 0 deletions tests/Feature/EndpointCreateValidationErrorFormatTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class EndpointCreateValidationErrorFormatTest extends TestCase
{
use RefreshDatabase;

/**
* The "Create Endpoint" modal submits via a raw axios call (rather than
* Inertia's form helper) so it can read back the one-time plain_secret
* on success, which means the frontend receives Laravel's raw JSON
* validation-error shape and must flatten it itself. This test pins
* that shape down: each field's errors are an array of messages, not a
* single string.
*/
public function test_validation_errors_for_ajax_endpoint_creation_are_returned_as_arrays_per_field(): void
{
$user = User::factory()->withPersonalTeam()->create();

$response = $this->actingAs($user)->postJson('/endpoints', [
'name' => '',
'url' => 'not-a-url',
]);

$response->assertStatus(422);
$response->assertJsonValidationErrors(['name', 'url']);
$this->assertIsArray($response->json('errors.name'));
$this->assertIsArray($response->json('errors.url'));
}
}
Loading