feature test su institution

This commit is contained in:
Giuseppe Naponiello
2026-06-22 22:14:15 +02:00
parent cc4e174880
commit fe73662903
39 changed files with 2432 additions and 1 deletions

View File

@@ -0,0 +1,168 @@
<?php
namespace Tests\Feature\Etl;
use App\Etl\Importers\InstitutionImporter;
use App\Models\Institution;
use Database\Seeders\InstitutionCategorySeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\Concerns\CreatesLegacyDatabase;
use Tests\TestCase;
class InstitutionImporterTest extends TestCase
{
use CreatesLegacyDatabase;
use RefreshDatabase;
/** Categorie v2 con gli id legacy fissi (2,3,4,6). */
private function seedV2Categories(): void
{
$this->seed(InstitutionCategorySeeder::class);
}
public function test_it_imports_an_institution_and_creates_the_official_link(): void
{
$this->seedV2Categories();
$this->fakeLegacyConnection();
$this->insertLegacyInstitution([
'id' => 1,
'category' => 3,
'name' => 'Blekinge Museum',
'abbreviation' => 'BLM',
'city' => 'Karlskrona',
'url' => 'https://blekingemuseum.se/',
]);
$summary = (new InstitutionImporter)->import(false);
$this->assertSame(1, $summary->created);
$this->assertDatabaseHas('institutions', [
'legacy_id' => 1,
'category_id' => 3,
'name' => 'Blekinge Museum',
'city' => 'Karlskrona',
]);
$institution = Institution::where('legacy_id', 1)->firstOrFail();
$this->assertNotEmpty($institution->uuid);
$this->assertDatabaseHas('institution_links', [
'institution_id' => $institution->id,
'type' => 'official',
'url' => 'https://blekingemuseum.se/',
]);
}
public function test_it_creates_no_link_when_the_url_is_blank(): void
{
$this->seedV2Categories();
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 21, 'url' => ' ']);
(new InstitutionImporter)->import(false);
$this->assertDatabaseCount('institution_links', 0);
}
public function test_it_trims_textual_fields(): void
{
$this->seedV2Categories();
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 20, 'name' => 'Lund University Library ']);
(new InstitutionImporter)->import(false);
$this->assertDatabaseHas('institutions', ['legacy_id' => 20, 'name' => 'Lund University Library']);
}
public function test_it_falls_back_to_the_default_color_when_legacy_color_is_blank(): void
{
$this->seedV2Categories();
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 1, 'color' => null]);
(new InstitutionImporter)->import(false);
$this->assertDatabaseHas('institutions', ['legacy_id' => 1, 'color' => '#c5cae9']);
}
public function test_it_skips_institutions_with_an_unknown_category(): void
{
$this->seedV2Categories();
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 99, 'category' => 999]);
$summary = (new InstitutionImporter)->import(false);
$this->assertSame(1, $summary->skipped);
$this->assertNotEmpty($summary->warnings);
$this->assertDatabaseMissing('institutions', ['legacy_id' => 99]);
}
public function test_it_regenerates_the_uuid_instead_of_copying_the_legacy_one(): void
{
$this->seedV2Categories();
$this->fakeLegacyConnection();
$legacyUuid = '00000000-0000-0000-0000-000000000000';
$this->insertLegacyInstitution(['id' => 1, 'uuid' => $legacyUuid]);
(new InstitutionImporter)->import(false);
$this->assertNotSame($legacyUuid, Institution::where('legacy_id', 1)->value('uuid'));
}
public function test_it_is_idempotent_and_keeps_the_uuid_stable(): void
{
$this->seedV2Categories();
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 1]);
$first = (new InstitutionImporter)->import(false);
$uuid = Institution::where('legacy_id', 1)->value('uuid');
$second = (new InstitutionImporter)->import(false);
$this->assertSame(1, $first->created);
$this->assertSame(0, $second->created);
$this->assertSame(1, $second->updated);
$this->assertDatabaseCount('institutions', 1);
$this->assertSame($uuid, Institution::where('legacy_id', 1)->value('uuid'));
}
public function test_dry_run_writes_nothing(): void
{
$this->seedV2Categories();
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 1]);
$summary = (new InstitutionImporter)->import(true);
$this->assertSame(1, $summary->created);
$this->assertDatabaseCount('institutions', 0);
}
public function test_dry_run_counts_an_existing_institution_as_updated(): void
{
$this->seedV2Categories();
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 1]);
(new InstitutionImporter)->import(false);
$summary = (new InstitutionImporter)->import(true);
$this->assertSame(0, $summary->created);
$this->assertSame(1, $summary->updated);
$this->assertDatabaseCount('institutions', 1);
}
public function test_it_warns_and_skips_when_the_v2_lookup_is_empty(): void
{
// Nessun seed delle categorie v2.
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 1]);
$summary = (new InstitutionImporter)->import(false);
$this->assertNotEmpty($summary->warnings);
$this->assertSame(0, $summary->total());
$this->assertDatabaseCount('institutions', 0);
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace Tests\Feature\Etl;
use Database\Seeders\InstitutionCategorySeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\Concerns\CreatesLegacyDatabase;
use Tests\TestCase;
class V1ImportCommandTest extends TestCase
{
use CreatesLegacyDatabase;
use RefreshDatabase;
public function test_it_imports_and_reports_counts(): void
{
$this->seed(InstitutionCategorySeeder::class);
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 1]);
$this->artisan('v1:import')
->expectsOutputToContain('created 1, updated 0, skipped 0')
->assertSuccessful();
$this->assertDatabaseCount('institutions', 1);
}
public function test_dry_run_writes_nothing(): void
{
$this->seed(InstitutionCategorySeeder::class);
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 1]);
$this->artisan('v1:import --dry-run')
->expectsOutputToContain('DRY-RUN')
->assertSuccessful();
$this->assertDatabaseCount('institutions', 0);
}
public function test_only_filter_skips_unmatched_importers(): void
{
$this->seed(InstitutionCategorySeeder::class);
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 1]);
$this->artisan('v1:import --only=nonexistent')->assertSuccessful();
$this->assertDatabaseCount('institutions', 0);
}
public function test_it_prints_importer_warnings(): void
{
$this->seed(InstitutionCategorySeeder::class);
$this->fakeLegacyConnection();
$this->insertLegacyInstitution(['id' => 99, 'category' => 999]);
$this->artisan('v1:import')
->expectsOutputToContain('category 999')
->assertSuccessful();
}
public function test_it_fails_when_an_importer_throws(): void
{
// Connessione raggiungibile (getPdo ok) ma senza la tabella `institution`:
// l'import lancia, il comando intercetta e fallisce.
config()->set('database.connections.legacy', [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
]);
DB::purge('legacy');
$this->seed(InstitutionCategorySeeder::class);
$this->artisan('v1:import')
->expectsOutputToContain('failed')
->assertFailed();
}
public function test_it_fails_when_the_legacy_connection_is_unavailable(): void
{
config()->set('database.connections.legacy', [
'driver' => 'sqlite',
'database' => '/nonexistent/path/legacy.sqlite',
'prefix' => '',
]);
DB::purge('legacy');
$this->artisan('v1:import')
->expectsOutputToContain('Legacy connection unavailable')
->assertFailed();
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace Tests\Feature;
use App\Models\Institution;
use App\Models\Lists\InstitutionCategory;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class InstitutionCategoryControllerTest extends TestCase
{
use RefreshDatabase;
// --- Lettura (tier.app) --------------------------------------------------
public function test_index_lists_categories(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
InstitutionCategory::factory()->count(2)->create();
$this->getJson('/api/institution-categories')
->assertOk()
->assertJsonStructure(['message', 'data' => [['id', 'value']]])
->assertJsonCount(2, 'data');
}
public function test_show_returns_a_single_category(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$category = InstitutionCategory::factory()->create();
$this->getJson("/api/institution-categories/{$category->id}")
->assertOk()
->assertJsonPath('data.id', $category->id);
}
public function test_usage_reflects_whether_the_category_is_used(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$free = InstitutionCategory::factory()->create();
$used = InstitutionCategory::factory()->create();
Institution::factory()->create(['category_id' => $used->id]);
$this->getJson("/api/institution-categories/{$free->id}/usage")->assertJsonPath('in_use', false);
$this->getJson("/api/institution-categories/{$used->id}/usage")->assertJsonPath('in_use', true);
}
// --- Scrittura (tier.admin) ---------------------------------------------
public function test_admin_can_create_a_category(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$this->postJson('/api/institution-categories', ['value' => 'gallery'])
->assertCreated()
->assertJsonPath('data.value', 'gallery');
$this->assertDatabaseHas('institution_categories', ['value' => 'gallery']);
}
public function test_create_rejects_a_duplicate_value(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
InstitutionCategory::factory()->create(['value' => 'gallery']);
$this->postJson('/api/institution-categories', ['value' => 'gallery'])
->assertStatus(422)
->assertJsonValidationErrors('value');
}
public function test_admin_can_update_a_category(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$category = InstitutionCategory::factory()->create();
$this->putJson("/api/institution-categories/{$category->id}", ['value' => 'archive'])
->assertOk()
->assertJsonPath('data.value', 'archive');
}
public function test_cannot_delete_a_category_in_use(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$category = InstitutionCategory::factory()->create();
Institution::factory()->create(['category_id' => $category->id]);
$this->deleteJson("/api/institution-categories/{$category->id}")
->assertStatus(409)
->assertJsonPath('in_use', true);
$this->assertDatabaseHas('institution_categories', ['id' => $category->id]);
}
public function test_admin_can_delete_a_free_category(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$category = InstitutionCategory::factory()->create();
$this->deleteJson("/api/institution-categories/{$category->id}")->assertOk();
$this->assertDatabaseMissing('institution_categories', ['id' => $category->id]);
}
public function test_a_non_admin_cannot_write(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$this->postJson('/api/institution-categories', ['value' => 'x'])->assertForbidden();
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Tests\Feature;
use App\Models\Lists\InstitutionCategory;
use Database\Seeders\InstitutionCategorySeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class InstitutionCategorySeederTest extends TestCase
{
use RefreshDatabase;
public function test_it_seeds_the_categories_with_fixed_legacy_ids(): void
{
$this->seed(InstitutionCategorySeeder::class);
$this->assertSame(4, InstitutionCategory::count());
$this->assertSame('library', InstitutionCategory::find(2)?->value);
$this->assertSame('museum', InstitutionCategory::find(3)?->value);
$this->assertSame('public administration', InstitutionCategory::find(4)?->value);
$this->assertSame('research institute', InstitutionCategory::find(6)?->value);
}
public function test_it_excludes_uncategorized_and_the_gap_ids(): void
{
$this->seed(InstitutionCategorySeeder::class);
$this->assertNull(InstitutionCategory::find(1));
$this->assertNull(InstitutionCategory::find(5));
}
public function test_it_is_idempotent(): void
{
$this->seed(InstitutionCategorySeeder::class);
$this->seed(InstitutionCategorySeeder::class);
$this->assertSame(4, InstitutionCategory::count());
}
}

View File

@@ -0,0 +1,231 @@
<?php
namespace Tests\Feature;
use App\Models\Institution;
use App\Models\InstitutionLink;
use App\Models\Lists\InstitutionCategory;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class InstitutionControllerTest extends TestCase
{
use RefreshDatabase;
/**
* @param array<string, mixed> $overrides
* @return array<string, mixed>
*/
private function validPayload(array $overrides = []): array
{
return array_merge([
'category_id' => InstitutionCategory::factory()->create()->id,
'name' => 'Test Museum',
'abbreviation' => 'TM',
'address' => 'Some Road 1',
'city' => 'Lund',
'lat' => 55.7,
'lon' => 13.19,
'color' => '#ffffff',
'is_storage_place' => true,
'logo' => UploadedFile::fake()->image('logo.png'),
], $overrides);
}
// --- Lettura (tier.app) --------------------------------------------------
public function test_index_lists_institutions_for_an_operational_user(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
Institution::factory()->count(2)->create();
$this->getJson('/api/institutions')
->assertOk()
->assertJsonStructure(['message', 'data', 'meta' => ['current_page', 'total']])
->assertJsonCount(2, 'data');
}
public function test_index_filters_by_category_and_search(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$category = InstitutionCategory::factory()->create();
Institution::factory()->create(['category_id' => $category->id, 'name' => 'Blekinge Museum']);
Institution::factory()->create(['name' => 'Other Place']);
$this->getJson("/api/institutions?category_id={$category->id}")
->assertOk()
->assertJsonCount(1, 'data')
->assertJsonPath('data.0.name', 'Blekinge Museum');
$this->getJson('/api/institutions?search=Blekinge')
->assertOk()
->assertJsonCount(1, 'data');
}
public function test_index_can_list_only_trashed(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$trashed = Institution::factory()->create();
Institution::factory()->create();
$trashed->delete();
$this->getJson('/api/institutions')->assertJsonCount(1, 'data');
$this->getJson('/api/institutions?trashed=only')
->assertOk()
->assertJsonCount(1, 'data')
->assertJsonPath('data.0.id', $trashed->id);
$this->getJson('/api/institutions?trashed=with')->assertJsonCount(2, 'data');
}
public function test_show_returns_institution_with_category_and_links(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$institution = Institution::factory()->create();
InstitutionLink::factory()->create(['institution_id' => $institution->id]);
$this->getJson("/api/institutions/{$institution->uuid}")
->assertOk()
->assertJsonPath('data.uuid', $institution->uuid)
->assertJsonStructure(['data' => ['category', 'links']]);
}
public function test_show_resolves_by_uuid_not_id(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$institution = Institution::factory()->create();
// L'id interno non è una route key valida.
$this->getJson("/api/institutions/{$institution->id}")->assertNotFound();
}
// --- Scrittura (tier.admin) ---------------------------------------------
public function test_admin_can_create_an_institution_with_a_logo(): void
{
Storage::fake('public');
$this->actingAs($this->adminUser(), 'sanctum');
$this->post('/api/institutions', $this->validPayload(), ['Accept' => 'application/json'])
->assertCreated()
->assertJsonPath('data.name', 'Test Museum')
->assertJsonStructure(['data' => ['uuid', 'category']]);
$institution = Institution::firstWhere('name', 'Test Museum');
$this->assertNotNull($institution);
$this->assertNotEmpty($institution->uuid);
Storage::disk('public')->assertExists($institution->logo);
}
public function test_create_applies_default_color_and_storage_flag(): void
{
Storage::fake('public');
$this->actingAs($this->adminUser(), 'sanctum');
$payload = $this->validPayload();
unset($payload['color'], $payload['is_storage_place']);
$this->post('/api/institutions', $payload, ['Accept' => 'application/json'])->assertCreated();
$this->assertDatabaseHas('institutions', [
'name' => 'Test Museum',
'color' => '#c5cae9',
'is_storage_place' => true,
]);
}
public function test_create_validates_required_fields(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$this->postJson('/api/institutions', [])
->assertStatus(422)
->assertJsonValidationErrors(['category_id', 'name', 'abbreviation', 'lat', 'lon', 'logo']);
}
public function test_admin_can_update_an_institution_keeping_the_logo(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$institution = Institution::factory()->create(['logo' => 'institution_logo/keep.jpg', 'name' => 'Old']);
$payload = $this->validPayload(['name' => 'New Name', 'category_id' => $institution->category_id]);
unset($payload['logo']);
$this->put("/api/institutions/{$institution->uuid}", $payload, ['Accept' => 'application/json'])
->assertOk()
->assertJsonPath('data.name', 'New Name');
$this->assertSame('institution_logo/keep.jpg', $institution->fresh()->logo);
}
public function test_update_replaces_the_logo_when_a_new_one_is_uploaded(): void
{
Storage::fake('public');
$this->actingAs($this->adminUser(), 'sanctum');
Storage::disk('public')->put('institution_logo/old.jpg', 'x');
$institution = Institution::factory()->create(['logo' => 'institution_logo/old.jpg']);
$payload = $this->validPayload(['category_id' => $institution->category_id]);
$this->put("/api/institutions/{$institution->uuid}", $payload, ['Accept' => 'application/json'])->assertOk();
Storage::disk('public')->assertMissing('institution_logo/old.jpg');
Storage::disk('public')->assertExists($institution->fresh()->logo);
}
public function test_admin_can_soft_delete_an_institution(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$institution = Institution::factory()->create();
$this->deleteJson("/api/institutions/{$institution->uuid}")->assertOk();
$this->assertSoftDeleted($institution);
}
public function test_admin_can_restore_a_trashed_institution(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$institution = Institution::factory()->create();
$institution->delete();
$this->postJson("/api/institutions/{$institution->uuid}/restore")
->assertOk()
->assertJsonPath('data.uuid', $institution->uuid);
$this->assertNotSoftDeleted($institution);
}
public function test_admin_can_force_delete_an_institution_and_its_logo_and_links(): void
{
Storage::fake('public');
$this->actingAs($this->adminUser(), 'sanctum');
Storage::disk('public')->put('institution_logo/gone.jpg', 'x');
$institution = Institution::factory()->create(['logo' => 'institution_logo/gone.jpg']);
$link = InstitutionLink::factory()->create(['institution_id' => $institution->id]);
$institution->delete();
$this->deleteJson("/api/institutions/{$institution->uuid}/force")->assertOk();
$this->assertDatabaseMissing('institutions', ['id' => $institution->id]);
$this->assertDatabaseMissing('institution_links', ['id' => $link->id]);
Storage::disk('public')->assertMissing('institution_logo/gone.jpg');
}
// --- Autorizzazione ------------------------------------------------------
public function test_a_non_admin_cannot_write(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$institution = Institution::factory()->create();
$this->postJson('/api/institutions', [])->assertForbidden();
$this->deleteJson("/api/institutions/{$institution->uuid}")->assertForbidden();
}
public function test_guests_cannot_access_institutions(): void
{
$this->getJson('/api/institutions')->assertUnauthorized();
}
}

View File

@@ -0,0 +1,149 @@
<?php
namespace Tests\Feature;
use App\Enums\InstitutionLinkType;
use App\Models\Institution;
use App\Models\InstitutionLink;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class InstitutionLinkControllerTest extends TestCase
{
use RefreshDatabase;
/**
* @param array<string, mixed> $overrides
* @return array<string, mixed>
*/
private function validPayload(array $overrides = []): array
{
return array_merge([
'url' => 'https://example.org',
'type' => InstitutionLinkType::Official->value,
'label' => 'Official site',
'sort_order' => 1,
], $overrides);
}
// --- Lettura (tier.app) --------------------------------------------------
public function test_index_lists_links_of_an_institution_ordered(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$institution = Institution::factory()->create();
$second = InstitutionLink::factory()->create(['institution_id' => $institution->id, 'sort_order' => 2]);
$first = InstitutionLink::factory()->create(['institution_id' => $institution->id, 'sort_order' => 1]);
$this->getJson("/api/institutions/{$institution->uuid}/links")
->assertOk()
->assertJsonCount(2, 'data')
->assertJsonPath('data.0.id', $first->id)
->assertJsonPath('data.1.id', $second->id);
}
public function test_show_returns_a_single_link(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$institution = Institution::factory()->create();
$link = InstitutionLink::factory()->create(['institution_id' => $institution->id]);
$this->getJson("/api/institutions/{$institution->uuid}/links/{$link->id}")
->assertOk()
->assertJsonPath('data.id', $link->id);
}
public function test_show_returns_not_found_when_the_link_belongs_to_another_institution(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$institution = Institution::factory()->create();
$otherInstitution = Institution::factory()->create();
$link = InstitutionLink::factory()->create(['institution_id' => $otherInstitution->id]);
$this->getJson("/api/institutions/{$institution->uuid}/links/{$link->id}")->assertNotFound();
}
// --- Scrittura (tier.admin) ---------------------------------------------
public function test_admin_can_add_a_link_to_an_institution(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$institution = Institution::factory()->create();
$this->postJson("/api/institutions/{$institution->uuid}/links", $this->validPayload())
->assertCreated()
->assertJsonPath('data.url', 'https://example.org')
->assertJsonPath('data.institution_id', $institution->id);
$this->assertDatabaseHas('institution_links', [
'institution_id' => $institution->id,
'url' => 'https://example.org',
]);
}
public function test_store_defaults_sort_order_to_zero_when_missing(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$institution = Institution::factory()->create();
$payload = $this->validPayload();
unset($payload['sort_order']);
$this->postJson("/api/institutions/{$institution->uuid}/links", $payload)
->assertCreated()
->assertJsonPath('data.sort_order', 0);
}
public function test_store_validates_required_fields(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$institution = Institution::factory()->create();
$this->postJson("/api/institutions/{$institution->uuid}/links", [])
->assertStatus(422)
->assertJsonValidationErrors(['url', 'type']);
}
public function test_admin_can_update_a_link(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$institution = Institution::factory()->create();
$link = InstitutionLink::factory()->create(['institution_id' => $institution->id]);
$this->putJson(
"/api/institutions/{$institution->uuid}/links/{$link->id}",
$this->validPayload(['url' => 'https://updated.example.org'])
)
->assertOk()
->assertJsonPath('data.url', 'https://updated.example.org');
$this->assertSame('https://updated.example.org', $link->fresh()->url);
}
public function test_admin_can_delete_a_link(): void
{
$this->actingAs($this->adminUser(), 'sanctum');
$institution = Institution::factory()->create();
$link = InstitutionLink::factory()->create(['institution_id' => $institution->id]);
$this->deleteJson("/api/institutions/{$institution->uuid}/links/{$link->id}")->assertOk();
$this->assertDatabaseMissing('institution_links', ['id' => $link->id]);
}
// --- Autorizzazione ------------------------------------------------------
public function test_a_non_admin_cannot_write(): void
{
$this->actingAs($this->operationalUser(), 'sanctum');
$institution = Institution::factory()->create();
$this->postJson("/api/institutions/{$institution->uuid}/links", $this->validPayload())->assertForbidden();
}
public function test_guests_cannot_access_links(): void
{
$institution = Institution::factory()->create();
$this->getJson("/api/institutions/{$institution->uuid}/links")->assertUnauthorized();
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Tests\Feature\Models;
use App\Enums\InstitutionLinkType;
use App\Models\Institution;
use App\Models\InstitutionLink;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class InstitutionLinkTest extends TestCase
{
use RefreshDatabase;
public function test_type_is_cast_to_enum(): void
{
$link = InstitutionLink::factory()->create(['type' => InstitutionLinkType::Ticketing]);
$this->assertInstanceOf(InstitutionLinkType::class, $link->fresh()->type);
$this->assertSame(InstitutionLinkType::Ticketing, $link->fresh()->type);
}
public function test_it_belongs_to_an_institution(): void
{
$institution = Institution::factory()->create();
$link = InstitutionLink::factory()->create(['institution_id' => $institution->id]);
$this->assertTrue($link->institution->is($institution));
}
}

View File

@@ -0,0 +1,99 @@
<?php
namespace Tests\Feature\Models;
use App\Models\Institution;
use App\Models\InstitutionLink;
use App\Models\Lists\InstitutionCategory;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Str;
use Tests\TestCase;
class InstitutionTest extends TestCase
{
use RefreshDatabase;
public function test_uuid_is_generated_on_create(): void
{
$institution = Institution::factory()->create();
$this->assertNotEmpty($institution->uuid);
$this->assertSame(36, strlen((string) $institution->uuid));
}
public function test_two_institutions_get_distinct_uuids(): void
{
$a = Institution::factory()->create();
$b = Institution::factory()->create();
$this->assertNotSame($a->uuid, $b->uuid);
}
public function test_a_provided_uuid_is_not_overwritten(): void
{
$uuid = (string) Str::uuid();
$institution = Institution::factory()->make();
$institution->uuid = $uuid;
$institution->save();
$this->assertSame($uuid, $institution->fresh()->uuid);
}
public function test_route_key_is_the_uuid(): void
{
$this->assertSame('uuid', (new Institution)->getRouteKeyName());
}
public function test_attributes_are_cast(): void
{
$institution = Institution::factory()->create([
'is_storage_place' => 1,
'lat' => '55.700000',
'lon' => '13.190000',
'legacy_id' => '42',
]);
$fresh = $institution->fresh();
$this->assertIsBool($fresh->is_storage_place);
$this->assertIsFloat($fresh->lat);
$this->assertIsFloat($fresh->lon);
$this->assertSame(42, $fresh->legacy_id);
}
public function test_it_belongs_to_a_category(): void
{
$category = InstitutionCategory::factory()->create();
$institution = Institution::factory()->create(['category_id' => $category->id]);
$this->assertTrue($institution->category->is($category));
}
public function test_a_category_has_many_institutions(): void
{
$category = InstitutionCategory::factory()->create();
Institution::factory()->count(2)->create(['category_id' => $category->id]);
$this->assertCount(2, $category->institutions);
}
public function test_it_has_many_links(): void
{
$institution = Institution::factory()->create();
InstitutionLink::factory()->create(['institution_id' => $institution->id]);
$this->assertCount(1, $institution->refresh()->links);
}
public function test_it_is_soft_deleted(): void
{
$institution = Institution::factory()->create();
$institution->delete();
$this->assertSoftDeleted($institution);
$this->assertSame(0, Institution::count());
$this->assertSame(1, Institution::withTrashed()->count());
}
}