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:
164
tests/Feature/Panel/DuplicateTitlesTest.php
Normal file
164
tests/Feature/Panel/DuplicateTitlesTest.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature\Panel;
|
||||
|
||||
use App\Filament\Resources\Pages\PageResource;
|
||||
use App\Filament\Resources\Pages\Pages\CreatePage;
|
||||
use App\Filament\Resources\Pages\Pages\EditPage;
|
||||
use App\Filament\Resources\Projects\Pages\CreateProject;
|
||||
use App\Filament\Resources\Services\Pages\CreateService;
|
||||
use App\Models\Page;
|
||||
use App\Models\Project;
|
||||
use App\Models\Service;
|
||||
use App\Support\DuplicateTitles;
|
||||
use Database\Seeders\RolePermissionSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use Tests\FakesPireon;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* A nudge, not a rule.
|
||||
*
|
||||
* The slug already has a hard uniqueness constraint — two records cannot
|
||||
* answer at the same address. What this catches is the case that constraint
|
||||
* cannot: two records with different addresses and almost the same title,
|
||||
* which is what actually happens when nobody remembers something already
|
||||
* exists. It warns; it has never once refused to save.
|
||||
*/
|
||||
class DuplicateTitlesTest extends TestCase
|
||||
{
|
||||
use FakesPireon, RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->seed(RolePermissionSeeder::class);
|
||||
$this->actingAs($this->userWithRoles('admin'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function a_near_identical_title_is_found(): void
|
||||
{
|
||||
Page::factory()->create(['title' => ['es' => 'Gestor de socios']]);
|
||||
|
||||
$matches = DuplicateTitles::similarTo(Page::class, 'Gestor de socios v2', 'es', null);
|
||||
|
||||
$this->assertCount(1, $matches);
|
||||
$this->assertSame('Gestor de socios', $matches->first()->getTranslation('title', 'es', false));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function an_unrelated_title_is_not_a_match(): void
|
||||
{
|
||||
Page::factory()->create(['title' => ['es' => 'Gestor de socios']]);
|
||||
|
||||
$matches = DuplicateTitles::similarTo(Page::class, 'Convocatoria de primavera', 'es', null);
|
||||
|
||||
$this->assertTrue($matches->isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* The record being edited must never flag itself: typing in an existing
|
||||
* page's own title field would otherwise "find" a perfect match on every
|
||||
* keystroke.
|
||||
*/
|
||||
#[Test]
|
||||
public function a_record_is_never_a_duplicate_of_itself(): void
|
||||
{
|
||||
$page = Page::factory()->create(['title' => ['es' => 'Gestor de socios']]);
|
||||
|
||||
$matches = DuplicateTitles::similarTo(Page::class, 'Gestor de socios', 'es', $page->id);
|
||||
|
||||
$this->assertTrue($matches->isEmpty());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function an_empty_title_matches_nothing(): void
|
||||
{
|
||||
Page::factory()->create(['title' => ['es' => 'Gestor de socios']]);
|
||||
|
||||
$this->assertTrue(DuplicateTitles::similarTo(Page::class, '', 'es', null)->isEmpty());
|
||||
$this->assertTrue(DuplicateTitles::similarTo(Page::class, ' ', 'es', null)->isEmpty());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function only_the_closest_three_are_returned(): void
|
||||
{
|
||||
foreach (range(1, 5) as $n) {
|
||||
Page::factory()->create(['title' => ['es' => "Gestor de socios {$n}"]]);
|
||||
}
|
||||
|
||||
$matches = DuplicateTitles::similarTo(Page::class, 'Gestor de socios', 'es', null);
|
||||
|
||||
$this->assertCount(3, $matches);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function typing_a_near_duplicate_title_warns_while_creating(): void
|
||||
{
|
||||
Page::factory()->create(['title' => ['es' => 'Quiénes somos']]);
|
||||
|
||||
Livewire::test(CreatePage::class)
|
||||
->fillForm(['title' => ['es' => 'Quienes somos']])
|
||||
->assertNotified(__('panel.duplicates.title'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Editing an existing page must not warn about itself the moment the
|
||||
* form is touched.
|
||||
*/
|
||||
#[Test]
|
||||
public function editing_a_page_without_changing_its_title_does_not_warn(): void
|
||||
{
|
||||
$page = Page::factory()->create(['title' => ['es' => 'Quiénes somos']]);
|
||||
|
||||
Livewire::test(EditPage::class, ['record' => $page->getKey()])
|
||||
->fillForm(['excerpt' => ['es' => 'Un resumen nuevo']])
|
||||
->assertNotNotified(__('panel.duplicates.title'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function the_warning_links_to_the_existing_record(): void
|
||||
{
|
||||
$existing = Page::factory()->create(['title' => ['es' => 'Quiénes somos']]);
|
||||
|
||||
$component = Livewire::test(CreatePage::class)
|
||||
->fillForm(['title' => ['es' => 'Quienes somos']]);
|
||||
|
||||
// Read ahead of `assertNotified()`, which pulls this same key from
|
||||
// the session and would leave nothing behind for a second read.
|
||||
$notified = collect(session('filament.claimed_notifications'))->first();
|
||||
|
||||
$component->assertNotified(__('panel.duplicates.title'));
|
||||
|
||||
$this->assertSame(
|
||||
PageResource::getUrl('edit', ['record' => $existing]),
|
||||
$notified['actions'][0]['url'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_works_for_projects(): void
|
||||
{
|
||||
Project::factory()->create(['title' => ['es' => 'Web del colectivo']]);
|
||||
|
||||
Livewire::test(CreateProject::class)
|
||||
->fillForm(['title' => ['es' => 'Web del colectivo v2']])
|
||||
->assertNotified(__('panel.duplicates.title'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function it_works_for_services(): void
|
||||
{
|
||||
Service::factory()->create(['title' => ['es' => 'Auditoría técnica']]);
|
||||
|
||||
Livewire::test(CreateService::class)
|
||||
->fillForm(['title' => ['es' => 'Auditoria tecnica']])
|
||||
->assertNotified(__('panel.duplicates.title'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user