$ref, 'name' => 'P-'.$ref, 'address' => 'x', 'lat' => 40, 'lng' => -3, 'start_date' => now()->toDateString(), 'end_date_estimated' => now()->addMonth()->toDateString(), 'status' => 'in_progress', 'created_by' => $owner->id, ]); $p->users()->attach($owner->id, ['role_in_project' => 'supervisor']); return $p; } public function test_global_manager_requires_manage_templates(): void { Permission::findOrCreate('manage templates'); $user = User::factory()->create(); // sin permiso Livewire::actingAs($user) ->test(GlobalTemplateManager::class) ->assertForbidden(); } public function test_global_manager_creates_template_without_project(): void { Permission::findOrCreate('manage templates'); $admin = User::factory()->create(); $admin->givePermissionTo('manage templates'); Livewire::actingAs($admin) ->test(GlobalTemplateManager::class) ->call('newTemplate') ->set('form.name', 'Inspección obra') ->call('saveTemplate') ->assertHasNoErrors(); $this->assertDatabaseHas('inspection_templates', [ 'name' => 'Inspección obra', 'project_id' => null, ]); } public function test_picker_toggles_project_assignment(): void { Permission::findOrCreate('edit projects'); $user = User::factory()->create(); $user->givePermissionTo('edit projects'); $project = $this->project($user); $tpl = InspectionTemplate::create(['name' => 'Recep', 'fields' => []]); Livewire::actingAs($user) ->test(ProjectTemplatesPicker::class, ['project' => $project]) ->call('toggle', $tpl->id); $this->assertTrue($project->fresh()->inspectionTemplates()->where('inspection_templates.id', $tpl->id)->exists()); // Toggle de nuevo → desasigna Livewire::actingAs($user) ->test(ProjectTemplatesPicker::class, ['project' => $project]) ->call('toggle', $tpl->id); $this->assertFalse($project->fresh()->inspectionTemplates()->where('inspection_templates.id', $tpl->id)->exists()); } public function test_templates_table_lists_and_requires_permission(): void { Permission::findOrCreate('manage templates'); InspectionTemplate::create(['name' => 'Recepción acero', 'fields' => []]); // Sin permiso → 403 $weak = User::factory()->create(); Livewire::actingAs($weak) ->test(InspectionTemplatesTable::class) ->assertForbidden(); // Con permiso → lista $admin = User::factory()->create(); $admin->givePermissionTo('manage templates'); Livewire::actingAs($admin) ->test(InspectionTemplatesTable::class) ->assertOk() ->assertSee('Recepción acero'); } public function test_table_emits_edit_event_handled_by_manager(): void { Permission::findOrCreate('manage templates'); $admin = User::factory()->create(); $admin->givePermissionTo('manage templates'); $tpl = InspectionTemplate::create(['name' => 'Editame', 'fields' => []]); // El manager escucha #[On('template-edit')] y abre el form Livewire::actingAs($admin) ->test(GlobalTemplateManager::class) ->assertSet('showForm', false) ->call('editTemplate', $tpl->id) // simula el dispatch ->assertSet('showForm', true) ->assertSet('editingTemplate', $tpl->id); } public function test_csv_import_parses_group_question_and_help(): void { Permission::findOrCreate('manage templates'); $admin = User::factory()->create(); $admin->givePermissionTo('manage templates'); $csv = "group,name,label,question,type,required,options,min,max,step,help\n" ."Dimensiones,altura,Altura (m),¿Cumple la cota?,decimal,1,,0,100,0.1,Medir con flexómetro\n" ."Acabados,ok,¿Acabado?,,boolean,0,,,,,\n"; $file = UploadedFile::fake()->createWithContent('plantilla.csv', $csv); $cmp = Livewire::actingAs($admin) ->test(GlobalTemplateManager::class) ->set('importTemplateName', 'Importada') ->set('importFile', $file) ->call('parseImportFile') ->assertHasNoErrors(); $fields = $cmp->get('importPreviewFields'); $this->assertCount(2, $fields); $this->assertEquals('Dimensiones', $fields[0]['group']); $this->assertEquals('altura', $fields[0]['name']); $this->assertEquals('¿Cumple la cota?', $fields[0]['question']); $this->assertEquals('Medir con flexómetro', $fields[0]['help']); $this->assertEquals('decimal', $fields[0]['type']); $this->assertTrue($fields[0]['required']); // Fila sin group (columna 1 vacía) NO debe descartarse $this->assertEquals('Acabados', $fields[1]['group']); $this->assertEquals('ok', $fields[1]['name']); $cmp->call('confirmImportFile'); $tpl = InspectionTemplate::where('name', 'Importada')->first(); $this->assertNotNull($tpl); $this->assertEquals('¿Cumple la cota?', $tpl->fields[0]['question']); } public function test_map_template_selector_only_shows_assigned_templates(): void { $user = User::factory()->create(); $project = $this->project($user, 'M'); $assigned = InspectionTemplate::create(['name' => 'Asignada', 'fields' => []]); $unassigned = InspectionTemplate::create(['name' => 'Otra', 'fields' => []]); $project->inspectionTemplates()->attach($assigned->id); // Necesita una phase/layer al menos Phase::create(['project_id' => $project->id, 'name' => 'F', 'order' => 1, 'color' => '#000', 'progress_percent' => 0]); $cmp = Livewire::actingAs($user) ->test(ProjectMap::class, ['project' => $project]); $names = collect($cmp->get('templates'))->pluck('name')->all(); $this->assertContains('Asignada', $names); $this->assertNotContains('Otra', $names); } }