Files
termanager2/tests/Feature/RitornoTest.php
Francesco Picone bc465f53f5 ++ dopo un'operazione si torna alla pagina di partenza, con i suoi filtri
- 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>
2026-10-19 15:04:42 +02:00

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);
}
}