import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pluriwave/app.dart'; import 'package:pluriwave/estado/estado_entitlement.dart'; import 'package:pluriwave/servicios/servicio_anuncios.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// S1 (Tier 1 visual fidelity): the prototype (`t4`) never draws a global /// `AppBar` — every root owns its own 56px title row instead (see /// `PluriRootHeader` and `root_header_wiring_test.dart`). `app.dart` used to /// wrap every tab in `PluriWaveScaffold(appBar: AppBar(...))`; this is a /// fast source-level regression guard for that removal, since the widget /// under it (`_PaginaPrincipal`) is library-private and constructs real /// platform-backed services, so it cannot be safely widget-tested here. void main() { test('app.dart no longer constructs a global Material AppBar', () { final source = File('lib/app.dart').readAsStringSync(); expect( source.contains('AppBar('), isFalse, reason: 'the prototype has no global app bar — each root draws its own ' 'PluriRootHeader inside its content instead', ); }); test('the first-launch sequence runs the welcome screen, then the tutorial ' 'carousel, then the recurring what-is-new dialog, in that order', () { // `_PaginaPrincipal` is library-private and its // `_mostrarFlujoPrimerLanzamiento` constructs real platform-backed // services, so it cannot be safely widget-tested here (same // constraint as the AppBar guard above). This is a fast source-level // ordering guard instead: PantallaBienvenida.mostrarSiProcede must // run before PantallaTutorialAyuda.mostrarSiProcede, which must run // before the unrelated, pre-existing _mostrarOnboardingInicial() call // -- so the tutorial shows once on every launch sequence (fresh // installs AND existing installs upgrading to this version) without // ever racing the welcome screen or the what's-new dialog. final source = File('lib/app.dart').readAsStringSync(); final indiceBienvenida = source.indexOf( 'PantallaBienvenida.mostrarSiProcede', ); final indiceTutorial = source.indexOf( 'PantallaTutorialAyuda.mostrarSiProcede', ); final indiceOnboarding = source.indexOf('_mostrarOnboardingInicial()'); expect( indiceBienvenida, greaterThanOrEqualTo(0), reason: 'PantallaBienvenida.mostrarSiProcede must still be called', ); expect( indiceTutorial, greaterThanOrEqualTo(0), reason: 'PantallaTutorialAyuda.mostrarSiProcede must be wired in', ); expect( indiceOnboarding, greaterThanOrEqualTo(0), reason: '_mostrarOnboardingInicial() must still be called', ); expect( indiceBienvenida, lessThan(indiceTutorial), reason: 'the welcome screen must run before the tutorial carousel', ); expect( indiceTutorial, lessThan(indiceOnboarding), reason: 'the tutorial carousel must run before the what-is-new dialog', ); }); group( 'construirCuerpoPrincipal — banner y la status bar (FIX 1, code review)', () { setUp(() { SharedPreferences.setMockInitialValues({}); }); Future bombear(WidgetTester tester, {required bool premium}) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(padding: EdgeInsets.only(top: 44)), child: MaterialApp( home: MultiProvider( providers: [ ChangeNotifierProvider( create: (_) => EstadoEntitlement(prefs: null), ), Provider( create: (_) => ServicioAnuncios(esPremium: () => premium), ), ], child: Scaffold( body: construirCuerpoPrincipal( contenido: const Align( alignment: Alignment.topLeft, child: Text('contenido'), ), ), ), ), ), ), ); await tester.pump(); await tester.pump(const Duration(milliseconds: 50)); } testWidgets( 'usuario premium: el contenido arranca en y=0 -- edge-to-edge, sin ' 'franja en blanco reservada para la status bar', (tester) async { await bombear(tester, premium: true); expect(tester.getTopLeft(find.text('contenido')).dy, 0); }, ); testWidgets( 'usuario free con el banner aún sin cargar: el contenido arranca ' 'igualmente en y=0 -- misma posición edge-to-edge que antes del ' 'cambio, no una franja reservada de 44px hasta que el ad cargue', (tester) async { await bombear(tester, premium: false); expect(tester.getTopLeft(find.text('contenido')).dy, 0); }, ); }, ); }