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>
This commit is contained in:
132
tests/Feature/Panel/WebhookPanelTest.php
Normal file
132
tests/Feature/Panel/WebhookPanelTest.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user