Initial commit: Pireon Admin — headless admin panel and public API
Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
166
tests/Feature/Panel/PanelToolsTest.php
Normal file
166
tests/Feature/Panel/PanelToolsTest.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature\Panel;
|
||||
|
||||
use App\Filament\Pages\Trash;
|
||||
use App\Models\Application;
|
||||
use App\Models\Page;
|
||||
use App\Models\Project;
|
||||
use App\Models\User;
|
||||
use App\Support\PreviewLink;
|
||||
use Database\Seeders\RolePermissionSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Livewire\Livewire;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Tests\FakesPireon;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* The everyday tools: the bin and the shareable preview link.
|
||||
*/
|
||||
class PanelToolsTest extends TestCase
|
||||
{
|
||||
use FakesPireon, RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->seed(RolePermissionSeeder::class);
|
||||
Queue::fake();
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function the_bin_gathers_everything_deleted(): void
|
||||
{
|
||||
Page::factory()->create(['title' => ['es' => 'Borrada']])->delete();
|
||||
Project::factory()->create(['title' => ['es' => 'Borrado']])->delete();
|
||||
|
||||
$this->actingAs($this->userWithRoles('admin'));
|
||||
|
||||
// Recovering something used to mean remembering which resource it had
|
||||
// been in and then turning on a filter.
|
||||
$this->get(Trash::getUrl())
|
||||
->assertSuccessful()
|
||||
->assertSee('Borrada')
|
||||
->assertSee('Borrado');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function something_can_be_put_back_from_the_bin(): void
|
||||
{
|
||||
$page = Page::factory()->create();
|
||||
$page->delete();
|
||||
|
||||
$this->actingAs($this->userWithRoles('admin'));
|
||||
|
||||
Livewire::test(Trash::class)
|
||||
->call('restoreRecord', Page::class, $page->id);
|
||||
|
||||
$this->assertNull($page->fresh()->deleted_at);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function the_bin_refuses_a_model_it_does_not_list(): void
|
||||
{
|
||||
$this->actingAs($this->userWithRoles('admin'));
|
||||
|
||||
// An id and a class name arriving from the browser must not be able to
|
||||
// reach anything the page did not declare.
|
||||
Livewire::test(Trash::class)
|
||||
->call('restoreRecord', User::class, 1)
|
||||
->assertOk();
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function a_viewer_sees_only_what_they_may_see(): void
|
||||
{
|
||||
Application::factory()->create()->delete();
|
||||
Page::factory()->create(['title' => ['es' => 'Una página']])->delete();
|
||||
|
||||
$this->actingAs($this->userWithRoles('viewer'));
|
||||
|
||||
// A viewer has no business reading a stranger's message, in the bin or
|
||||
// anywhere else.
|
||||
$this->get(Trash::getUrl())
|
||||
->assertSuccessful()
|
||||
->assertSee('Una página')
|
||||
->assertDontSee(__('panel.applications.plural'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function a_preview_link_points_at_the_record_it_was_made_for(): void
|
||||
{
|
||||
$project = Project::factory()->draft()->create([
|
||||
'title' => ['es' => 'Borrador'],
|
||||
'slug' => ['es' => 'borrador'],
|
||||
]);
|
||||
|
||||
$url = PreviewLink::for($project, 'project', 'es');
|
||||
|
||||
$this->assertStringContainsString('/proyectos/borrador', $url);
|
||||
$this->assertStringContainsString('preview=', $url);
|
||||
|
||||
$token = urldecode((string) parse_url($url, PHP_URL_QUERY));
|
||||
$token = str_replace('preview=', '', $token);
|
||||
|
||||
$payload = PreviewLink::open($token);
|
||||
|
||||
$this->assertSame('project', $payload['type']);
|
||||
$this->assertSame($project->id, $payload['id']);
|
||||
$this->assertSame('es', $payload['locale']);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function a_preview_link_opens_a_draft_on_the_api(): void
|
||||
{
|
||||
$project = Project::factory()->draft()->create([
|
||||
'title' => ['es' => 'Borrador'],
|
||||
'slug' => ['es' => 'borrador'],
|
||||
]);
|
||||
|
||||
$url = PreviewLink::for($project, 'project', 'es');
|
||||
$token = str_replace('preview=', '', urldecode((string) parse_url($url, PHP_URL_QUERY)));
|
||||
|
||||
$this->withHeaders(['Accept-Language' => 'es'])
|
||||
->getJson('/api/public/v1/projects/borrador')
|
||||
->assertNotFound();
|
||||
|
||||
$this->withHeaders(['Accept-Language' => 'es'])
|
||||
->getJson('/api/public/v1/projects/borrador?preview='.urlencode($token))
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function a_forged_or_expired_link_opens_nothing(): void
|
||||
{
|
||||
$this->assertNull(PreviewLink::open('no-es-un-token'));
|
||||
|
||||
$project = Project::factory()->draft()->create([
|
||||
'title' => ['es' => 'Borrador'], 'slug' => ['es' => 'borrador'],
|
||||
]);
|
||||
|
||||
$url = PreviewLink::for($project, 'project', 'es');
|
||||
$token = str_replace('preview=', '', urldecode((string) parse_url($url, PHP_URL_QUERY)));
|
||||
|
||||
$this->travel(PreviewLink::HOURS + 1)->hours();
|
||||
|
||||
// Short-lived on purpose: one forwarded in an e-mail thread stops
|
||||
// working rather than living for ever.
|
||||
$this->assertNull(PreviewLink::open($token));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function a_record_with_no_slug_in_a_language_has_no_link_for_it(): void
|
||||
{
|
||||
$project = Project::factory()->draft()->create(['slug' => ['es' => 'solo-es']]);
|
||||
|
||||
$this->assertNotNull(PreviewLink::for($project, 'project', 'es'));
|
||||
$this->assertNull(PreviewLink::for($project, 'project', 'ca'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user