feat(buscar): add discovery landing state, filter pills, counter, and sort

This commit is contained in:
2026-07-29 08:45:36 +02:00
parent 3a803ce2bf
commit 9bd828139f
29 changed files with 1789 additions and 655 deletions
+101
View File
@@ -0,0 +1,101 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:pluriwave/estado/orden_emisoras.dart';
import 'package:pluriwave/modelos/emisora.dart';
/// WU6: every criterion the Buscar "Ordenar" control can render must map to
/// a real, tested [OrdenEmisoras] case (`station-discovery-browse` spec,
/// "Client-Side Search Sort Only" — "the system MUST NOT render an option
/// that does not actually sort").
void main() {
Emisora conMetricas({
required String uuid,
required String nombre,
int? bitrate,
int votes = 0,
int clickcount = 0,
}) => Emisora(
uuid: uuid,
nombre: nombre,
url: 'https://stream.demo/$uuid',
bitrate: bitrate,
votes: votes,
clickcount: clickcount,
);
group('OrdenEmisoras.nombre', () {
test('ordena alfabéticamente sin distinguir mayúsculas', () {
final emisoras = [
conMetricas(uuid: 'z', nombre: 'zeta fm'),
conMetricas(uuid: 'a', nombre: 'Alfa FM'),
conMetricas(uuid: 'm', nombre: 'medio fm'),
];
final resultado = ordenarEmisoras(emisoras, OrdenEmisoras.nombre);
expect(resultado.map((e) => e.uuid), ['a', 'm', 'z']);
});
});
group('OrdenEmisoras.calidad', () {
test('ordena por bitrate descendente', () {
final emisoras = [
conMetricas(uuid: 'baja', nombre: 'Baja', bitrate: 64),
conMetricas(uuid: 'alta', nombre: 'Alta', bitrate: 320),
conMetricas(uuid: 'media', nombre: 'Media', bitrate: 128),
];
final resultado = ordenarEmisoras(emisoras, OrdenEmisoras.calidad);
expect(resultado.map((e) => e.uuid), ['alta', 'media', 'baja']);
});
});
group('OrdenEmisoras.popularidad', () {
test('ordena por votos descendente', () {
final emisoras = [
conMetricas(uuid: 'pocos', nombre: 'Pocos', votes: 3),
conMetricas(uuid: 'muchos', nombre: 'Muchos', votes: 900),
conMetricas(uuid: 'medio', nombre: 'Medio', votes: 40),
];
final resultado = ordenarEmisoras(emisoras, OrdenEmisoras.popularidad);
expect(resultado.map((e) => e.uuid), ['muchos', 'medio', 'pocos']);
});
test('en empate de votos, desempata por clickcount descendente', () {
final emisoras = [
conMetricas(
uuid: 'menos-clicks',
nombre: 'Menos clicks',
votes: 10,
clickcount: 5,
),
conMetricas(
uuid: 'mas-clicks',
nombre: 'Mas clicks',
votes: 10,
clickcount: 500,
),
];
final resultado = ordenarEmisoras(emisoras, OrdenEmisoras.popularidad);
expect(resultado.map((e) => e.uuid), ['mas-clicks', 'menos-clicks']);
});
});
test(
'todos los valores del enum tienen un caso de ordenamiento implementado '
'(regresión: nunca ofrecer una opción decorativa que no ordene)',
() {
for (final criterio in OrdenEmisoras.values) {
// Must not throw and must return a same-length list for every case.
final resultado = ordenarEmisoras([
conMetricas(uuid: 'x', nombre: 'X'),
], criterio);
expect(resultado, hasLength(1));
}
},
);
}