EstadoAlarmas, EstadoGrabacion and EstadoRadio defaulted `esPremium` to `() => true`, so any construction site that forgot to wire entitlement compiled fine and silently ran ungated — failing OPEN to premium and disabling the paywall with no test able to catch it. The parameter is now required with no default. Production wiring in app.dart was already correct and is unchanged; the 184 pre-existing test call sites now pass `() => true` explicitly, which is exactly the old implicit default, so every assertion is untouched. EstadoRadio has no gate of its own but constructs EstadoGrabacion, so it inherits the same contract. The one test that existed to pin the old default is renamed to describe what it still covers (the premium path through iniciar() with no duracion); its assertions are unchanged.
146 lines
5.7 KiB
Dart
146 lines
5.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:pluriwave/estado/estado_busqueda.dart';
|
|
import 'package:pluriwave/estado/estado_ecualizador.dart';
|
|
import 'package:pluriwave/estado/estado_grabacion.dart';
|
|
import 'package:pluriwave/estado/estado_radio.dart';
|
|
import 'package:pluriwave/l10n/gen/app_localizations.dart';
|
|
import 'package:pluriwave/pantallas/pantalla_buscar.dart';
|
|
import 'package:pluriwave/widgets/tarjeta_emisora.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import '../helpers/fakes.dart';
|
|
|
|
/// S5-R6: the search loading state uses shimmer placeholders, not a bare
|
|
/// spinner, to stay consistent with the rest of the app.
|
|
///
|
|
/// WU6 correction: `PantallaBuscar` now also renders a discovery LANDING
|
|
/// state (task 6.5) that reads `EstadoRadio` directly, so any widget test
|
|
/// mounting it — this one included — must provide a full `EstadoRadio`
|
|
/// provider from the start, not just `EstadoBusqueda`. A non-empty query is
|
|
/// entered first so the screen leaves the landing state and reaches the
|
|
/// search-results branch this test actually targets.
|
|
///
|
|
/// Bugfix (surfaced while landing audit item 18's "Explorar por" grid):
|
|
/// on the FIRST pump here (landing state, empty `EstadoRadio`, default
|
|
/// narrow test viewport, no `_setLargeSurfaceSize`), `_gridEmisoras`
|
|
/// renders its empty-state branch — `PluriEmptyState`, in a fixed
|
|
/// `SizedBox(height: 260)`. That widget's own Column overflowed by 10px
|
|
/// at this width with real ARB copy (`pluri_premium_widgets.dart`,
|
|
/// fixed by wrapping it in a `SingleChildScrollView` — a no-op whenever
|
|
/// content already fits, which is every real device width). This test IS
|
|
/// the end-to-end regression guard for that fix: it renders the exact
|
|
/// scenario that surfaced it.
|
|
class _BusquedaCargando extends EstadoBusqueda {
|
|
_BusquedaCargando() : super(radio: FakeServicioRadio());
|
|
|
|
@override
|
|
bool get cargando => true;
|
|
}
|
|
|
|
void main() {
|
|
setUp(() {
|
|
SharedPreferences.setMockInitialValues({});
|
|
});
|
|
|
|
testWidgets('PantallaBuscar muestra shimmer mientras carga', (tester) async {
|
|
final busqueda = _BusquedaCargando();
|
|
addTearDown(busqueda.dispose);
|
|
final estado = EstadoRadio(
|
|
esPremium: () => true,
|
|
audio: FakeServicioAudio(),
|
|
favoritos: FakeServicioFavoritos(),
|
|
radio: FakeServicioRadio(),
|
|
servicioEcualizador: FakeServicioEcualizador(),
|
|
servicioGrabacion: FakeServicioGrabacionRadio(),
|
|
resolverArchivoCustom: () async => throw UnimplementedError(),
|
|
iniciarAutomaticamente: false,
|
|
);
|
|
addTearDown(estado.dispose);
|
|
|
|
await tester.pumpWidget(
|
|
MultiProvider(
|
|
providers: [
|
|
ChangeNotifierProvider<EstadoRadio>.value(value: estado),
|
|
ListenableProvider<EstadoEcualizador>.value(
|
|
value: estado.ecualizador,
|
|
),
|
|
ListenableProvider<EstadoGrabacion>.value(value: estado.grabacion),
|
|
// Overrides EstadoRadio's own (unused here) EstadoBusqueda with a
|
|
// fake pinned to cargando: true.
|
|
ListenableProvider<EstadoBusqueda>.value(value: busqueda),
|
|
],
|
|
child: MaterialApp(
|
|
locale: const Locale('es'),
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
home: const Scaffold(body: PantallaBuscar()),
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
|
|
// Still the landing state — no query entered yet.
|
|
expect(find.byType(TarjetaEmisoraShimmer), findsNothing);
|
|
|
|
await tester.enterText(find.byType(SearchBar), 'jazz');
|
|
await tester.pump();
|
|
|
|
expect(find.byType(TarjetaEmisoraShimmer), findsWidgets);
|
|
expect(find.byType(CircularProgressIndicator), findsNothing);
|
|
});
|
|
|
|
testWidgets('visual fidelity (audit 13.3/13.4): the "BUSCANDO EMISORAS..." '
|
|
'eyebrow renders above the loading rows, spaced 4px apart (t4:649-651)', (
|
|
tester,
|
|
) async {
|
|
final busqueda = _BusquedaCargando();
|
|
addTearDown(busqueda.dispose);
|
|
final estado = EstadoRadio(
|
|
esPremium: () => true,
|
|
audio: FakeServicioAudio(),
|
|
favoritos: FakeServicioFavoritos(),
|
|
radio: FakeServicioRadio(),
|
|
servicioEcualizador: FakeServicioEcualizador(),
|
|
servicioGrabacion: FakeServicioGrabacionRadio(),
|
|
resolverArchivoCustom: () async => throw UnimplementedError(),
|
|
iniciarAutomaticamente: false,
|
|
);
|
|
addTearDown(estado.dispose);
|
|
|
|
await tester.pumpWidget(
|
|
MultiProvider(
|
|
providers: [
|
|
ChangeNotifierProvider<EstadoRadio>.value(value: estado),
|
|
ListenableProvider<EstadoEcualizador>.value(
|
|
value: estado.ecualizador,
|
|
),
|
|
ListenableProvider<EstadoGrabacion>.value(value: estado.grabacion),
|
|
ListenableProvider<EstadoBusqueda>.value(value: busqueda),
|
|
],
|
|
child: MaterialApp(
|
|
locale: const Locale('es'),
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
home: const Scaffold(body: PantallaBuscar()),
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
await tester.enterText(find.byType(SearchBar), 'jazz');
|
|
await tester.pump();
|
|
|
|
final l10n = AppLocalizations.of(
|
|
tester.element(find.byType(PantallaBuscar)),
|
|
);
|
|
expect(find.text(l10n.searchLoadingStationsLabel), findsOneWidget);
|
|
|
|
final filas = find.byType(TarjetaEmisoraShimmer);
|
|
expect(filas, findsWidgets);
|
|
final primeraAbajo = tester.getBottomLeft(filas.at(0)).dy;
|
|
final segundaArriba = tester.getTopLeft(filas.at(1)).dy;
|
|
expect(segundaArriba - primeraAbajo, 4);
|
|
});
|
|
}
|