Files
pluriwave/test/widgets/pluri_root_header_test.dart
T
FreeTLab e297413145 feat(tutorial): wire tutorial carousel into the first-launch flow
Insert PantallaTutorialAyuda.mostrarSiProcede between the welcome
screen and the recurring what's-new dialog in
_mostrarFlujoPrimerLanzamiento, so the carousel shows once on every
install -- fresh AND existing installs upgrading to this version --
via its own independent one-time flag, without racing either
surface.
2026-08-01 11:44:25 +02:00

101 lines
3.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pluriwave/l10n/gen/app_localizations.dart';
import 'package:pluriwave/tema/pluriwave_theme.dart';
import 'package:pluriwave/widgets/pluri_layout.dart';
import 'package:pluriwave/widgets/pluri_root_header.dart';
/// S1 (Tier 1 visual fidelity): the prototype draws no global `AppBar` —
/// each root instead owns a plain 56px title row inside its own content
/// (`t4`, e.g. Alarmas line 325 `height:56px`, Ajustes line 511, Explorar
/// line 641). [PluriRootHeader] is that row, shared by all 5 roots so the
/// sleep-timer action that used to live on `app.dart`'s single global
/// `AppBar` stays reachable from every tab.
void main() {
Widget host(Widget child) {
return MaterialApp(
theme: PluriWaveTheme.dark(),
locale: const Locale('en'),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Scaffold(body: child),
);
}
testWidgets('renders the given title and is exactly 56px tall', (
tester,
) async {
await tester.pumpWidget(
host(PluriRootHeader(title: 'Settings', onSleepTimer: () {})),
);
expect(find.text('Settings'), findsOneWidget);
expect(PluriRootHeader.height, 56);
final size = tester.getSize(find.byType(PluriRootHeader));
expect(size.height, 56);
});
testWidgets('S5: uses the title tier (20px) on the left, matching the '
"prototype's own header padding (t4 e.g. Alarmas "
'`padding:0 12px 0 20px`)', (tester) async {
await tester.pumpWidget(
host(PluriRootHeader(title: 'Settings', onSleepTimer: () {})),
);
final padding = tester.widget<Padding>(find.byType(Padding).first);
final insets = padding.padding as EdgeInsets;
expect(insets.left, PluriLayout.titleHorizontal);
expect(insets.right, PluriLayout.rowHorizontal);
});
testWidgets('exposes a bedtime action that invokes onSleepTimer when '
'tapped', (tester) async {
var tapped = false;
await tester.pumpWidget(
host(PluriRootHeader(title: 'Alarms', onSleepTimer: () => tapped = true)),
);
expect(find.byIcon(Icons.bedtime_outlined), findsOneWidget);
await tester.tap(find.byIcon(Icons.bedtime_outlined));
await tester.pump();
expect(tapped, isTrue);
});
testWidgets('never builds a Material AppBar', (tester) async {
await tester.pumpWidget(
host(PluriRootHeader(title: 'Search signal', onSleepTimer: () {})),
);
expect(find.byType(AppBar), findsNothing);
});
testWidgets('S2: renders optional actions BEFORE the bedtime button — a few '
"roots' single functional action (e.g. Alarmas' create-alarm button, "
"Buscar's filters entry point) that used to live on the now-retired "
'PluriScreenHeader', (tester) async {
await tester.pumpWidget(
host(
PluriRootHeader(
title: 'Alarms',
onSleepTimer: () {},
actions: [
IconButton(icon: const Icon(Icons.add_rounded), onPressed: () {}),
],
),
),
);
expect(find.byIcon(Icons.add_rounded), findsOneWidget);
expect(find.byIcon(Icons.bedtime_outlined), findsOneWidget);
final actionRect = tester.getRect(find.byIcon(Icons.add_rounded));
final bedtimeRect = tester.getRect(find.byIcon(Icons.bedtime_outlined));
expect(
actionRect.left,
lessThan(bedtimeRect.left),
reason: 'actions render before (to the left of) the bedtime button',
);
});
}