Files
landing-api/tests/Feature/Panel/WebhookPanelTest.php
Josep Piguillem d4cf4a66b7
Some checks failed
Tests / lint (push) Has been cancelled
Tests / test (push) Has been cancelled
Tests / test-postgres (push) Has been cancelled
Tests / mcp (push) Has been cancelled
Manage webhooks from the panel
Create one and see its secret once, send a test, change the secret, and read
each delivery with what the other end answered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:44:11 +02:00

133 lines
4.2 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Feature\Panel;
use App\Filament\Resources\Webhooks\Pages\CreateWebhook;
use App\Filament\Resources\Webhooks\Pages\EditWebhook;
use App\Filament\Resources\Webhooks\RelationManagers\DeliveriesRelationManager;
use App\Filament\Resources\Webhooks\WebhookResource;
use App\Models\Webhook;
use App\Services\Media\HostResolver;
use Database\Seeders\RolePermissionSeeder;
use Filament\Notifications\Notification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Livewire\Livewire;
use PHPUnit\Framework\Attributes\Test;
use Tests\FakesPireon;
use Tests\TestCase;
/**
* Webhooks from the panel: the same rules as the API, plus the secret shown
* once and the deliveries at hand.
*/
class WebhookPanelTest extends TestCase
{
use FakesPireon, RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
$this->seed(RolePermissionSeeder::class);
$this->app->instance(HostResolver::class, new class extends HostResolver
{
public function resolve(string $host): array
{
return ['hooks.example.org' => ['93.184.216.34'], 'internal.example.org' => ['10.0.0.5']][$host] ?? [];
}
});
}
#[Test]
public function an_admin_registers_one_and_sees_its_secret_once(): void
{
$this->actingAs($admin = $this->userWithRoles('admin'));
Livewire::test(CreateWebhook::class)
->fillForm([
'name' => 'Avisos',
'url' => 'https://hooks.example.org/pireon',
'events' => ['application.received'],
])
->call('create')
->assertHasNoFormErrors();
$webhook = Webhook::query()->sole();
$this->assertSame(40, strlen($webhook->secret));
$this->assertSame($admin->id, $webhook->created_by);
Notification::assertNotified(
Notification::make()
->title(__('panel.webhooks.secret.title'))
->body(__('panel.webhooks.secret.body', ['secret' => $webhook->secret]))
->warning()
->persistent(),
);
}
#[Test]
public function an_address_inside_the_network_is_refused(): void
{
$this->actingAs($this->userWithRoles('admin'));
Livewire::test(CreateWebhook::class)
->fillForm(['name' => 'X', 'url' => 'https://internal.example.org/x', 'events' => ['*']])
->call('create')
->assertHasFormErrors(['url']);
$this->assertSame(0, Webhook::query()->count());
}
#[Test]
public function a_test_is_sent_and_shows_among_the_deliveries(): void
{
Http::fake(['hooks.example.org/*' => Http::response('ok')]);
$this->actingAs($this->userWithRoles('admin'));
$webhook = Webhook::factory()->create(['url' => 'https://hooks.example.org/x']);
Livewire::test(EditWebhook::class, ['record' => $webhook->getRouteKey()])
->callAction('ping');
Livewire::test(DeliveriesRelationManager::class, ['ownerRecord' => $webhook, 'pageClass' => EditWebhook::class])
->assertCanSeeTableRecords($webhook->deliveries()->get())
->assertSee('ping');
}
#[Test]
public function rotating_the_secret_shows_the_new_one(): void
{
$this->actingAs($this->userWithRoles('admin'));
$webhook = Webhook::factory()->create(['secret' => 'old-secret-old-secret']);
Livewire::test(EditWebhook::class, ['record' => $webhook->getRouteKey()])
->callAction('rotate_secret');
$new = $webhook->fresh()->secret;
$this->assertNotSame('old-secret-old-secret', $new);
Notification::assertNotified(
Notification::make()
->title(__('panel.webhooks.secret.title'))
->body(__('panel.webhooks.secret.body', ['secret' => $new]))
->warning()
->persistent(),
);
}
#[Test]
public function an_editor_does_not_see_them(): void
{
$this->actingAs($this->userWithRoles('editor'));
$this->get(WebhookResource::getUrl('index'))->assertForbidden();
}
}