This commit is contained in:
Laucha1312
2026-06-04 15:22:45 -03:00
parent cc70b74e5a
commit aa9bc585fd
12 changed files with 782 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App\Models\AdminUser;
use App\Models\Club;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
class AdminTest extends TestCase
{
use DatabaseTransactions;
public function test_guest_cannot_access_admin_dashboard()
{
$response = $this->get('/admin');
$response->assertStatus(403);
}
public function test_player_cannot_access_admin_dashboard()
{
// Simular que un jugador está logueado
$this->withSession(['user_logged_in' => true, 'user_tipo' => 'jugador']);
$response = $this->get('/admin');
// El middleware/controlador debería redirigirlo por no ser admin
$response->assertStatus(403);
}
public function test_superadmin_can_access_admin_dashboard()
{
AdminUser::create([
'username' => 'supertest',
'password' => Hash::make('123456'),
'role' => 1
]);
$this->withSession([
'admin_logged_in' => true,
'admin_role' => 1,
'admin_username' => 'supertest'
]);
$response = $this->get('/admin');
$response->assertStatus(200);
$response->assertSee('Resumen General');
}
public function test_superadmin_can_create_a_club()
{
Storage::fake('public');
$this->withSession([
'admin_logged_in' => true,
'admin_role' => 1,
'admin_username' => 'supertest'
]);
// Evitamos enviar una imagen real para no depender del File System
$response = $this->post('/admin/clubes', [
'id_club' => 999,
'nombre' => 'Club Atlético Test',
'localidad' => 'Testville',
'direccion' => 'Calle Falsa 123',
'activo' => 1
]);
$response->assertRedirect(route('admin.clubes.index'));
$this->assertDatabaseHas('clubes', [
'nombre' => 'Club Atlético Test'
]);
}
}
+115
View File
@@ -0,0 +1,115 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App\Models\AdminUser;
use App\Models\Jugador;
use App\Models\Aficionado;
use Illuminate\Support\Facades\Hash;
class AuthTest extends TestCase
{
use DatabaseTransactions;
const TURNSTILE_BYPASS = '1x00000000000000000000AA';
public function test_admin_login_success()
{
AdminUser::create([
'username' => 'superadmin',
'password' => Hash::make('password123'),
'role' => 1
]);
$response = $this->post('/login', [
'tipo' => 'admin',
'username' => 'superadmin',
'password' => 'password123',
'cf-turnstile-response' => self::TURNSTILE_BYPASS
]);
$response->assertRedirect('/');
$response->assertSessionHas('admin_logged_in', true);
$response->assertSessionHas('admin_username', 'superadmin');
$response->assertSessionHas('admin_role', 1);
}
public function test_admin_login_failure()
{
AdminUser::create([
'username' => 'superadmin',
'password' => Hash::make('password123'),
'role' => 1
]);
$response = $this->post('/login', [
'tipo' => 'admin',
'username' => 'superadmin',
'password' => 'wrongpassword',
'cf-turnstile-response' => self::TURNSTILE_BYPASS
]);
$response->assertSessionHas('login_error', 'Usuario o contraseña incorrectos');
}
public function test_jugador_login_success()
{
Jugador::create([
'id_jugador' => 'TESTJ01',
'nombre' => 'Emanuel',
'apellido' => 'Ginobili',
'documento' => '25123456',
'fecha_nacimiento' => '1977-07-28',
'activo' => true,
'password' => Hash::make('secreta123')
]);
$response = $this->post('/login', [
'tipo' => 'player',
'dni' => '25123456',
'password' => 'secreta123',
'cf-turnstile-response' => self::TURNSTILE_BYPASS
]);
$response->assertRedirect('/');
$response->assertSessionHas('user_logged_in', true);
$response->assertSessionHas('user_tipo', 'jugador');
$response->assertSessionHas('user_documento', '25123456');
}
public function test_aficionado_login_success()
{
Aficionado::create([
'nombre' => 'Juan',
'apellido' => 'Pérez',
'dni' => '12345678',
'email' => 'juan@example.com',
'password' => Hash::make('fan123')
]);
$response = $this->post('/login', [
'tipo' => 'player',
'dni' => '12345678',
'password' => 'fan123',
'cf-turnstile-response' => self::TURNSTILE_BYPASS
]);
$response->assertRedirect('/');
$response->assertSessionHas('user_logged_in', true);
$response->assertSessionHas('user_tipo', 'aficionado');
}
public function test_logout_clears_session()
{
// Simulamos admin logged in
$this->withSession(['admin_logged_in' => true, 'admin_username' => 'testadmin']);
$response = $this->post('/logout');
$response->assertSessionMissing('admin_logged_in');
$response->assertSessionMissing('admin_username');
$response->assertRedirectContains('logout_msg=');
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App\Models\Evento;
use App\Models\QrCode;
use Illuminate\Support\Facades\Artisan;
class CleanupTest extends TestCase
{
use DatabaseTransactions;
public function test_cleanup_only_removes_qrs_but_keeps_event()
{
// 1. Create an old event
$idEvento = 'old_evt_1';
Evento::create([
'id_evento' => $idEvento,
'nombre_evento' => 'Old Event',
'fecha_evento' => now()->subDays(40)->format('Y-m-d'),
'hora_inicio' => '10:00',
'hora_fin' => '12:00'
]);
// 2. Create a QR for this event
QrCode::create([
'id_qr' => 'qr_old_1',
'id_evento' => $idEvento,
'tipo_qr' => 'publico'
]);
// 3. Ensure they exist
$this->assertDatabaseHas('eventos', ['id_evento' => $idEvento]);
$this->assertDatabaseHas('qr_codes', ['id_qr' => 'qr_old_1']);
// 4. Run the cleanup command
Artisan::call('app:cleanup-old-events');
// 5. Verify QRs are gone but event remains
$this->assertDatabaseMissing('qr_codes', ['id_qr' => 'qr_old_1']);
$this->assertDatabaseHas('eventos', ['id_evento' => $idEvento]);
}
}
+129
View File
@@ -0,0 +1,129 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App\Models\Aficionado;
use App\Models\Evento;
use App\Models\QrCode;
class EventoQRTest extends TestCase
{
use DatabaseTransactions;
// No hay cambios requeridos aquí si es Aficionado, auto_increment está ON para id_aficionado.
// Pero si algún dia usamos jugadores, recordamos usar id_jugador string.
public function test_jugador_puede_solicitar_qr()
{
// 1. Crear un Club y un Jugador activo
$club = \App\Models\Club::create(['nombre' => 'Club Test']);
$idJugador = 'JUG_' . substr(uniqid(), 0, 15);
$jugador = \App\Models\Jugador::create([
'id_jugador' => $idJugador,
'nombre' => 'Carlos',
'apellido' => 'Test',
'documento' => '12345678',
'email' => 'carlos@test.com',
'password' => bcrypt('password123'),
'id_club_actual' => $club->id_club,
'activo' => true
]);
// 2. Crear un equipo del club
$idEquipo = (int) (rand(1000, 9999));
$equipo = \App\Models\Equipo::create([
'id_club' => $club->id_club,
'categoria' => 'Mayores',
'division' => 'A'
]);
// Vincular jugador al equipo
\Illuminate\Support\Facades\DB::table('jugador_equipo')->insert([
'id_jugador' => $jugador->id_jugador,
'id_equipo' => $equipo->id_equipo
]);
// 3. Crear un evento donde juegue ese equipo
$evento = Evento::create([
'id_evento' => 'EVE_' . substr(uniqid(), 0, 15),
'nombre_evento' => 'Partido Amistoso',
'fecha_evento' => now()->addDays(2)->format('Y-m-d'),
'hora_inicio' => '20:00',
'hora_fin' => '22:00',
'id_equipo_local' => $equipo->id_equipo,
'id_equipo_visitante' => null,
'limite_qr_jugador' => 3
]);
// 4. Simular la sesión iniciada como jugador
$this->withSession([
'user_logged_in' => true,
'user_tipo' => 'jugador',
'user_id' => $jugador->id_jugador,
'user_name' => 'Carlos Test'
]);
// 5. Hacer el request POST
$response = $this->post(route('panel.solicitar.qr'), [
'id_evento' => $evento->id_evento
]);
// 6. Verificaciones
$response->assertRedirect(route('panel.mis.qrs', ['evento' => $evento->id_evento]));
$response->assertSessionHas('panel_msg');
// Verificar que en la tabla 'qr_codes' existan los QRs
$this->assertEquals(3, QrCode::where('id_evento', $evento->id_evento)
->where('id_jugador', $jugador->id_jugador)
->count());
}
public function test_jugador_no_puede_solicitar_dos_veces_qrs_para_mismo_evento()
{
$club = \App\Models\Club::create(['nombre' => 'Club Test']);
$idJugador = 'JUG_' . substr(uniqid(), 0, 15);
$jugador = \App\Models\Jugador::create([
'id_jugador' => $idJugador,
'nombre' => 'Carlos',
'apellido' => 'Test',
'documento' => '12345678',
'email' => 'carlos@test.com',
'password' => bcrypt('password123'),
'id_club_actual' => $club->id_club,
'activo' => true
]);
$evento = Evento::create([
'id_evento' => 'EVE_' . substr(uniqid(), 0, 15),
'nombre_evento' => 'Partido Amistoso',
'fecha_evento' => now()->addDays(2)->format('Y-m-d'),
'hora_inicio' => '18:00',
'hora_fin' => '20:00'
]);
// Generar el primer QR directamente en BD simulando que ya lo pidió antes
QrCode::create([
'id_qr' => 'qr_' . uniqid(),
'id_evento' => $evento->id_evento,
'id_jugador' => $jugador->id_jugador,
'tipo_qr' => 'invitado',
'escaneos_restantes' => 1,
'creado' => now()
]);
$this->withSession([
'user_logged_in' => true,
'user_tipo' => 'jugador',
'user_id' => $jugador->id_jugador
]);
$response = $this->post(route('panel.solicitar.qr'), [
'id_evento' => $evento->id_evento
]);
// Debería tirar mensaje de error de que ya solicitó
$response->assertSessionHas('panel_error', 'Ya solicitaste QRs para este evento.');
$this->assertEquals(1, QrCode::where('id_evento', $evento->id_evento)->count());
}
}
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace Tests\Feature;
// use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*/
public function test_the_application_returns_a_successful_response(): void
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
+80
View File
@@ -0,0 +1,80 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App\Models\Club;
use App\Models\Jugador;
use App\Models\AdminUser;
use Illuminate\Support\Facades\Hash;
class JugadorCreationTest extends TestCase
{
use DatabaseTransactions;
protected $clubA;
protected $clubB;
protected function setUp(): void
{
parent::setUp();
$this->clubA = Club::create(['id_club' => 101, 'nombre' => 'Club Alpha']);
$this->clubB = Club::create(['id_club' => 102, 'nombre' => 'Club Beta']);
}
public function test_duplicate_dni_shows_club_name_error()
{
// 1. Create an existing player in Club Alpha
Jugador::create([
'id_jugador' => '1019001',
'documento' => '99999999',
'nombre' => 'Existing',
'apellido' => 'Player',
'fecha_nacimiento' => '1990-01-01',
'id_club_actual' => 101,
'id_club_origen' => 101,
'activo' => 1
]);
// 2. Log in as SuperAdmin (Role 1)
$this->withSession([
'admin_logged_in' => true,
'admin_role' => 1,
'admin_username' => 'supertest'
]);
// 3. Try to create a new player with the same DNI
$response = $this->post(route('admin.jugadores.store'), [
'documento' => '99999999',
'nombre' => 'New',
'apellido' => 'Player',
'fecha_nacimiento' => '1995-05-05',
'id_club_actual' => 102,
'id_club_origen' => 102
]);
// 4. Assert error message contains the club name
$response->assertSessionHasErrors(['documento']);
$errors = session('errors')->get('documento');
$this->assertStringContainsString('Club Alpha', $errors[0]);
}
public function test_club_admin_can_see_all_clubs_in_origen()
{
// Log in as Club Admin (Role 2)
$this->withSession([
'admin_logged_in' => true,
'admin_role' => 2,
'admin_id_club' => 101,
'admin_username' => 'clubadmin'
]);
$response = $this->get(route('admin.jugadores.create'));
$response->assertStatus(200);
$response->assertSee('Club Alpha');
$response->assertSee('Club Beta');
}
}
+64
View File
@@ -0,0 +1,64 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App\Models\AdminUser;
use App\Models\Club;
use App\Models\Jugador;
use App\Models\Pase;
use Illuminate\Support\Facades\Hash;
class PaseTest extends TestCase
{
use DatabaseTransactions;
public function test_superadmin_can_approve_a_transfer()
{
// 1. Setup: Dos clubes y un jugador en el club A
$clubA = Club::create(['id_club' => 101, 'nombre' => 'Club A']);
$clubB = Club::create(['id_club' => 102, 'nombre' => 'Club B']);
$jugador = Jugador::create([
'id_jugador' => 'T-PASE-1',
'documento' => '99000111',
'nombre' => 'Pedro',
'apellido' => 'Pase',
'id_club_actual' => $clubA->id_club,
'id_club_origen' => $clubA->id_club,
'activo' => true
]);
// 2. Crear solicitud de pase
$pase = Pase::create([
'id_jugador' => $jugador->id_jugador,
'id_club_origen' => $clubA->id_club,
'id_club_destino' => $clubB->id_club,
'estado' => 'Pendiente'
]);
// 3. Loguear como SuperAdmin
$this->withSession([
'admin_role' => 1,
'admin_logged_in' => true
]);
// 4. Ejecutar la aprobación
$response = $this->put(route('admin.pases.aprobar', $pase->id_pase));
// 5. Verificar redirección y base de datos
$response->assertRedirect(route('admin.pases.index'));
// El pase debe estar aprobado
$this->assertDatabaseHas('pases', [
'id_jugador' => $jugador->id_jugador,
'estado' => 'Aprobado'
]);
// El jugador debe haber cambiado de club actual
$jugador->refresh();
$this->assertEquals($clubB->id_club, $jugador->id_club_actual);
$this->assertEquals($clubA->id_club, $jugador->id_club_origen);
}
}
+52
View File
@@ -0,0 +1,52 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App\Models\Club;
use App\Models\Jugador;
use App\Models\Evento;
class SoftDeleteTest extends TestCase
{
use DatabaseTransactions;
public function test_deletion_uses_soft_deletes_on_critical_models()
{
// 1. Setup: Crear un club, jugador y evento
$club = Club::create(['id_club' => 888, 'nombre' => 'Club Borrable']);
$jugador = Jugador::create([
'id_jugador' => 'T-SD-1',
'documento' => '11111111',
'nombre' => 'Borra',
'apellido' => 'Mela',
'id_club_actual' => $club->id_club,
'id_club_origen' => $club->id_club,
'activo' => true
]);
$evento = Evento::create([
'id_evento' => 'UUID-SD-1',
'nombre_evento' => 'Evento Prueba SD',
'fecha_evento' => now()->format('Y-m-d'),
'hora_inicio' => '18:00',
'hora_fin' => '20:00'
]);
// 2. Ejecutar borrado
$club->delete();
$jugador->delete();
$evento->delete();
// 3. Verificar que siguen en la base de datos (físicamente) pero con deleted_at
$this->assertSoftDeleted('clubes', ['id_club' => 888]);
$this->assertSoftDeleted('jugadores', ['id_jugador' => 'T-SD-1']);
$this->assertSoftDeleted('eventos', ['id_evento' => 'UUID-SD-1']);
// 4. Verificar que no aparecen en consultas normales
$this->assertNull(Club::find(888));
// 5. Verificar que aparecen si usamos withTrashed()
$this->assertNotNull(Club::withTrashed()->find(888));
}
}
+108
View File
@@ -0,0 +1,108 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App\Models\Club;
use App\Models\AdminUser;
use App\Models\Evento;
use App\Models\Equipo;
use App\Models\Jugador;
use App\Models\QrCode;
class TFICorrectionsTest extends TestCase
{
use DatabaseTransactions;
/**
* Test que verifica el ordenamiento descendente en el panel de clubes.
*/
public function test_clubes_are_ordered_descending_by_id()
{
$admin = AdminUser::create([
'username' => 'superadmin_test',
'password' => bcrypt('password'),
'role' => 1 // SuperAdmin
]);
$club1 = Club::create(['nombre' => 'Club Viejo']);
$club2 = Club::create(['nombre' => 'Club Nuevo']);
$this->withSession(['admin_logged_in' => true, 'admin_role' => 1]);
$response = $this->get(route('admin.clubes.index'));
$response->assertStatus(200);
// El club con mayor ID (el último creado) debería aparecer primero en el HTML
$response->assertSeeInOrder(['Club Nuevo', 'Club Viejo']);
}
/**
* Test que verifica el bloqueo de botón y validación JS (indirectamente via form attributes).
*/
public function test_admin_layout_contains_form_validation_script()
{
$this->withSession(['admin_logged_in' => true, 'admin_role' => 1]);
$response = $this->get(route('admin.dashboard'));
$response->assertStatus(200);
// Verificar que el script de validación inyectado esté presente
$response->assertSee('handleFormValidation');
}
/**
* Test que verifica la ruta de descarga de QR en PDF.
*/
public function test_qr_pdf_download_route_is_accessible()
{
$club = Club::create(['nombre' => 'Club Test']);
$jugador = Jugador::create([
'id_jugador' => 'JUG_TEST_PDF',
'nombre' => 'Test',
'apellido' => 'User',
'documento' => '99999999',
'email' => 'test@pdf.com',
'id_club_actual' => $club->id_club
]);
$evento = Evento::create([
'id_evento' => 'EVE_TEST_PDF',
'nombre_evento' => 'Evento PDF',
'fecha_evento' => now()->toDateString(),
'hora_inicio' => '10:00',
'hora_fin' => '12:00'
]);
$qr = QrCode::create([
'id_qr' => 'qr_pdf_test',
'id_evento' => $evento->id_evento,
'id_jugador' => $jugador->id_jugador,
'tipo_qr' => 'invitado',
'creado' => now()
]);
$this->withSession([
'user_logged_in' => true,
'user_tipo' => 'jugador',
'user_id' => $jugador->id_jugador
]);
$response = $this->get(route('panel.qr.descargar', $qr->id_qr));
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/pdf');
}
/**
* Test que verifica la visibilidad del manual de usuario.
*/
public function test_documentation_is_accessible()
{
$response = $this->get(route('documentacion.index'));
$response->assertStatus(200);
$response->assertSee('Manual de Usuario');
}
}