import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:receipity/main.dart'; import 'package:receipity/models/line_item.dart'; import 'package:receipity/review_screen.dart'; import 'package:receipity/widgets/shop_heatmap.dart'; import 'test_helpers.dart'; void main() { ensureTestSqlite(); testWidgets('home screen shows overview and bottom navigation', ( tester, ) async { await tester.pumpWidget(ReceipityApp(repository: memoryRepository())); await pumpUntilFound(tester, find.text('Nothing logged yet.')); expect(find.text('Home'), findsWidgets); expect(find.text('Products'), findsOneWidget); expect(find.text('Lists'), findsOneWidget); expect(find.byTooltip('Add'), findsOneWidget); expect(find.byIcon(Icons.add), findsWidgets); expect(find.text('Shop log'), findsOneWidget); expect(find.byTooltip('Profile'), findsOneWidget); expect(find.byTooltip('Settings'), findsOneWidget); }); testWidgets('scan screen shows capture actions', (tester) async { await tester.pumpWidget(ReceipityApp(repository: memoryRepository())); await pumpUntilFound(tester, find.text('Overview')); await tester.tap(find.byTooltip('Add')); await tester.pump(); expect(find.text('Receipity'), findsOneWidget); expect(find.text('Take photo'), findsOneWidget); expect(find.text('Pick from gallery'), findsOneWidget); expect(find.text('Enter manually'), findsOneWidget); expect(find.text('Use sample receipt'), findsOneWidget); expect( find.textContaining('Scan a receipt or enter a trip by hand'), findsOneWidget, ); }); testWidgets('empty shop log hides edit and disables search', (tester) async { await tester.pumpWidget(ReceipityApp(repository: memoryRepository())); await pumpUntilFound(tester, find.text('Overview')); await tester.tap(find.text('Shop log')); await pumpUntilFound( tester, find.text('Scan a receipt or enter a trip to log it.'), ); expect(find.byTooltip('Edit'), findsNothing); expect(find.byTooltip('Search products'), findsOneWidget); expect( tester .widget( find.ancestor( of: find.byIcon(Icons.search), matching: find.byType(IconButton), ), ) .onPressed, isNull, ); }); testWidgets('deleting a trip removes it without leaving the screen', ( tester, ) async { final repository = memoryRepository(); await tester.runAsync(() async { await repository.saveShop( supermarket: 'Jumbo', shoppedAt: DateTime.now(), name: 'Weekly shop', items: [LineItem(id: '1', name: 'Milk', price: 1.5)], ); }); await tester.pumpWidget(ReceipityApp(repository: repository)); await pumpUntilFound(tester, find.text('Overview')); await tester.tap(find.text('Shop log')); await pumpUntilFound(tester, find.text('Weekly shop')); await tester.tap(find.byTooltip('Edit')); await tester.pump(); await tester.tap(find.byTooltip('Remove')); await tester.pump(); await tester.tap(find.text('Delete')); await tester.pump(); await tester.runAsync( () => Future.delayed(const Duration(milliseconds: 50)), ); await tester.pump(); expect(find.text('Weekly shop'), findsNothing); expect( find.text('Scan a receipt or enter a trip to log it.'), findsOneWidget, ); expect(find.byTooltip('Edit'), findsNothing); }); testWidgets('products edit mode shows delete, star, and wipe all', ( tester, ) async { final repository = memoryRepository(); await tester.runAsync(() async { await repository.saveShop( supermarket: 'Jumbo', shoppedAt: DateTime.now(), items: [LineItem(id: '1', name: 'Milk', price: 1.5)], ); }); await tester.pumpWidget(ReceipityApp(repository: repository)); await pumpUntilFound(tester, find.text('Overview')); await tester.tap(find.text('Products').last); await pumpUntilFound(tester, find.text('Milk')); await tester.tap(find.byTooltip('Edit')); await tester.pump(); expect(find.byTooltip('Delete'), findsOneWidget); expect(find.byTooltip('Favourite'), findsOneWidget); expect(find.byTooltip('Delete all products'), findsOneWidget); await tester.tap(find.byTooltip('Delete all products')); await tester.pump(); await tester.tap(find.text('Delete')); await tester.pump(); await tester.runAsync( () => Future.delayed(const Duration(milliseconds: 50)), ); await tester.pump(); expect(find.text('Milk'), findsNothing); expect(find.byTooltip('Edit'), findsNothing); }); testWidgets('profile screen is a placeholder', (tester) async { await tester.pumpWidget(ReceipityApp(repository: memoryRepository())); await pumpUntilFound(tester, find.text('Overview')); await tester.tap(find.byTooltip('Profile')); await pumpUntilFound(tester, find.text('Guest')); }); testWidgets('shop heatmap renders the visible month', (tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: ShopHeatmap( month: DateTime(2026, 8), counts: const {}, monthTotal: 0, monthTripCount: 0, canGoForward: false, onPreviousMonth: () {}, onNextMonth: () {}, onSelectDay: (_) {}, ), ), ), ); expect(find.text('August 2026'), findsOneWidget); expect(find.text('No trips this month'), findsOneWidget); expect(find.text('Less'), findsOneWidget); expect(find.text('More'), findsOneWidget); }); testWidgets('enter manually opens a blank trip', (tester) async { await tester.pumpWidget(ReceipityApp(repository: memoryRepository())); await pumpUntilFound(tester, find.text('Overview')); await tester.tap(find.byTooltip('Add')); await tester.pump(); await tester.tap(find.text('Enter manually')); await pumpUntilFound(tester, find.text('New trip')); expect(find.text('Add item'), findsOneWidget); }); testWidgets('lists tab shows shopping lists', (tester) async { await tester.pumpWidget(ReceipityApp(repository: memoryRepository())); await pumpUntilFound(tester, find.text('Overview')); await tester.tap(find.text('Lists')); await tester.pump(); expect(find.text('Shopping lists'), findsOneWidget); }); testWidgets('review screen lists items and can delete one', (tester) async { await tester.pumpWidget( MaterialApp( home: ReviewScreen( items: [ LineItem(id: '1', name: 'Milk', price: 1.5), LineItem(id: '2', name: 'Bread', price: 2), ], rawText: 'Milk 1.50\nBread 2.00', repository: memoryRepository(), ), ), ); expect(find.text('Milk'), findsOneWidget); expect(find.text('Bread'), findsOneWidget); expect(find.text('Add item'), findsOneWidget); expect(find.textContaining('Save trip'), findsOneWidget); expect(find.text('Supermarket'), findsOneWidget); expect(find.text('Trip name'), findsOneWidget); expect(find.text('Add tag'), findsOneWidget); await tester.drag(find.text('Milk'), const Offset(-500, 0)); await tester.pumpAndSettle(); expect(find.text('Milk'), findsNothing); expect(find.text('Bread'), findsOneWidget); }); testWidgets('review screen preselects a supermarket from OCR text', ( tester, ) async { await tester.pumpWidget( MaterialApp( home: ReviewScreen( items: [LineItem(id: '1', name: 'Milk', price: 1.5)], rawText: 'Jumbo\nMilk 1.50', repository: memoryRepository(), ), ), ); expect(find.text('Jumbo'), findsWidgets); }); }