Files
WebHookInspector/tests/Feature/WebhookInspectorTest.php
T
2026-08-05 16:19:43 +02:00

177 lines
6.8 KiB
PHP

<?php
namespace Tests\Feature;
use App\Livewire\Dashboard;
use App\Livewire\Inspector;
use App\Models\User;
use App\Models\WebhookEndpoint;
use App\Models\WebhookRequest;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;
class WebhookInspectorTest extends TestCase
{
use LazilyRefreshDatabase;
public function test_private_endpoints_are_only_visible_to_the_owner(): void
{
$owner = User::factory()->create();
$otherUser = User::factory()->create();
$endpoint = WebhookEndpoint::factory()->ownedBy($owner)->create();
$this->get(route('inspect.show', ['token' => $endpoint->token]))->assertForbidden();
$this->actingAs($otherUser)->get(route('inspect.show', ['token' => $endpoint->token]))->assertForbidden();
$this->actingAs($owner)->get(route('inspect.show', ['token' => $endpoint->token]))->assertOk();
}
public function test_private_endpoints_can_only_be_deleted_by_the_owner(): void
{
$owner = User::factory()->create();
$otherUser = User::factory()->create();
$endpoint = WebhookEndpoint::factory()->ownedBy($owner)->create();
$this->actingAs($otherUser)
->delete(route('inspect.destroy', ['token' => $endpoint->token]))
->assertForbidden();
$this->assertModelExists($endpoint);
$this->actingAs($owner)
->delete(route('inspect.destroy', ['token' => $endpoint->token]))
->assertRedirect(route('home'));
$this->assertModelMissing($endpoint);
}
public function test_livewire_inspector_can_filter_search_select_and_delete_requests(): void
{
$endpoint = WebhookEndpoint::factory()->create();
$getRequest = WebhookRequest::factory()->forEndpoint($endpoint)->create([
'method' => 'GET',
'request_uri' => '/hook/test?search=visible',
'body' => '<script>alert(1)</script>',
'body_size' => 25,
]);
WebhookRequest::factory()->forEndpoint($endpoint)->create([
'method' => 'POST',
'request_uri' => '/hook/other',
]);
Livewire::test(Inspector::class, ['endpoint' => $endpoint])
->assertSee('/hook/test?search=visible')
->set('methodFilter', 'POST')
->assertSee('/hook/other')
->assertDontSee('/hook/test?search=visible')
->set('methodFilter', 'ALL')
->set('search', 'visible')
->assertSee('/hook/test?search=visible')
->assertDontSee('/hook/other')
->call('selectRequest', $getRequest->getKey())
->assertSee('&lt;script&gt;alert(1)&lt;/script&gt;', false)
->assertDontSee('<script>alert(1)</script>', false)
->call('deleteRequest', $getRequest->getKey());
$this->assertModelMissing($getRequest);
}
public function test_private_endpoints_can_be_created_from_the_dashboard(): void
{
$user = User::factory()->create();
Livewire::actingAs($user)
->test(Dashboard::class)
->set('endpointName', 'Payments')
->call('saveEndpoint')
->assertRedirect();
$endpoint = $user->webhookEndpoints()->firstOrFail();
$this->assertFalse($endpoint->is_public);
$this->assertSame('Payments', $endpoint->name);
$this->assertNull($endpoint->expires_at);
}
public function test_private_endpoint_response_can_be_configured_from_the_inspector(): void
{
$user = User::factory()->create();
$endpoint = WebhookEndpoint::factory()->ownedBy($user)->create();
Livewire::actingAs($user)
->test(Inspector::class, ['endpoint' => $endpoint])
->set('responseStatus', 202)
->set('responseHeadersJson', '{"Content-Type":"text/plain","X-Inspector":"accepted"}')
->set('responseBody', 'queued')
->call('saveResponse')
->assertSet('responseSaved', true);
$endpoint->refresh();
$this->assertSame(202, $endpoint->response_status);
$this->assertSame(
['Content-Type' => 'text/plain', 'X-Inspector' => 'accepted'],
$endpoint->response_headers,
);
$this->assertSame('queued', $endpoint->response_body);
}
public function test_private_endpoint_settings_are_available_in_a_modal(): void
{
$user = User::factory()->create();
$endpoint = WebhookEndpoint::factory()->ownedBy($user)->create();
Livewire::actingAs($user)
->test(Inspector::class, ['endpoint' => $endpoint])
->set('showEndpointSettings', true)
->assertSee('Endpoint settings')
->assertSee('Send requests here')
->assertSee('Save response');
}
public function test_selected_requests_expose_browser_xhr_forwarding_controls(): void
{
$endpoint = WebhookEndpoint::factory()->create();
$webhookRequest = WebhookRequest::factory()->forEndpoint($endpoint)->create([
'method' => 'POST',
'request_uri' => '/hook/test?source=browser',
'headers' => ['content-type' => ['application/json'], 'x-request-id' => ['req-123']],
'body' => '{"event":"created"}',
]);
$payload = new Inspector;
$payload->mount($endpoint);
$this->assertSame($endpoint->getKey(), $payload->xhrRequestPayload($webhookRequest->getKey())['endpointId']);
$this->assertSame(base64_encode($webhookRequest->body), $payload->xhrRequestPayload($webhookRequest->getKey())['body']);
Livewire::test(Inspector::class, ['endpoint' => $endpoint])
->call('selectRequest', $webhookRequest->getKey())
->assertSee('Send via XHR')
->assertSee('data-xhr-redirect-modal', false)
->assertSee('data-xhr-request-headers', false)
->call('requestReceived', [
'endpointId' => (string) $endpoint->getKey(),
'requestId' => (string) $webhookRequest->getKey(),
])
->assertDispatched(
'xhr-request-available',
endpointId: (string) $endpoint->getKey(),
requestId: (string) $webhookRequest->getKey(),
);
}
public function test_request_body_is_escaped_in_the_inspector(): void
{
$endpoint = WebhookEndpoint::factory()->create();
$webhookRequest = WebhookRequest::factory()->forEndpoint($endpoint)->create([
'body' => '<img src=x onerror=alert(1)>',
'body_size' => 29,
]);
Livewire::test(Inspector::class, ['endpoint' => $endpoint])
->call('selectRequest', $webhookRequest->getKey())
->assertDontSee('<img src=x onerror=alert(1)>', false)
->assertSee('&lt;img src=x onerror=alert(1)&gt;', false);
}
}