++ fix e controlli
This commit is contained in:
195
tests/Feature/PaginaBackupImportTest.php
Normal file
195
tests/Feature/PaginaBackupImportTest.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Spatie\Permission\PermissionRegistrar;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* La pagina "Backup e import" servita per intero: rotta, permessi, layout e i
|
||||
* tre componenti Livewire annidati.
|
||||
*
|
||||
* Serve perché il grosso di questa pagina è markup, e il markup non fallisce
|
||||
* come il codice: una vista che non compila non rompe niente finché qualcuno non
|
||||
* la apre. È già successo — `@disabled(...)` dentro un tag <x-btn> non viene
|
||||
* compilato, il tag resta letterale nel PHP generato e la pagina muore con un
|
||||
* errore di sintassi. Qui quella classe di errori si vede subito.
|
||||
*
|
||||
* Quello che questi test NON possono coprire: Alpine e il comportamento della
|
||||
* console (apertura automatica, scorrimento, evidenziazione delle zone) girano
|
||||
* nel browser, e qui non c'è un browser. Vanno provati a mano.
|
||||
*/
|
||||
class PaginaBackupImportTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// L'immagine di test non contiene public/build: gli asset sono
|
||||
// compilati in uno stage a parte, che serve al runtime e non qui. Senza
|
||||
// questo, ogni pagina morirebbe su "Vite manifest not found" — un
|
||||
// fallimento che non parla del markup, cioe' l'unica cosa che questi
|
||||
// test guardano. Che la build degli asset funzioni lo dice `npm run
|
||||
// build`, non PHPUnit.
|
||||
$this->withoutVite();
|
||||
}
|
||||
|
||||
private function admin(): User
|
||||
{
|
||||
Role::findOr('amministratore', fn () => Role::create(['name' => 'amministratore', 'guard_name' => 'web']));
|
||||
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||
|
||||
$utente = User::create([
|
||||
'name' => 'Amministratore',
|
||||
'email' => 'admin@example.test',
|
||||
'password' => 'password-di-prova',
|
||||
]);
|
||||
$utente->assignRole('amministratore');
|
||||
|
||||
return $utente;
|
||||
}
|
||||
|
||||
public function test_la_pagina_si_apre_per_l_amministratore(): void
|
||||
{
|
||||
$this->actingAs($this->admin())
|
||||
->get(route('xml.exchange'))
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
public function test_chi_non_e_amministratore_non_ci_entra(): void
|
||||
{
|
||||
$utente = User::create([
|
||||
'name' => 'Assistente',
|
||||
'email' => 'assistente@example.test',
|
||||
'password' => 'password-di-prova',
|
||||
]);
|
||||
|
||||
$this->actingAs($utente)
|
||||
->get(route('xml.exchange'))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Le cinque zone esistono e sono raggiungibili per ancora: l'indice in cima
|
||||
* alla pagina ci salta sopra, e un id sbagliato lo renderebbe un pulsante
|
||||
* che non fa niente.
|
||||
*/
|
||||
public function test_ci_sono_tutte_e_cinque_le_zone_con_la_loro_ancora(): void
|
||||
{
|
||||
$risposta = $this->actingAs($this->admin())->get(route('xml.exchange'));
|
||||
|
||||
foreach (['zona-backup', 'zona-ripristino', 'zona-pdf', 'zona-xml', 'zona-azzeramento'] as $zona) {
|
||||
$risposta->assertSee('id="' . $zona . '"', false);
|
||||
$risposta->assertSee('tmFocusZona(\'' . $zona . '\'', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* La zona pericolosa è l'ultima. È il motivo per cui l'azzeramento è stato
|
||||
* estratto in un componente suo: reso da BackupManager finiva a metà pagina,
|
||||
* fra il ripristino e l'import, che è l'ultimo posto in cui si vuole trovare
|
||||
* un pulsante che cancella tutto.
|
||||
*/
|
||||
public function test_la_zona_pericolosa_e_l_ultima_della_pagina(): void
|
||||
{
|
||||
$html = $this->actingAs($this->admin())->get(route('xml.exchange'))->getContent();
|
||||
|
||||
$posizioni = [];
|
||||
foreach (['zona-backup', 'zona-ripristino', 'zona-pdf', 'zona-xml', 'zona-azzeramento'] as $zona) {
|
||||
$posizioni[$zona] = strpos($html, 'id="' . $zona . '"');
|
||||
$this->assertNotFalse($posizioni[$zona], "Zona {$zona} assente dalla pagina.");
|
||||
}
|
||||
|
||||
$this->assertSame(
|
||||
['zona-backup', 'zona-ripristino', 'zona-pdf', 'zona-xml', 'zona-azzeramento'],
|
||||
array_keys($posizioni),
|
||||
'Ordine atteso delle chiavi.'
|
||||
);
|
||||
|
||||
$precedente = -1;
|
||||
foreach ($posizioni as $zona => $posizione) {
|
||||
$this->assertGreaterThan($precedente, $posizione, "La zona {$zona} è fuori ordine.");
|
||||
$precedente = $posizione;
|
||||
}
|
||||
}
|
||||
|
||||
public function test_la_console_unica_e_nella_pagina(): void
|
||||
{
|
||||
$risposta = $this->actingAs($this->admin())->get(route('xml.exchange'));
|
||||
|
||||
$risposta->assertSee('tmConsoleOperazioni', false);
|
||||
$risposta->assertSee('class="tm-console"', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ordine di caricamento, che è il motivo per cui quel JavaScript sta in uno
|
||||
* <script> nella pagina e non in resources/js/app.js.
|
||||
*
|
||||
* Alpine arriva col pacchetto di Livewire, in fondo al body, e valuta
|
||||
* x-data="tmConsoleOperazioni()" quando parte: se la funzione non fosse
|
||||
* ancora definita, la console sarebbe un riquadro morto. Il bundle di app.js
|
||||
* non andrebbe bene perché è un modulo ES, che il browser rimanda a dopo il
|
||||
* parsing del documento — cioè dopo Alpine.
|
||||
*
|
||||
* Il rapporto fra i due è invisibile guardando i file: si vede solo qui.
|
||||
*/
|
||||
public function test_la_console_e_definita_prima_che_alpine_parta(): void
|
||||
{
|
||||
$html = $this->actingAs($this->admin())->get(route('xml.exchange'))->getContent();
|
||||
|
||||
$definizione = strpos($html, 'window.tmConsoleOperazioni =');
|
||||
$livewire = strpos($html, 'livewire.js');
|
||||
|
||||
$this->assertNotFalse($definizione, 'La definizione della console non è nella pagina.');
|
||||
$this->assertNotFalse($livewire, 'Il pacchetto di Livewire non è nella pagina.');
|
||||
$this->assertLessThan(
|
||||
$livewire,
|
||||
$definizione,
|
||||
'La console va definita prima del pacchetto che avvia Alpine, altrimenti x-data non la trova.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* I cinque riquadri di log separati sono spariti: se ne torna uno, la pagina
|
||||
* ricomincia a raccontare la stessa operazione in due punti diversi.
|
||||
*/
|
||||
public function test_non_sono_rimasti_riquadri_di_log_separati(): void
|
||||
{
|
||||
$risposta = $this->actingAs($this->admin())->get(route('xml.exchange'));
|
||||
|
||||
$risposta->assertDontSee('Console upload');
|
||||
$risposta->assertDontSee('Log import PDF');
|
||||
}
|
||||
|
||||
/**
|
||||
* Il difetto che questo test presidia: se un tag di componente non viene
|
||||
* compilato, resta nella pagina come testo. Non solleva, non rompe il
|
||||
* layout in modo evidente — semplicemente il pulsante non c'è.
|
||||
*/
|
||||
public function test_nessun_tag_di_componente_e_rimasto_da_compilare(): void
|
||||
{
|
||||
$html = $this->actingAs($this->admin())->get(route('xml.exchange'))->getContent();
|
||||
|
||||
$this->assertStringNotContainsString('<x-btn', $html);
|
||||
$this->assertStringNotContainsString('</x-btn>', $html);
|
||||
}
|
||||
|
||||
/**
|
||||
* I pulsanti passano tutti dal sistema unico. Un `style=` inline su un
|
||||
* pulsante è il segnale che qualcuno è tornato a definirne uno per conto suo,
|
||||
* senza stato di focus.
|
||||
*/
|
||||
public function test_i_pulsanti_usano_le_classi_del_sistema_unico(): void
|
||||
{
|
||||
$html = $this->actingAs($this->admin())->get(route('xml.exchange'))->getContent();
|
||||
|
||||
foreach (['tm-btn tm-btn-primary', 'tm-btn tm-btn-danger', 'tm-btn tm-btn-secondary'] as $classe) {
|
||||
$this->assertStringContainsString($classe, $html, "Manca un pulsante {$classe}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user