import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:halkyon_ui/halkyon_ui.dart'; import 'package:material_ui/material_ui.dart'; import '../support/test_app.dart'; void main() { late StreamController> items; setUp(() => items = StreamController()); tearDown(() => items.close()); /// Opens the screen of the item [id] over a first screen. Future open( WidgetTester tester, String id, { ({String label, VoidCallback onPressed})? wayBack, }) async { await tester.pumpWidget( testApp( Builder( builder: (context) => TextButton( onPressed: () => Navigator.of(context).push( MaterialPageRoute( builder: (context) => FoundById( id: id, items: () => items.stream, idOf: (item) => item, builder: (item, items) => Scaffold(body: Text('Item $item of ${items.length}')), wayBack: wayBack, ), ), ), child: const Text('Open'), ), ), ), ); await tester.tap(find.text('Open')); // Through the opening transition; the spinner never settles. await tester.pump(); await tester.pump(const Duration(seconds: 1)); } testWidgets('shows a spinner until the list arrives, then the item', ( tester, ) async { await open(tester, 'a'); expect(find.byType(AppLoadingIndicator), findsOneWidget); items.add(['a', 'b']); await tester.pump(); expect(find.text('Item a of 2'), findsOneWidget); expect(find.byType(AppLoadingIndicator), findsNothing); }); testWidgets('says that an item missing from the list no longer exists', ( tester, ) async { await open(tester, 'c'); items.add(['a', 'b']); await tester.pump(); expect(find.textContaining('no longer exists'), findsOneWidget); }); testWidgets('leads the way back from there, as the app says', ( tester, ) async { var ledBack = 0; await open( tester, 'c', wayBack: (label: 'To the library', onPressed: () => ledBack++), ); items.add(['a']); await tester.pump(); await tester.tap(find.text('To the library')); expect(ledBack, 1); }); testWidgets('says so once the item goes while its screen is open', ( tester, ) async { await open(tester, 'a'); items.add(['a']); await tester.pump(); // Deleted on another device, say. items.add([]); await tester.pump(); expect(find.text('Item a of 1'), findsNothing); expect(find.textContaining('no longer exists'), findsOneWidget); }); testWidgets('a screen that closes as its item goes keeps showing the item ' 'on its way out', (tester) async { await open(tester, 'a'); items.add(['a']); await tester.pump(); // As when the screen deleted its item and closes. Navigator.of(tester.element(find.text('Item a of 1'))).pop(); items.add([]); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); expect(find.text('Item a of 1'), findsOneWidget); expect(find.textContaining('no longer exists'), findsNothing); await tester.pumpAndSettle(); expect(find.text('Open'), findsOneWidget); }); }