4
This commit is contained in:
@@ -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'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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=');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# 🃏 Machete de Tests — OnAPB
|
||||||
|
### Resumen para la Defensa del Proyecto (Taller de Integración)
|
||||||
|
|
||||||
|
Este documento sirve como guía para explicarle al profesor qué estamos probando exactamente con cada comando de `php artisan test`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ Conceptos Clave (Para responder si preguntan)
|
||||||
|
- **Feature Tests:** Prueban una funcionalidad completa desde la perspectiva del usuario (ej: hacer login, crear un club).
|
||||||
|
- **DatabaseTransactions:** Es un "Trait" que usamos en los tests para que cada prueba se envuelva en una transacción de base de datos y se haga un **Rollback** al final. Así, los datos de prueba nunca ensucian la base de datos real.
|
||||||
|
- **Assertions (Afirmaciones):** Son las comprobaciones que hacemos, como `assertStatus(200)` (la página cargó bien) o `assertDatabaseHas` (el dato se guardó en la BD).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📂 Detalle de los Tests (Qué hace cada uno)
|
||||||
|
|
||||||
|
### 1. `AuthTest.php` (Autenticación)
|
||||||
|
- **Qué prueba:** Que los 3 tipos de usuarios (Admin, Jugador, Aficionado) puedan entrar al sistema con sus credenciales y que el Logout funcione.
|
||||||
|
- **Escenario crítico:** Verifica que el captcha de Cloudflare (Turnstile) sea sorteado correctamente en el entorno de pruebas.
|
||||||
|
|
||||||
|
### 2. `AdminTest.php` (Seguridad y Roles)
|
||||||
|
- **Qué prueba:** El control de acceso.
|
||||||
|
- Un visitante o un jugador **no deben** poder entrar al `/admin` (Error 403).
|
||||||
|
- Un Súper Admin **sí debe** poder entrar y ver el "Panel de Control".
|
||||||
|
- El Súper Admin puede crear un Club y este se guarda correctamente en la BD.
|
||||||
|
|
||||||
|
### 3. `PaseTest.php` (Lógica de Negocio — **NUEVO**)
|
||||||
|
- **Qué prueba:** El flujo de traspaso de un jugador.
|
||||||
|
- **Escenario:** Un Súper Admin aprueba un pase pendiente. El test verifica que:
|
||||||
|
1. El estado del pase cambie a "Aprobado".
|
||||||
|
2. El `id_club_actual` del jugador se actualice automáticamente al club de destino.
|
||||||
|
|
||||||
|
### 4. `SoftDeleteTest.php` (Recuperación ante fallos — **NUEVO**)
|
||||||
|
- **Qué prueba:** Que el borrado sea "lógico" y no "físico".
|
||||||
|
- **Escenario:** Al eliminar un Club o un Jugador, el test verifica que el registro **siga existiendo** en la base de datos pero con la columna `deleted_at` completa. Esto demuestra la capacidad de recuperación del sistema.
|
||||||
|
|
||||||
|
### 5. `EventoQRTest.php` (Generación de QRs)
|
||||||
|
- **Qué prueba:** La funcionalidad estrella del sistema.
|
||||||
|
- **Escenario:** Un aficionado solicita un QR para un partido. El test verifica que se genere el registro en la tabla `qr_codes` y que el sistema **impida** solicitar un segundo QR para el mismo evento (evita fraudes).
|
||||||
|
|
||||||
|
### 6. `JugadorCreationTest.php` (Validaciones)
|
||||||
|
- **Qué prueba:** Reglas de integridad de datos.
|
||||||
|
- **Escenario:** Intentar crear un jugador con un DNI que ya existe. El test verifica que el sistema devuelva un error amigable indicando a qué club pertenece ese DNI ya registrado.
|
||||||
|
|
||||||
|
### 7. `CleanupTest.php` (Mantenimiento)
|
||||||
|
- **Qué prueba:** Que el sistema de limpieza automática funcione.
|
||||||
|
- **Escenario:** Simula la limpieza de eventos viejos. Verifica que se borren los QRs (para ahorrar espacio) pero que el **Evento (partido)** se mantenga para el historial de torneos.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. `TFICorrectionsTest.php` (Correcciones Finales — **NUEVO**)
|
||||||
|
- **Qué prueba:** Las últimas mejoras solicitadas por los profesores.
|
||||||
|
- **Escenario:**
|
||||||
|
1. Verifica que los listados de administración estén ordenados de forma descendente (último creado, primero en verse).
|
||||||
|
2. Verifica que la descarga de QRs en formato PDF funcione correctamente y devuelva el archivo esperado.
|
||||||
|
3. Verifica que el Manual de Usuario sea accesible y se renderice correctamente en la web.
|
||||||
|
4. Verifica la presencia del sistema de bloqueo de botones y validación proactiva en el panel.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Cómo ejecutar y mostrar
|
||||||
|
Si el profesor pide ver los tests en vivo:
|
||||||
|
1. Abrir la terminal.
|
||||||
|
2. Correr: `php artisan test`
|
||||||
|
3. Explicar: *"Instalamos una batería de 22 tests que cubren desde el login y la lógica de pases hasta las nuevas correcciones de ordenamiento, descarga de PDFs y documentación integrada. Esto asegura que el sistema sea extremadamente robusto para la entrega final."*
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||||
|
|
||||||
|
abstract class TestCase extends BaseTestCase
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ExampleTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A basic test example.
|
||||||
|
*/
|
||||||
|
public function test_that_true_is_true(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user