seed(RolePermissionSeeder::class); Queue::fake(); $this->app->instance(HostResolver::class, new class extends HostResolver { public function resolve(string $host): array { return ['93.184.216.34']; } }); } protected function actingWithRole(string $role): User { $user = User::factory()->create(); $user->syncRoles([$role]); $this->withHeaders($this->apiHeadersFor($user)); return $user; } #[Test] public function wildcards_cover_a_kind_of_record_or_an_action(): void { $webhook = Webhook::factory()->make(['events' => ['projects.*', '*.deleted']]); $this->assertTrue($webhook->listensTo('projects.updated')); $this->assertTrue($webhook->listensTo('pages.deleted')); $this->assertFalse($webhook->listensTo('pages.updated')); $this->assertFalse($webhook->listensTo('content.published')); } #[Test] public function editing_a_project_says_what_changed_who_did_it_and_how(): void { $editor = $this->actingWithRole('editor'); $webhook = Webhook::factory()->create(['events' => ['projects.*']]); $project = Project::factory()->create(['status' => 'active']); $this->patchJson("/api/v1/projects/{$project->id}", ['status' => 'paused'])->assertOk(); $delivery = $webhook->deliveries()->where('event', 'projects.updated')->sole(); $this->assertSame($project->id, $delivery->payload['id']); $this->assertSame(['old' => 'active', 'new' => 'paused'], $delivery->payload['changes']['status']); $this->assertSame($editor->id, $delivery->payload['by']['id']); $this->assertSame('api', $delivery->payload['via']); } #[Test] public function creating_and_deleting_are_events_too(): void { $this->actingWithRole('editor'); $webhook = Webhook::factory()->create(['events' => ['pages.created', '*.deleted']]); $id = $this->postJson('/api/v1/pages', ['title' => ['es' => 'Hola'], 'slug' => ['es' => 'hola']])->json('data.id'); $this->deleteJson("/api/v1/pages/{$id}")->assertNoContent(); $this->assertSame(['pages.deleted', 'pages.created'], $webhook->deliveries()->pluck('event')->all()); $this->assertNull($webhook->deliveries()->first()->payload['url']); } #[Test] public function what_the_application_does_by_itself_is_not_announced(): void { $webhook = Webhook::factory()->create(['events' => ['*']]); Repository::factory()->create()->forceFill(['stars' => 10])->save(); $this->assertSame(0, $webhook->deliveries()->count()); } #[Test] public function security_records_cannot_be_subscribed_to(): void { $this->actingWithRole('admin'); foreach (['users.updated', 'tokens.*', 'settings.updated', 'webhooks.created', 'projects.exploded'] as $event) { $this->postJson('/api/v1/webhooks', ['name' => 'X', 'url' => 'https://hooks.example.org/x', 'events' => [$event]]) ->assertUnprocessable() ->assertJsonValidationErrors('events.0'); } $this->postJson('/api/v1/webhooks', ['name' => 'X', 'url' => 'https://hooks.example.org/x', 'events' => ['projects.*', '*.restored']]) ->assertCreated(); } #[Test] public function the_inbox_tells_how_it_is_handled_and_its_words_only_when_asked(): void { $this->actingWithRole('editor'); $plain = Webhook::factory()->create(['events' => ['applications.updated']]); $personal = Webhook::factory()->create(['events' => ['applications.*'], 'include_personal_data' => true]); $application = Application::factory()->create(['email' => 'ada@example.org']); $this->patchJson("/api/v1/applications/{$application->id}", ['status' => 'contacted', 'notes' => 'Llamar el lunes'])->assertOk(); $sent = $plain->deliveries()->latest('id')->first()->payload; $full = $personal->deliveries()->latest('id')->first()->payload; $this->assertArrayNotHasKey('notes', $sent['changes'] ?? []); $this->assertArrayNotHasKey('email', $sent); $this->assertSame('ada@example.org', $full['email']); $this->assertSame(ApplicationStatus::Contacted->value, $application->fresh()->status->value); } #[Test] public function the_events_answer_as_queued_deliveries(): void { $this->actingWithRole('editor'); Webhook::factory()->create(['events' => ['*']]); $page = Page::factory()->create(); $this->patchJson("/api/v1/pages/{$page->id}", ['is_featured' => ! $page->is_featured])->assertOk(); $this->assertTrue(WebhookDelivery::query()->where('event', 'pages.updated')->exists()); } }