feat(multi-device): host puede participar como jugador
- Añadido modelo Usuario con pool de usuarios sincronizado - El host ahora recibe palabra y rol como cualquier jugador - UI de selección de perfil en pantallas de lobby - Los clientes pueden ver usuarios del servidor o crear nuevos - El juego no inicia hasta que el host selecciona perfil
This commit is contained in:
115
test/estado_juego_crear_partida_host_test.dart
Normal file
115
test/estado_juego_crear_partida_host_test.dart
Normal file
@@ -0,0 +1,115 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:farolero/estado/estado_juego.dart';
|
||||
import 'package:farolero/modelos/palabra.dart';
|
||||
import 'package:farolero/modelos/partida.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('EstadoJuego crearPartida with host local', () {
|
||||
late EstadoJuego estado;
|
||||
|
||||
setUp(() async {
|
||||
estado = EstadoJuego();
|
||||
await estado.cargarBanco();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
estado.dispose();
|
||||
});
|
||||
|
||||
test(
|
||||
'should include host in jugadores list when setHostJugador called',
|
||||
() {
|
||||
// Set host local player first
|
||||
estado.setHostJugador('HostJuan');
|
||||
|
||||
// Create game with 3 client players + host (host is in the list)
|
||||
estado.crearPartida(
|
||||
config: ConfigPartida(
|
||||
modoMultimovil: true,
|
||||
categoria: 'objetos',
|
||||
numImpostores: 1,
|
||||
pistaImpostor: false,
|
||||
),
|
||||
nombresJugadores: ['HostJuan', 'Cliente1', 'Cliente2', 'Cliente3'],
|
||||
);
|
||||
|
||||
expect(estado.partida, isNotNull);
|
||||
expect(estado.partida!.jugadores.length, 4);
|
||||
|
||||
// Verify host is in the list
|
||||
final hostJugador = estado.partida!.jugadores
|
||||
.where((j) => j.nombre == 'HostJuan')
|
||||
.firstOrNull;
|
||||
expect(hostJugador, isNotNull);
|
||||
expect(hostJugador!.endpointId, isNull);
|
||||
},
|
||||
);
|
||||
|
||||
test('should assign word to host local player', () {
|
||||
estado.setHostJugador('HostJuan');
|
||||
|
||||
estado.crearPartida(
|
||||
config: ConfigPartida(
|
||||
modoMultimovil: true,
|
||||
categoria: 'objetos',
|
||||
numImpostores: 1,
|
||||
pistaImpostor: false,
|
||||
),
|
||||
nombresJugadores: ['HostJuan', 'Cliente1', 'Cliente2', 'Cliente3'],
|
||||
);
|
||||
|
||||
final hostJugador = estado.partida!.jugadores
|
||||
.where((j) => j.nombre == 'HostJuan')
|
||||
.firstOrNull;
|
||||
|
||||
// Host should receive a word if not impostor
|
||||
expect(hostJugador, isNotNull);
|
||||
if (!hostJugador!.esImpostor) {
|
||||
expect(hostJugador.palabra, isNotNull);
|
||||
expect(hostJugador.palabra!.isNotEmpty, isTrue);
|
||||
}
|
||||
});
|
||||
|
||||
test('should include host in impostor selection pool', () async {
|
||||
// Run multiple times to increase chance of host being impostor
|
||||
bool hostWasImpostorAtLeastOnce = false;
|
||||
bool hostWasNormalAtLeastOnce = false;
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
final estado2 = EstadoJuego();
|
||||
await estado2.cargarBanco();
|
||||
estado2.setHostJugador('HostJuan');
|
||||
|
||||
estado2.crearPartida(
|
||||
config: ConfigPartida(
|
||||
modoMultimovil: true,
|
||||
categoria: 'objetos',
|
||||
numImpostores: 1,
|
||||
pistaImpostor: false,
|
||||
),
|
||||
nombresJugadores: ['HostJuan', 'Cliente1', 'Cliente2', 'Cliente3'],
|
||||
);
|
||||
|
||||
final hostJugador = estado2.partida!.jugadores
|
||||
.where((j) => j.nombre == 'HostJuan')
|
||||
.firstOrNull;
|
||||
|
||||
if (hostJugador!.esImpostor) {
|
||||
hostWasImpostorAtLeastOnce = true;
|
||||
} else {
|
||||
hostWasNormalAtLeastOnce = true;
|
||||
}
|
||||
estado2.dispose();
|
||||
|
||||
if (hostWasImpostorAtLeastOnce && hostWasNormalAtLeastOnce) break;
|
||||
}
|
||||
|
||||
// Host should have been impostor at least once and normal at least once
|
||||
// (statistically likely with 20 iterations)
|
||||
expect(hostWasImpostorAtLeastOnce, isTrue);
|
||||
expect(hostWasNormalAtLeastOnce, isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
39
test/estado_juego_host_local_test.dart
Normal file
39
test/estado_juego_host_local_test.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:farolero/estado/estado_juego.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('EstadoJuego host local', () {
|
||||
late EstadoJuego estado;
|
||||
|
||||
setUp(() {
|
||||
estado = EstadoJuego();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
estado.dispose();
|
||||
});
|
||||
|
||||
test('should start with null hostLocal', () {
|
||||
expect(estado.hostLocal, isNull);
|
||||
});
|
||||
|
||||
test('should set host jugador correctly', () {
|
||||
estado.setHostJugador('Juan');
|
||||
|
||||
expect(estado.hostLocal, isNotNull);
|
||||
expect(estado.hostLocal!.nombre, 'Juan');
|
||||
expect(estado.hostLocal!.endpointId, isNull);
|
||||
});
|
||||
|
||||
test('should update host jugador name', () {
|
||||
estado.setHostJugador('Juan');
|
||||
expect(estado.hostLocal!.nombre, 'Juan');
|
||||
|
||||
estado.setHostJugador('Maria');
|
||||
expect(estado.hostLocal!.nombre, 'Maria');
|
||||
});
|
||||
});
|
||||
}
|
||||
70
test/servicio_nearby_user_pool_test.dart
Normal file
70
test/servicio_nearby_user_pool_test.dart
Normal file
@@ -0,0 +1,70 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:farolero/modelos/usuario.dart';
|
||||
import 'package:farolero/servicios/servicio_nearby.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('ServicioNearby user pool', () {
|
||||
late ServicioNearby servicio;
|
||||
|
||||
setUp(() {
|
||||
servicio = ServicioNearby();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
servicio.dispose();
|
||||
});
|
||||
|
||||
test('should start with empty user pool', () {
|
||||
expect(servicio.usuarios, isEmpty);
|
||||
});
|
||||
|
||||
test('should add user to pool', () {
|
||||
final usuario = Usuario(id: 'user-1', nombre: 'Juan');
|
||||
servicio.agregarUsuario(usuario);
|
||||
|
||||
expect(servicio.usuarios.length, 1);
|
||||
expect(servicio.usuarios.first.nombre, 'Juan');
|
||||
});
|
||||
|
||||
test('should remove user from pool', () {
|
||||
final usuario = Usuario(id: 'user-1', nombre: 'Juan');
|
||||
servicio.agregarUsuario(usuario);
|
||||
expect(servicio.usuarios.length, 1);
|
||||
|
||||
servicio.eliminarUsuario('user-1');
|
||||
expect(servicio.usuarios, isEmpty);
|
||||
});
|
||||
|
||||
test('should synchronize users from list', () {
|
||||
final usuarios = [
|
||||
Usuario(id: 'user-1', nombre: 'Juan'),
|
||||
Usuario(id: 'user-2', nombre: 'Maria'),
|
||||
];
|
||||
servicio.sincronizarUsuarios(usuarios);
|
||||
|
||||
expect(servicio.usuarios.length, 2);
|
||||
expect(servicio.usuarios.map((u) => u.nombre).toList(), contains('Juan'));
|
||||
expect(
|
||||
servicio.usuarios.map((u) => u.nombre).toList(),
|
||||
contains('Maria'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should get usuario by id', () {
|
||||
final usuario = Usuario(id: 'user-1', nombre: 'Juan');
|
||||
servicio.agregarUsuario(usuario);
|
||||
|
||||
final found = servicio.getUsuario('user-1');
|
||||
expect(found, isNotNull);
|
||||
expect(found!.nombre, 'Juan');
|
||||
});
|
||||
|
||||
test('should return null for non-existent user', () {
|
||||
final found = servicio.getUsuario('non-existent');
|
||||
expect(found, isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
37
test/usuario_test.dart
Normal file
37
test/usuario_test.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:farolero/modelos/usuario.dart';
|
||||
|
||||
void main() {
|
||||
group('Usuario', () {
|
||||
test('should create Usuario with id and nombre', () {
|
||||
final usuario = Usuario(id: 'test-id', nombre: 'Juan');
|
||||
|
||||
expect(usuario.id, 'test-id');
|
||||
expect(usuario.nombre, 'Juan');
|
||||
});
|
||||
|
||||
test('should serialize to JSON correctly', () {
|
||||
final usuario = Usuario(id: 'test-id', nombre: 'Juan');
|
||||
final json = usuario.toJson();
|
||||
|
||||
expect(json['id'], 'test-id');
|
||||
expect(json['nombre'], 'Juan');
|
||||
});
|
||||
|
||||
test('should deserialize from JSON correctly', () {
|
||||
final json = {'id': 'test-id', 'nombre': 'Juan'};
|
||||
final usuario = Usuario.fromJson(json);
|
||||
|
||||
expect(usuario.id, 'test-id');
|
||||
expect(usuario.nombre, 'Juan');
|
||||
});
|
||||
|
||||
test('should handle JSON with avatar field', () {
|
||||
final json = {'id': 'test-id', 'nombre': 'Juan', 'avatar': '👤'};
|
||||
final usuario = Usuario.fromJson(json);
|
||||
|
||||
expect(usuario.id, 'test-id');
|
||||
expect(usuario.nombre, 'Juan');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user