From 7faf56900f8666aa52d4152e70166c89e208f2fb Mon Sep 17 00:00:00 2001 From: freetlab Date: Thu, 30 Jul 2026 22:06:36 +0200 Subject: [PATCH 1/6] fix(favoritos): stop the header padding from doubling up Issue 3 (feedback-pruebas): ReorderableListView.padding wrapped header/rows/footer with a single horizontal value (16), which doubled up on top of PluriRootHeader's own internal inset -- landing the title at 36px instead of the 20px every other root uses -- while also applying card-tier padding to the flat FilaEmisoraPlana rows (row tier, matching the same widget's fix on Buscar) and leaving the populated-state top gap at an unwired 4 that didn't match this same screen's own empty state (0) or the footer CTA's prototype value (8). Zeroes the list-level padding and gives the header, chip strip, rows, and footer CTA their own correctly-tiered insets instead. --- lib/pantallas/pantalla_favoritos.dart | 77 +++++++++++---- test/pantallas/pantalla_favoritos_test.dart | 102 ++++++++++++++++++++ 2 files changed, 159 insertions(+), 20 deletions(-) diff --git a/lib/pantallas/pantalla_favoritos.dart b/lib/pantallas/pantalla_favoritos.dart index 3753a0b..cbf87ca 100644 --- a/lib/pantallas/pantalla_favoritos.dart +++ b/lib/pantallas/pantalla_favoritos.dart @@ -174,12 +174,18 @@ class _PantallaFavoritosState extends State { return ReorderableListView( buildDefaultDragHandles: false, - padding: const EdgeInsets.fromLTRB( - PluriLayout.horizontal, - 4, - PluriLayout.horizontal, - PluriLayout.bottomChromeInset, - ), + // Issue 3 (feedback-pruebas): zero horizontal here, matching every + // other root's PluriLayout.pageListPadding convention (Alarmas, + // Ajustes, and this screen's OWN empty-state branch above). + // ReorderableListView.padding wraps header/children/footer UNIFORMLY, + // so a single horizontal value here can never be simultaneously right + // for PluriRootHeader (self-padded, wants none), the reorderable rows + // (want row tier, applied per item below) and the footer CTA (wants + // card tier, applied on the footer's own Padding below). The previous + // `PluriLayout.horizontal` doubled up on top of PluriRootHeader's own + // internal inset, pushing "Favorites" in by 36px instead of the 20px + // every other root uses for its title. + padding: const EdgeInsets.only(bottom: PluriLayout.bottomChromeInset), header: Padding( padding: const EdgeInsets.only(bottom: 12), child: Column( @@ -224,17 +230,39 @@ class _PantallaFavoritosState extends State { ], ), const SizedBox(height: 12), - _FilaChipsGrupos( - grupos: gruposVisibles, - favoritos: favoritos, - seleccionado: seleccionEfectiva, - onSeleccionar: (id) => setState(() => _grupoSeleccionadoId = id), + // Issue 3 (feedback-pruebas): t4:218 draws this chip strip at + // title-tier (20px) horizontal inset, directly on the page + // background -- it now needs its OWN inset since the list's + // padding no longer supplies one. + Padding( + padding: const EdgeInsets.symmetric( + horizontal: PluriLayout.titleHorizontal, + ), + child: _FilaChipsGrupos( + grupos: gruposVisibles, + favoritos: favoritos, + seleccionado: seleccionEfectiva, + onSeleccionar: + (id) => setState(() => _grupoSeleccionadoId = id), + ), ), ], ), ), footer: Padding( - padding: const EdgeInsets.only(top: 4), + // Issue 3 (feedback-pruebas): card tier (16, matching every other + // screen's dashed CTA) now that the list's own padding no longer + // supplies it, plus t4:234's 8px gap above the CTA + // (PluriLayout.compactGap) instead of the previous unwired literal + // 4 -- the ONLY state of this screen with a nonzero top gap before + // its own content used a value that matched neither this screen's + // own empty-state branch nor the prototype. + padding: const EdgeInsets.fromLTRB( + PluriLayout.horizontal, + PluriLayout.compactGap, + PluriLayout.horizontal, + 0, + ), child: _CtaEmisoraPersonalizada( onTap: _abrirFormularioEmisoraPersonalizada, ), @@ -244,14 +272,24 @@ class _PantallaFavoritosState extends State { _onReorder(filtrados, favoritos, oldIndex, newIndex), children: [ for (var i = 0; i < filtrados.length; i++) - _FilaFavorito( + // Issue 3 (feedback-pruebas): row tier (12), not card tier -- the + // key moves to this wrapper (ReorderableListView identifies each + // child by its own top-level key) since FilaEmisoraPlana rows are + // documented (audit 4.3) as flat, background-less rows, the same + // tier Buscar's results list already uses for the same widget. + Padding( key: ValueKey(filtrados[i].uuid), - index: i, - emisora: filtrados[i], - grupos: gruposVisibles, - grupoActual: gruposVisibles.firstWhere( - (g) => g.id == filtrados[i].grupoFavoritosId, - orElse: () => gruposVisibles.first, + padding: const EdgeInsets.symmetric( + horizontal: PluriLayout.rowHorizontal, + ), + child: _FilaFavorito( + index: i, + emisora: filtrados[i], + grupos: gruposVisibles, + grupoActual: gruposVisibles.firstWhere( + (g) => g.id == filtrados[i].grupoFavoritosId, + orElse: () => gruposVisibles.first, + ), ), ), ], @@ -343,7 +381,6 @@ class _FilaChipsGrupos extends StatelessWidget { class _FilaFavorito extends StatelessWidget { const _FilaFavorito({ - super.key, required this.index, required this.emisora, required this.grupos, diff --git a/test/pantallas/pantalla_favoritos_test.dart b/test/pantallas/pantalla_favoritos_test.dart index 623a606..eaa38eb 100644 --- a/test/pantallas/pantalla_favoritos_test.dart +++ b/test/pantallas/pantalla_favoritos_test.dart @@ -7,7 +7,9 @@ import 'package:pluriwave/l10n/gen/app_localizations.dart'; import 'package:pluriwave/pantallas/ajustes/pantalla_ajustes_grupos_favoritos.dart'; import 'package:pluriwave/pantallas/pantalla_favoritos.dart'; import 'package:pluriwave/widgets/fila_emisora_plana.dart'; +import 'package:pluriwave/widgets/pluri_layout.dart'; import 'package:pluriwave/widgets/pluri_push_scaffold.dart'; +import 'package:pluriwave/widgets/pluri_root_header.dart'; import 'package:pluriwave/widgets/tarjeta_emisora.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -546,6 +548,106 @@ void main() { expect(inactivo.backgroundColor, const Color(0xFF102532)); }); }); + + group('Issue 3 (feedback-pruebas): spacing tiers', () { + testWidgets('the header title sits at title-tier inset (20px) -- ' + 'ReorderableListView.padding used to double up on top of ' + "PluriRootHeader's own internal inset", (tester) async { + setLargeSurface(tester); + _suppressListTileInkAssertion(); + final estado = await crearEstadoConFavoritos(); + addTearDown(estado.dispose); + final l10n = lookupAppLocalizations(const Locale('en')); + + await tester.pumpWidget(buildScreen(estado)); + await pumpStable(tester); + + final titulo = find.descendant( + of: find.byType(PluriRootHeader), + matching: find.text(l10n.favoritesTitle), + ); + expect( + tester.getTopLeft(titulo).dx, + PluriLayout.titleHorizontal, + reason: + 'PluriRootHeader already supplies its own 20px inset; the ' + 'previous ReorderableListView.padding of 16 doubled up on top ' + 'of it, landing the title at 36px instead of 20px -- the ONE ' + "root screen whose header didn't match Alarmas/Ajustes", + ); + }); + + testWidgets( + 'the header sits at the SAME horizontal position whether the list is ' + 'empty or populated -- two mutually-exclusive states of the same ' + 'header must not read differently', + (tester) async { + setLargeSurface(tester); + final l10n = lookupAppLocalizations(const Locale('en')); + + final vacio = await crearEstadoVacio(); + addTearDown(vacio.dispose); + await tester.pumpWidget(buildScreen(vacio)); + await pumpStable(tester); + final dxVacio = + tester + .getTopLeft( + find.descendant( + of: find.byType(PluriRootHeader), + matching: find.text(l10n.favoritesTitle), + ), + ) + .dx; + + _suppressListTileInkAssertion(); + final conFavoritos = await crearEstadoConFavoritos(); + addTearDown(conFavoritos.dispose); + await tester.pumpWidget(buildScreen(conFavoritos)); + await pumpStable(tester); + final dxConFavoritos = + tester + .getTopLeft( + find.descendant( + of: find.byType(PluriRootHeader), + matching: find.text(l10n.favoritesTitle), + ), + ) + .dx; + + expect( + dxConFavoritos, + dxVacio, + reason: + 'the empty and populated branches of this screen must render ' + 'the SAME header inset -- they previously did not (0 vs 16 ' + 'extra px of list-level padding)', + ); + }, + ); + + testWidgets( + 'each favourite row uses row-tier horizontal inset (12), not the ' + 'card-tier constant a background-less row was never meant to carry', + (tester) async { + setLargeSurface(tester); + _suppressListTileInkAssertion(); + final estado = await crearEstadoConFavoritos(); + addTearDown(estado.dispose); + + await tester.pumpWidget(buildScreen(estado)); + await pumpStable(tester); + + expect( + tester.getTopLeft(find.byType(FilaEmisoraPlana).first).dx, + PluriLayout.rowHorizontal, + reason: + 'audit 4.3: background-less rows are row tier (12), matching ' + 'the same widget already fixed on Buscar -- not card tier ' + '(16)', + ); + }, + ); + }); } void setLargeSurface(WidgetTester tester) { From 5bbf750b63432078db2a63169e42a808b0e90279 Mon Sep 17 00:00:00 2001 From: freetlab Date: Thu, 30 Jul 2026 22:08:40 +0200 Subject: [PATCH 2/6] fix(ajustes): correct the gap between stacked settings groups Issue 3 (feedback-pruebas): the prototype (t4:523/534/541) draws a 16px gap between the AUDIO/STATIONS/RECORDINGS/APPLICATION cards, not 12 -- a plain unwired literal that happened to collide with the sectionGap/panelGap tokens' own value without actually citing the prototype. --- lib/pantallas/pantalla_ajustes.dart | 8 ++++--- test/pantallas/pantalla_ajustes_test.dart | 26 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/pantallas/pantalla_ajustes.dart b/lib/pantallas/pantalla_ajustes.dart index 8ff6e3d..f57f114 100644 --- a/lib/pantallas/pantalla_ajustes.dart +++ b/lib/pantallas/pantalla_ajustes.dart @@ -147,7 +147,9 @@ class _AjustesContent extends StatelessWidget { ), ], ), - const SizedBox(height: 12), + // Issue 3 (feedback-pruebas): t4:523/534/541 all draw a 16px gap + // between these opaque, stacked settings groups -- not 12. + const SizedBox(height: 16, key: ValueKey('ajustes-group-gap-1')), GrupoAjustes( titulo: l10n.settingsGroupStationsTitle, filas: [ @@ -202,7 +204,7 @@ class _AjustesContent extends StatelessWidget { ), ], ), - const SizedBox(height: 12), + const SizedBox(height: 16, key: ValueKey('ajustes-group-gap-2')), GrupoAjustes( titulo: l10n.settingsGroupRecordingsTitle, filas: [ @@ -250,7 +252,7 @@ class _AjustesContent extends StatelessWidget { ), ], ), - const SizedBox(height: 12), + const SizedBox(height: 16, key: ValueKey('ajustes-group-gap-3')), GrupoAjustes( titulo: l10n.settingsGroupApplicationTitle, filas: [ diff --git a/test/pantallas/pantalla_ajustes_test.dart b/test/pantallas/pantalla_ajustes_test.dart index 4ef5e4f..9466b03 100644 --- a/test/pantallas/pantalla_ajustes_test.dart +++ b/test/pantallas/pantalla_ajustes_test.dart @@ -306,6 +306,32 @@ void main() { expect(find.text('RECORDINGS & MUSIC'), findsOneWidget); expect(find.text('APPLICATION'), findsOneWidget); }); + + testWidgets( + 'Issue 3 (feedback-pruebas): the gap between stacked settings groups ' + 'is 16, matching t4:523/534/541 -- not 12', + (tester) async { + setLargeSurface(tester); + _suppressListTileInkAssertion(); + final estado = await crearEstado(); + addTearDown(estado.dispose); + + await tester.pumpWidget(buildAjustes(estado)); + await pumpStable(tester); + + for (final key in [ + 'ajustes-group-gap-1', + 'ajustes-group-gap-2', + 'ajustes-group-gap-3', + ]) { + expect( + tester.getSize(find.byKey(ValueKey(key))).height, + 16, + reason: 't4:523/534/541 all draw a 16px gap between stacked groups', + ); + } + }, + ); }); } From 93b7ec2af9dcb9e83408e55ae77dcb130726f533 Mon Sep 17 00:00:00 2001 From: freetlab Date: Thu, 30 Jul 2026 22:12:24 +0200 Subject: [PATCH 3/6] fix(alarma-sonando): make the snooze block's vertical gaps uniform Issue 3 (feedback-pruebas): t4:427 wraps the POSPONER eyebrow, the snooze tiles and the Stop button in a single flex column with a uniform gap:12 -- this screen carried a 10/14 pair instead, matching neither the prototype nor each other. The dismiss-guard test (protected, untouched) only asserts behaviour via find.text/find.byType, so this pure value change is safe against it -- re-verified empty diff after this commit. --- lib/pantallas/pantalla_alarma_sonando.dart | 8 +++- .../pantalla_alarma_sonando_tier5_test.dart | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/pantallas/pantalla_alarma_sonando.dart b/lib/pantallas/pantalla_alarma_sonando.dart index cf62ff1..0ce1d67 100644 --- a/lib/pantallas/pantalla_alarma_sonando.dart +++ b/lib/pantallas/pantalla_alarma_sonando.dart @@ -339,14 +339,18 @@ class _PantallaAlarmaSonandoState extends State { ], ), ), - const SizedBox(height: 10), + // Issue 3 (feedback-pruebas): t4:427 wraps POSPONER's + // eyebrow, the snooze tiles and Stop in a `gap:12` flex + // column -- the same 12 on both sides, not the 10/14 pair + // this used to carry. + const SizedBox(height: 12), _FilaSnoozeFija( alarma: alarma, l10n: l10n, tokens: tokens, onPosponer: _posponer, ), - const SizedBox(height: 14), + const SizedBox(height: 12), SizedBox( width: double.infinity, child: FilledButton.icon( diff --git a/test/pantallas/pantalla_alarma_sonando_tier5_test.dart b/test/pantallas/pantalla_alarma_sonando_tier5_test.dart index b241773..f3277ab 100644 --- a/test/pantallas/pantalla_alarma_sonando_tier5_test.dart +++ b/test/pantallas/pantalla_alarma_sonando_tier5_test.dart @@ -159,4 +159,49 @@ void main() { await tester.pumpAndSettle(); }, ); + + testWidgets( + 'Issue 3 (feedback-pruebas): the gap above the snooze tiles matches the ' + 'gap below them (t4:427 draws a uniform gap:12 flex column) -- the ' + 'previous 10/14 pair matched neither the prototype nor each other', + (tester) async { + await _montarPantalla(tester); + final l10n = AppLocalizations.of( + tester.element(find.byType(PantallaAlarmaSonando)), + ); + + final eyebrowBottom = + tester + .getBottomLeft( + find + .ancestor( + of: find.byIcon(Icons.snooze_rounded), + matching: find.byType(Row), + ) + .first, + ) + .dy; + final tileDestacado = find.ancestor( + of: find.text(l10n.alarmSnoozeOptionLabel(10)), + matching: find.byType(FilledButton), + ); + final tilesTop = tester.getTopLeft(tileDestacado).dy; + final tilesBottom = tester.getBottomLeft(tileDestacado).dy; + final stopButtonTop = + tester + .getTopLeft(find.byKey(const ValueKey('ringing-stop-button'))) + .dy; + + expect( + tilesTop - eyebrowBottom, + 12, + reason: 't4:427: gap:12 above the snooze tiles', + ); + expect( + stopButtonTop - tilesBottom, + 12, + reason: 't4:427: gap:12 below the snooze tiles, same as above', + ); + }, + ); } From 9a75027d57d19508534c57f5dbaad14d0ba00ef7 Mon Sep 17 00:00:00 2001 From: freetlab Date: Thu, 30 Jul 2026 22:13:43 +0200 Subject: [PATCH 4/6] fix(paises): correct the gap between the language and country lists Issue 3 (feedback-pruebas): t4:260 draws a 14px gap between "Tus idiomas" and "Todos", not 16. --- lib/pantallas/pantalla_paises.dart | 7 ++++++- test/pantallas/pantalla_paises_test.dart | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/pantallas/pantalla_paises.dart b/lib/pantallas/pantalla_paises.dart index ac4444c..4891aa0 100644 --- a/lib/pantallas/pantalla_paises.dart +++ b/lib/pantallas/pantalla_paises.dart @@ -134,7 +134,12 @@ class _PantallaPaisesState extends State { ), if (query.isEmpty) ...[ _seccionTusIdiomas(context, estado.paises, l10n), - const SizedBox(height: 16), + // Issue 3 (feedback-pruebas): t4:260 draws a 14px gap + // between "Tus idiomas" and "Todos", not 16. + const SizedBox( + height: 14, + key: ValueKey('paises-seccion-gap'), + ), _seccionTodos(context, estado.paises, l10n), ] else _seccionTodos(context, paisesFiltrados, l10n), diff --git a/test/pantallas/pantalla_paises_test.dart b/test/pantallas/pantalla_paises_test.dart index 1d15d9d..06f7683 100644 --- a/test/pantallas/pantalla_paises_test.dart +++ b/test/pantallas/pantalla_paises_test.dart @@ -262,6 +262,27 @@ void main() { expect(find.byIcon(Icons.search_rounded), findsOneWidget); }); + + testWidgets('Issue 3 (feedback-pruebas): the gap between "Tus idiomas" and ' + '"Todos" is 14, matching t4:260 -- not 16', (tester) async { + final estado = EstadoBusqueda( + radio: FakeServicioRadio( + paises: const [ + PaisRadio(nombre: 'Spain', codigoIso: 'ES', numeroEmisoras: 482), + ], + ), + ); + addTearDown(estado.dispose); + + await tester.pumpWidget(buildScreen(estado)); + await pumpEstable(tester); + + expect( + tester.getSize(find.byKey(const ValueKey('paises-seccion-gap'))).height, + 14, + reason: 't4:260 draws a 14px gap between the two eyebrow sections', + ); + }); }); testWidgets( From 3bb92c05365cac474dfa5e92854d14528ce53a02 Mon Sep 17 00:00:00 2001 From: freetlab Date: Thu, 30 Jul 2026 22:14:51 +0200 Subject: [PATCH 5/6] fix(grabaciones): correct the gap between the storage card and rows Issue 3 (feedback-pruebas): t4:617 draws a 16px gap between the storage usage card and the recordings list below it, not 12. --- lib/pantallas/pantalla_grabaciones.dart | 7 ++++- test/pantallas/pantalla_grabaciones_test.dart | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/pantallas/pantalla_grabaciones.dart b/lib/pantallas/pantalla_grabaciones.dart index 61f3d0c..3b6e5d4 100644 --- a/lib/pantallas/pantalla_grabaciones.dart +++ b/lib/pantallas/pantalla_grabaciones.dart @@ -251,7 +251,12 @@ class _PantallaGrabacionesState extends State { padding: PluriLayout.pageContentPadding, children: [ _BarraDeAlmacenamiento(archivos: archivos), - const SizedBox(height: 12), + // Issue 3 (feedback-pruebas): t4:617 draws a 16px gap between + // the storage card and the rows below it, not 12. + const SizedBox( + height: 16, + key: ValueKey('grabaciones-storage-gap'), + ), if (snap.connectionState == ConnectionState.done && archivos.isEmpty) PluriEmptyState( diff --git a/test/pantallas/pantalla_grabaciones_test.dart b/test/pantallas/pantalla_grabaciones_test.dart index fa64101..877b06e 100644 --- a/test/pantallas/pantalla_grabaciones_test.dart +++ b/test/pantallas/pantalla_grabaciones_test.dart @@ -216,6 +216,35 @@ void main() { }, ); + testWidgets( + 'Issue 3 (feedback-pruebas): the gap between the storage card and the ' + 'rows below is 16, matching t4:617 -- not 12', + (tester) async { + final estado = EstadoGrabacion( + servicio: _FakeServicioGrabacionConArchivos([ + fijaA, + ], maxBytesFijo: 200 * 1024 * 1024), + ); + addTearDown(estado.dispose); + + await tester.pumpWidget( + buildScreen( + estado: estado, + reproductor: _ReproductorGrabacionesFake(const {}), + ), + ); + await pumpStable(tester); + + expect( + tester + .getSize(find.byKey(const ValueKey('grabaciones-storage-gap'))) + .height, + 16, + reason: 't4:617 draws a 16px gap here', + ); + }, + ); + testWidgets('15.2-A: 3 recording fixtures render as 3 rows', (tester) async { final estado = EstadoGrabacion( servicio: _FakeServicioGrabacionConArchivos([ From db6f4a3a11bdb3065456d109505dba51870f6a73 Mon Sep 17 00:00:00 2001 From: freetlab Date: Thu, 30 Jul 2026 22:22:50 +0200 Subject: [PATCH 6/6] fix(alarma-sonando): put the date line below the hero time The prototype's order is pill (t4:415-416), then 7:30 at 88px (t4:417), then "Lunes, 3 de agosto" at 14px (t4:419). An earlier pass rendered the date between the pill and the time and cited "t4 line 419" as its justification -- but that line number is where the date SITS in the source, which is exactly why it comes last. Both the code and the test encoded the same misreading, so the test passed while the screen was wrong. --- lib/pantallas/pantalla_alarma_sonando.dart | 41 ++++++++++--------- .../pantalla_alarma_sonando_tier5_test.dart | 20 +++++---- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/lib/pantallas/pantalla_alarma_sonando.dart b/lib/pantallas/pantalla_alarma_sonando.dart index 0ce1d67..b476d32 100644 --- a/lib/pantallas/pantalla_alarma_sonando.dart +++ b/lib/pantallas/pantalla_alarma_sonando.dart @@ -225,25 +225,6 @@ class _PantallaAlarmaSonandoState extends State { tokens: tokens, ), const SizedBox(height: 22), - // Audit 9.4 (t4 line 419): "Lunes, 3 de agosto" between - // the pill and the hero time -- never rendered before. - // Purely additive: a new sibling Text, touching neither - // the pill above nor the hero time below. - Text( - fechaLargaConDiaSemana( - Localizations.localeOf(context).toString(), - DateTime.now(), - ), - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Theme.of( - context, - ).colorScheme.onSurface.withValues(alpha: 0.6), - ), - ), - const SizedBox(height: 6), FittedBox( fit: BoxFit.scaleDown, child: Text( @@ -261,6 +242,28 @@ class _PantallaAlarmaSonandoState extends State { ), ), const SizedBox(height: 6), + // Audit 9.4: the date line goes BELOW the hero time. The + // prototype's order is pill (t4:415-416) -> 7:30 at 88px + // (t4:417) -> "Lunes, 3 de agosto" at 14px (t4:419). An + // earlier pass placed it between the pill and the time + // and cited "t4 line 419" for it — that line number is + // where the date SITS in the source, which is precisely + // why it comes last, not first. + Text( + fechaLargaConDiaSemana( + Localizations.localeOf(context).toString(), + DateTime.now(), + ), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Theme.of( + context, + ).colorScheme.onSurface.withValues(alpha: 0.6), + ), + ), + const SizedBox(height: 6), Text( localizedAlarmName(l10n, alarma.nombre), textAlign: TextAlign.center, diff --git a/test/pantallas/pantalla_alarma_sonando_tier5_test.dart b/test/pantallas/pantalla_alarma_sonando_tier5_test.dart index f3277ab..93f6dbf 100644 --- a/test/pantallas/pantalla_alarma_sonando_tier5_test.dart +++ b/test/pantallas/pantalla_alarma_sonando_tier5_test.dart @@ -99,8 +99,8 @@ void main() { SharedPreferences.setMockInitialValues({}); }); - testWidgets('visual fidelity (audit 9.4): the date line renders between the ' - 'schedule pill and the hero time (t4:419)', (tester) async { + testWidgets('visual fidelity (audit 9.4): the date line renders BELOW the ' + 'hero time (t4:415-419: pill, then 7:30, then the date)', (tester) async { await _montarPantalla(tester); final localeTag = @@ -111,16 +111,22 @@ void main() { expect(find.text(esperado), findsOneWidget); - // Order: pill above the date line, date line above the hero time. + // Order: pill, then the hero time, then the date line. This test used + // to assert date-before-time and cited "t4:419" for it — but 419 is + // simply the source line the date occupies, and in the prototype it + // comes AFTER the 88px time on line 417. The citation refuted the + // assertion it was supporting. final pillY = tester .getBottomLeft(find.byKey(const ValueKey('ringing-schedule-pill'))) .dy; - final dateY = tester.getTopLeft(find.text(esperado)).dy; final timeY = - tester.getTopLeft(find.byKey(const ValueKey('ringing-hero-time'))).dy; - expect(pillY <= dateY, isTrue); - expect(dateY <= timeY, isTrue); + tester + .getBottomLeft(find.byKey(const ValueKey('ringing-hero-time'))) + .dy; + final dateY = tester.getTopLeft(find.text(esperado)).dy; + expect(pillY <= timeY, isTrue, reason: 'pill sits above the time'); + expect(timeY <= dateY, isTrue, reason: 'the date sits below the time'); // Regression guard: pumpAndSettle must still complete (purely // additive static text, no new animation).