Files
pluriwave/test/pantallas/pantalla_inicio_test.dart
Javier Bautista Fernández d579a0e107 feat: Implement startup retry mechanism for custom stations and equalizer persistence
- Added state management for startup retry and custom station handling in `EstadoRadio`.
- Created tasks for implementing strict TDD with RED tests for HTTP failure retries and EQ persistence.
- Developed verification report to ensure compliance with TDD practices.
- Introduced fake services for testing, including `FakeServicioAudio`, `FakeServicioFavoritos`, and `FakeServicioRadio`.
- Implemented widget tests for `PantallaInicio` and `PantallaFavoritos` to validate UI behavior with custom stations.
- Enhanced `ServicioRadio` to support host rotation and retry logic for API calls.
- Established a new configuration file to enforce project constraints and testing rules.
2026-04-27 17:34:04 +02:00

174 lines
5.3 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pluriwave/estado/estado_radio.dart';
import 'package:pluriwave/pantallas/pantalla_favoritos.dart';
import 'package:pluriwave/pantallas/pantalla_inicio.dart';
import 'package:provider/provider.dart';
import '../helpers/fakes.dart';
void main() {
testWidgets(
'PantallaInicio muestra custom, reproducir usa EstadoRadio y favorito usa flujo existente',
(tester) async {
final audio = FakeServicioAudio();
final favoritos = FakeServicioFavoritos();
final radio = FakeServicioRadio();
final custom = emisoraDemo(uuid: 'custom-1', nombre: 'Custom Uno');
final archivo = await _crearArchivoCustom([custom]);
final estado = EstadoRadio(
audio: audio,
favoritos: favoritos,
radio: radio,
servicioEcualizador: FakeServicioEcualizador(),
resolverArchivoCustom: () async => archivo,
iniciarAutomaticamente: false,
);
await estado.inicializar();
await tester.pumpWidget(
ChangeNotifierProvider<EstadoRadio>.value(
value: estado,
child: const MaterialApp(
home: Scaffold(body: PantallaInicio()),
),
),
);
await tester.pumpAndSettle();
expect(find.text('Custom Uno'), findsOneWidget);
await tester.tap(find.text('Custom Uno'));
await tester.pumpAndSettle();
expect(audio.emisorasReproducidas.map((e) => e.uuid), contains('custom-1'));
expect(radio.ultimoUuidClick, 'custom-1');
final tarjetaCustom = find.ancestor(
of: find.text('Custom Uno'),
matching: find.byType(Card),
);
final botonFavorito = find.descendant(
of: tarjetaCustom.first,
matching: find.byIcon(Icons.favorite_outline_rounded),
);
expect(botonFavorito, findsOneWidget);
await tester.tap(botonFavorito);
await tester.pumpAndSettle();
expect(favoritos.toggleCalls, 1);
expect(await favoritos.esFavorito(custom.uuid), isTrue);
});
testWidgets(
'PantallaInicio permite reintentar manualmente tras fallo inicial agotado',
(tester) async {
final radio = FakeServicioRadio(
erroresPopularesPorLlamada: [Exception('sin red')],
popularesPorLlamada: [
const [],
[emisoraDemo(uuid: 'api-1', nombre: 'API Uno')],
),
tendenciasPorLlamada: [
const [],
[emisoraDemo(uuid: 'trend-1', nombre: 'Trend Uno')],
],
);
final estado = EstadoRadio(
audio: FakeServicioAudio(),
favoritos: FakeServicioFavoritos(),
radio: radio,
servicioEcualizador: FakeServicioEcualizador(),
resolverArchivoCustom: _archivoCustomVacio,
iniciarAutomaticamente: false,
);
await estado.inicializar();
await tester.pumpWidget(
ChangeNotifierProvider<EstadoRadio>.value(
value: estado,
child: const MaterialApp(
home: Scaffold(body: PantallaInicio()),
),
),
);
await tester.pumpAndSettle();
expect(find.text('Sin conexión a la API de radio'), findsOneWidget);
expect(find.text('Reintentar'), findsOneWidget);
await tester.tap(find.text('Reintentar'));
await tester.pumpAndSettle();
expect(radio.obtenerPopularesCalls, 2);
expect(find.text('Sin conexión a la API de radio'), findsNothing);
expect(find.text('API Uno'), findsOneWidget);
});
testWidgets('PantallaFavoritos muestra custom favorito tras recarga',
(tester) async {
final favoritos = FakeServicioFavoritos();
final custom = emisoraDemo(uuid: 'custom-1', nombre: 'Custom Uno');
final archivo = await _crearArchivoCustom([custom]);
final estado = EstadoRadio(
audio: FakeServicioAudio(),
favoritos: favoritos,
radio: FakeServicioRadio(
populares: [emisoraDemo(uuid: 'api-1', nombre: 'API Uno')],
),
servicioEcualizador: FakeServicioEcualizador(),
resolverArchivoCustom: () async => archivo,
iniciarAutomaticamente: false,
);
await estado.inicializar();
await tester.pumpWidget(
ChangeNotifierProvider<EstadoRadio>.value(
value: estado,
child: const MaterialApp(
home: Scaffold(body: PantallaInicio()),
),
),
);
await tester.pumpAndSettle();
final tarjetaCustom = find.ancestor(
of: find.text('Custom Uno'),
matching: find.byType(Card),
);
final botonFavorito = find.descendant(
of: tarjetaCustom.first,
matching: find.byIcon(Icons.favorite_outline_rounded),
);
expect(botonFavorito, findsOneWidget);
await tester.tap(botonFavorito);
await tester.pumpAndSettle();
await tester.pumpWidget(
ChangeNotifierProvider<EstadoRadio>.value(
value: estado,
child: const MaterialApp(
home: Scaffold(body: PantallaFavoritos()),
),
),
);
await tester.pumpAndSettle();
expect(await favoritos.esFavorito(custom.uuid), isTrue);
expect(find.text('Custom Uno'), findsOneWidget);
});
}
Future<File> _crearArchivoCustom(List<dynamic> emisoras) async {
final dir = await Directory.systemTemp.createTemp('pluriwave-test-');
final archivo = File('${dir.path}/emisoras_custom.json');
await archivo.writeAsString(jsonEncode(emisoras.map((e) => e.toMap()).toList()));
return archivo;
}
Future<File> _archivoCustomVacio() async => _crearArchivoCustom(const []);