'Polygon', 'coordinates' => [[[13.35, 38.11], [13.37, 38.11], [13.37, 38.13], [13.35, 38.11]]], ]; protected function setUp(): void { parent::setUp(); $this->withoutVite(); Storage::fake('public'); Storage::fake('local'); config(['piantine.formato' => 'jpeg']); // Un JPEG vero: FPDF lo legge davvero quando compone il PDF. $immagine = imagecreatetruecolor(80, 50); imagefilledrectangle($immagine, 0, 0, 79, 49, imagecolorallocate($immagine, 230, 230, 230)); ob_start(); imagejpeg($immagine); $jpeg = ob_get_clean(); imagedestroy($immagine); $this->jpeg = $jpeg; } private string $jpeg; private function rendererRisponde(): void { Http::fake(['*/render' => Http::response($this->jpeg)]); } public function test_l_anteprima_si_prepara_senza_toccare_territorio_ne_piantina(): void { [$territorio, $mappa] = $this->piantinaCollegata(); $servizio = app(PubblicazionePiantina::class); // In test la coda è sincrona: il job ha già lavorato al ritorno. $token = $servizio->avvia($mappa); $this->assertSame(PubblicazionePiantina::PRONTA, $servizio->stato($token)['stato']); $this->assertStringStartsWith('%PDF', file_get_contents($servizio->pdfAnteprima($token))); $this->assertNull($territorio->fresh()->pdf_path); $this->assertNull($mappa->fresh()->pubblicata_at); $this->assertNull($mappa->fresh()->image_path); $this->assertSame(TerritorioMappa::STATO_BOZZA, $mappa->fresh()->stato()); } public function test_il_pdf_dell_anteprima_si_vede_solo_con_il_token_giusto(): void { [, $mappa] = $this->piantinaCollegata(); $token = app(PubblicazionePiantina::class)->avvia($mappa); $this->actingAs($this->admin()) ->get(route('piantine.anteprima', $token)) ->assertOk() ->assertHeader('Content-Type', 'application/pdf'); $this->actingAs($this->admin()) ->get(route('piantine.anteprima', str_repeat('a', 40))) ->assertNotFound(); } public function test_la_conferma_sostituisce_il_pdf_e_archivia_il_precedente(): void { [$territorio, $mappa] = $this->piantinaCollegata(); Storage::disk('public')->put('territori-pdf/vecchio.pdf', '%PDF-vecchio'); $territorio->update(['pdf_path' => 'territori-pdf/vecchio.pdf']); $servizio = app(PubblicazionePiantina::class); $token = $servizio->avvia($mappa); $this->actingAs($this->admin()); $servizio->conferma($token); $territorio->refresh(); $mappa->refresh(); $this->assertStringStartsWith('territori-pdf/piantina-' . $territorio->id . '-', $territorio->pdf_path); Storage::disk('public')->assertExists($territorio->pdf_path); $this->assertSame(1, TerritorioPdfVersione::where('territorio_id', $territorio->id)->count()); $this->assertNotNull($mappa->image_path); Storage::disk('public')->assertExists($mappa->image_path); $this->assertSame(TerritorioMappa::STATO_PUBBLICATA, $mappa->stato()); $this->assertSame($mappa->geojson, $mappa->geojson_pubblicato); // L'anteprima confermata non resta in giro. $this->assertNull($servizio->stato($token)); $this->assertSame([], Storage::disk('local')->files('piantine-anteprime')); } public function test_se_la_piantina_cambia_dopo_l_anteprima_la_conferma_viene_rifiutata(): void { [$territorio, $mappa] = $this->piantinaCollegata(); $servizio = app(PubblicazionePiantina::class); $token = $servizio->avvia($mappa); // I confini sono stampati sulla cartolina: cambiarli rende vecchia l'anteprima. $territorio->update(['confini' => 'Nord: via Nuova']); try { $servizio->conferma($token); $this->fail('La conferma doveva essere rifiutata.'); } catch (RuntimeException $e) { $this->assertStringContainsString('cambiat', $e->getMessage()); } $this->assertNull($territorio->fresh()->pdf_path); $this->assertNull($mappa->fresh()->pubblicata_at); } public function test_una_piantina_scollegata_non_si_pubblica(): void { $mappa = TerritorioMappa::create(['geojson' => json_encode(self::GEOMETRIA)]); $this->expectException(RuntimeException::class); app(PubblicazionePiantina::class)->avvia($mappa); } public function test_un_renderer_che_non_risponde_lascia_un_errore_leggibile(): void { Http::fake(['*/render' => Http::response(['error' => 'area troppo estesa'], 413)]); [, $mappa] = $this->piantinaCollegata(renderer: false); $servizio = app(PubblicazionePiantina::class); $token = $servizio->avvia($mappa); $stato = $servizio->stato($token); $this->assertSame(PubblicazionePiantina::ERRORE, $stato['stato']); $this->assertStringContainsString('area troppo estesa', $stato['messaggio']); $this->assertNull($servizio->pdfAnteprima($token)); } public function test_annullare_butta_l_anteprima(): void { [, $mappa] = $this->piantinaCollegata(); $servizio = app(PubblicazionePiantina::class); $token = $servizio->avvia($mappa); $servizio->annulla($token); $this->assertNull($servizio->stato($token)); $this->assertSame([], Storage::disk('local')->files('piantine-anteprime')); } public function test_la_finestra_porta_dalla_richiesta_alla_conferma(): void { [$territorio, $mappa] = $this->piantinaCollegata(); Livewire::actingAs($this->admin()) ->test(Pubblicazione::class) ->dispatch('pubblica-piantina', mappaId: $mappa->id) ->assertSet('fase', PubblicazionePiantina::PRONTA) ->assertSee('Anteprima del PDF da pubblicare', false) ->call('conferma') ->assertSet('mappaId', null) ->assertDispatched('piantina-pubblicata', mappaId: $mappa->id); $this->assertSame(TerritorioMappa::STATO_PUBBLICATA, $mappa->fresh()->stato()); $this->assertNotNull($territorio->fresh()->pdf_path); } public function test_chiudere_la_finestra_non_pubblica_niente(): void { [$territorio, $mappa] = $this->piantinaCollegata(); Livewire::actingAs($this->admin()) ->test(Pubblicazione::class) ->dispatch('pubblica-piantina', mappaId: $mappa->id) ->call('chiudi') ->assertSet('mappaId', null); $this->assertNull($territorio->fresh()->pdf_path); $this->assertSame([], Storage::disk('local')->files('piantine-anteprime')); } // ─── Stati del modello ────────────────────────────────────────────────── public function test_dopo_la_pubblicazione_ogni_dato_stampato_riporta_la_piantina_da_pubblicare(): void { [$territorio, $mappa] = $this->piantinaCollegata(); $servizio = app(PubblicazionePiantina::class); $this->actingAs($this->admin()); $servizio->conferma($servizio->avvia($mappa)); $this->assertSame(TerritorioMappa::STATO_PUBBLICATA, $mappa->fresh()->stato()); $territorio->update(['zona_id' => Zona::create(['nome' => 'Altra', 'attivo' => true])->id]); $this->assertSame(TerritorioMappa::STATO_MODIFICATA, $mappa->fresh()->stato()); } public function test_un_pdf_sostituito_per_altre_vie_riporta_la_piantina_da_pubblicare(): void { [$territorio, $mappa] = $this->piantinaCollegata(); $servizio = app(PubblicazionePiantina::class); $this->actingAs($this->admin()); $servizio->conferma($servizio->avvia($mappa)); $territorio->update(['pdf_path' => 'territori-pdf/caricato-a-mano.pdf']); $this->assertSame(TerritorioMappa::STATO_MODIFICATA, $mappa->fresh()->stato()); } public function test_motivo_non_pubblicabile_dice_cosa_manca(): void { $senzaDisegno = TerritorioMappa::create(['geojson' => 'rotto']); $this->assertStringContainsString('Disegna', $senzaDisegno->motivoNonPubblicabile()); $scollegata = TerritorioMappa::create(['geojson' => json_encode(self::GEOMETRIA)]); $this->assertStringContainsString('Collega', $scollegata->motivoNonPubblicabile()); [$territorio, $mappa] = $this->piantinaCollegata(); $this->assertNull($mappa->motivoNonPubblicabile()); $territorio->delete(); $this->assertStringContainsString('cestino', $mappa->fresh()->motivoNonPubblicabile()); $this->assertSame('Terr. 7', $mappa->fresh()->etichetta()); } private function piantinaCollegata(bool $renderer = true): array { if ($renderer) { $this->rendererRisponde(); } $zona = Zona::firstOrCreate(['nome' => 'Centro'], ['attivo' => true]); $territorio = Territorio::create([ 'numero' => '7', 'attivo' => true, 'zona_id' => $zona->id, 'confini' => 'Nord: via Roma', ]); $mappa = TerritorioMappa::create([ 'territorio_id' => $territorio->id, 'geojson' => json_encode(self::GEOMETRIA), ]); return [$territorio, $mappa]; } private function admin(): User { Role::firstOrCreate(['name' => 'amministratore', 'guard_name' => 'web']); app(PermissionRegistrar::class)->forgetCachedPermissions(); Setting::firstOrCreate([], ['congregazione_nome' => 'Congregazione di prova']); $utente = User::firstOrCreate( ['email' => 'admin@example.test'], ['name' => 'Amministratore', 'password' => 'password-di-prova'], ); $utente->assignRole('amministratore'); return $utente; } }