- Gli elenchi tengono ricerca, filtri e ordinamento nell'indirizzo (#[Url]); la pagina c'era già. - I link verso schede e operazioni (data-ritorno) portano ?da= con la pagina di partenza, o il da già ricevuto: si risale all'origine (elenco -> scheda -> Rientra -> elenco filtrato). - Ritorno::valida accetta solo percorsi interni: niente rimandi esterni. - Trait RicordaRitorno: redirect dopo il salvataggio, Annulla e "Torna indietro" usano la pagina di partenza. Senza da, tutto come prima. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
192 lines
7.4 KiB
PHP
192 lines
7.4 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Assegnazioni\Rientra;
|
|
use App\Livewire\Proclamatori\ProclamatoreEdit;
|
|
use App\Livewire\Proclamatori\ProclamatoreIndex;
|
|
use App\Livewire\Territori\TerritorioIndex;
|
|
use App\Models\AnnoTeocratico;
|
|
use App\Models\Assegnazione;
|
|
use App\Models\Proclamatore;
|
|
use App\Models\Setting;
|
|
use App\Models\Territorio;
|
|
use App\Models\User;
|
|
use App\Support\Ritorno;
|
|
use Database\Seeders\RolesAndPermissionsSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Livewire\Livewire;
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Dopo un'operazione (confermata o annullata) si torna alla pagina da cui il
|
|
* percorso era partito, con i suoi filtri: ?da=… (App\Support\Ritorno).
|
|
*/
|
|
class RitornoTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private User $admin;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->withoutVite();
|
|
$this->seed(RolesAndPermissionsSeeder::class);
|
|
Setting::firstOrCreate([], ['congregazione_nome' => 'Congregazione di prova']);
|
|
AnnoTeocratico::create(['label' => '2026-2027', 'start_date' => '2026-09-01', 'end_date' => '2027-08-31']);
|
|
|
|
$this->admin = User::create(['name' => 'Admin', 'email' => 'admin@example.test', 'password' => 'password-di-prova']);
|
|
$this->admin->assignRole('amministratore');
|
|
}
|
|
|
|
// ─── Validazione ────────────────────────────────────────────
|
|
|
|
public function test_un_percorso_interno_diventa_l_url_di_ritorno(): void
|
|
{
|
|
$this->assertSame(url('/territori?filterZona=3&page=2'), Ritorno::valida('/territori?filterZona=3&page=2'));
|
|
$this->assertSame(url('/'), Ritorno::valida('/'));
|
|
}
|
|
|
|
#[DataProvider('ritorniNonValidi')]
|
|
public function test_un_ritorno_esterno_o_malformato_si_ignora(mixed $valore): void
|
|
{
|
|
$this->assertNull(Ritorno::valida($valore));
|
|
}
|
|
|
|
public static function ritorniNonValidi(): array
|
|
{
|
|
return [
|
|
'vuoto' => [''],
|
|
'null' => [null],
|
|
'array' => [['/territori']],
|
|
'url completo' => ['https://altro.sito/x'],
|
|
'senza schema' => ['//altro.sito/x'],
|
|
'barra rovesciata' => ['/\\altro.sito'],
|
|
'relativo' => ['territori'],
|
|
'javascript' => ['javascript:alert(1)'],
|
|
'a capo' => ["/territori\r\nX: y"],
|
|
'livewire' => ['/livewire/update'],
|
|
];
|
|
}
|
|
|
|
// ─── Dopo la conferma ───────────────────────────────────────
|
|
|
|
private function assegnazioneAperta(): Assegnazione
|
|
{
|
|
$territorio = Territorio::create(['numero' => '35', 'attivo' => true]);
|
|
$proclamatore = Proclamatore::create(['nome' => 'Mario', 'cognome' => 'Rossi', 'attivo' => true]);
|
|
|
|
return Assegnazione::create([
|
|
'territorio_id' => $territorio->id,
|
|
'proclamatore_id' => $proclamatore->id,
|
|
'anno_teocratico_id' => AnnoTeocratico::sole()->id,
|
|
'assigned_at' => now()->subDays(10),
|
|
'created_by' => $this->admin->id,
|
|
]);
|
|
}
|
|
|
|
public function test_il_rientro_torna_all_elenco_filtrato_da_cui_si_era_partiti(): void
|
|
{
|
|
$assegnazione = $this->assegnazioneAperta();
|
|
|
|
Livewire::withQueryParams(['da' => '/territori?filterStato=da_rientrare&page=2'])
|
|
->actingAs($this->admin)
|
|
->test(Rientra::class, ['assegnazione' => $assegnazione])
|
|
->call('save')
|
|
->assertRedirect(url('/territori?filterStato=da_rientrare&page=2'));
|
|
}
|
|
|
|
public function test_senza_pagina_di_partenza_il_rientro_va_alla_scheda_come_prima(): void
|
|
{
|
|
$assegnazione = $this->assegnazioneAperta();
|
|
|
|
Livewire::actingAs($this->admin)
|
|
->test(Rientra::class, ['assegnazione' => $assegnazione])
|
|
->call('save')
|
|
->assertRedirect(route('territori.show', $assegnazione->territorio_id));
|
|
}
|
|
|
|
public function test_un_ritorno_verso_l_esterno_non_viene_seguito(): void
|
|
{
|
|
$assegnazione = $this->assegnazioneAperta();
|
|
|
|
Livewire::withQueryParams(['da' => '//altro.sito/phishing'])
|
|
->actingAs($this->admin)
|
|
->test(Rientra::class, ['assegnazione' => $assegnazione])
|
|
->assertSet('ritorno', null)
|
|
->call('save')
|
|
->assertRedirect(route('territori.show', $assegnazione->territorio_id));
|
|
}
|
|
|
|
public function test_la_modifica_del_proclamatore_torna_alla_ricerca(): void
|
|
{
|
|
$mario = Proclamatore::create(['nome' => 'Mario', 'cognome' => 'Rossi', 'attivo' => true]);
|
|
|
|
Livewire::withQueryParams(['da' => '/proclamatori?search=Rossi'])
|
|
->actingAs($this->admin)
|
|
->test(ProclamatoreEdit::class, ['proclamatore' => $mario])
|
|
->set('nome', 'Mario Luigi')
|
|
->call('save')
|
|
->assertRedirect(url('/proclamatori?search=Rossi'));
|
|
}
|
|
|
|
// ─── Annulla e "Torna indietro" ─────────────────────────────
|
|
|
|
public function test_annulla_e_torna_indietro_portano_alla_pagina_di_partenza(): void
|
|
{
|
|
$assegnazione = $this->assegnazioneAperta();
|
|
$partenza = '/territori?search=35';
|
|
|
|
$this->actingAs($this->admin)
|
|
->get(route('assegnazioni.rientra', $assegnazione) . '?da=' . urlencode($partenza))
|
|
->assertOk()
|
|
->assertSee('Torna indietro')
|
|
->assertSee('href="' . e(url($partenza)) . '"', false);
|
|
}
|
|
|
|
public function test_senza_partenza_le_etichette_restano_quelle_di_prima(): void
|
|
{
|
|
$assegnazione = $this->assegnazioneAperta();
|
|
|
|
$this->actingAs($this->admin)
|
|
->get(route('assegnazioni.rientra', $assegnazione))
|
|
->assertOk()
|
|
->assertSee('Torna al territorio')
|
|
->assertDontSee('Torna indietro');
|
|
}
|
|
|
|
// ─── Gli elenchi ricordano filtri e ordinamento ─────────────
|
|
|
|
public function test_l_elenco_territori_legge_filtri_e_ordinamento_dall_indirizzo(): void
|
|
{
|
|
Livewire::withQueryParams(['search' => '35', 'filterStato' => 'assegnato', 'sortField' => 'zona', 'sortDirection' => 'desc'])
|
|
->actingAs($this->admin)
|
|
->test(TerritorioIndex::class)
|
|
->assertSet('search', '35')
|
|
->assertSet('filterStato', 'assegnato')
|
|
->assertSet('sortField', 'zona')
|
|
->assertSet('sortDirection', 'desc');
|
|
}
|
|
|
|
public function test_l_elenco_proclamatori_legge_la_ricerca_dall_indirizzo(): void
|
|
{
|
|
Livewire::withQueryParams(['search' => 'Rossi', 'filtroStato' => 'attivi'])
|
|
->actingAs($this->admin)
|
|
->test(ProclamatoreIndex::class)
|
|
->assertSet('search', 'Rossi')
|
|
->assertSet('filtroStato', 'attivi');
|
|
}
|
|
|
|
public function test_i_link_verso_schede_e_operazioni_portano_il_ritorno(): void
|
|
{
|
|
Territorio::create(['numero' => '35', 'attivo' => true]);
|
|
|
|
$html = $this->actingAs($this->admin)->get(route('territori.index'))->assertOk()->getContent();
|
|
|
|
// Il link alla scheda è marcato: il JS gli aggiunge ?da= al momento del clic.
|
|
$this->assertMatchesRegularExpression('/<a\b(?=[^>]*\bdata-ritorno\b)(?=[^>]*href="[^"]*\/territori\/\d+")[^>]*>/s', $html);
|
|
}
|
|
}
|