import 'package:cookit/src/recipes/models/recipe.dart'; import 'package:cookit/src/recipes/views/widgets/recipe_card.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../support/fixtures.dart'; import '../support/test_app.dart'; /// A Recipe name as shown on a grid card (the suggestion card may show it too). Finder inGrid(String text) => find.descendant(of: find.byType(RecipeCard), matching: find.text(text)); void main() { testWidgets('home grid shows Recipes and filters them by search, Course and review', (tester) async { final app = await TestApp.create(tester); final dessert = (await tester.runAsync(() => app.courses.findOrCreate('Dessert')))!; await tester.runAsync(() async { await app.recipes.saveRecipe(recipe(id: 'a', name: 'Käsespätzle', tags: ['schwäbisch'])); await app.recipes.saveRecipe( recipe(id: 'b', name: 'Tiramisu', courseId: dessert.id, reviewReasons: ['Portionen fehlen.']), ); }); await tester.pumpWidget(app.build()); await app.settle(tester); expect(inGrid('Käsespätzle'), findsOneWidget); expect(inGrid('Tiramisu'), findsOneWidget); expect(find.text('IDEE FÜR HEUTE'), findsOneWidget); await tester.enterText(find.byType(TextField), 'kase'); await tester.pumpAndSettle(); expect(inGrid('Käsespätzle'), findsOneWidget); expect(inGrid('Tiramisu'), findsNothing); await tester.enterText(find.byType(TextField), ''); await tester.tap(find.text('1 Rezept wartet auf deinen Blick')); await tester.pumpAndSettle(); expect(inGrid('Käsespätzle'), findsNothing); expect(inGrid('Tiramisu'), findsOneWidget); await tester.tap(find.text('Nur Rezepte zum Prüfen – alle zeigen')); await tester.pumpAndSettle(); final chips = find.byWidgetPredicate((w) => w is ListView && w.scrollDirection == Axis.horizontal); final dessertChip = find.descendant(of: chips, matching: find.text('Dessert')); await tester.scrollUntilVisible( dessertChip, 200, scrollable: find.descendant(of: chips, matching: find.byType(Scrollable)), ); await tester.tap(dessertChip); await tester.pumpAndSettle(); expect(inGrid('Tiramisu'), findsOneWidget); expect(inGrid('Käsespätzle'), findsNothing); await app.dispose(tester); }); testWidgets('Cooking Mode walks through the ingredients and every step', (tester) async { final app = await TestApp.create(tester); await tester.runAsync(() => app.recipes.saveRecipe(recipe())); await tester.pumpWidget(app.build()); await app.settle(tester); await tester.tap(inGrid('Focaccia')); await app.settle(tester); await tester.tap(find.text('Kochmodus starten')); await app.settle(tester); expect(find.text('Bereit zum Kochen?'), findsOneWidget); expect(find.text('300 g'), findsOneWidget); await tester.tap(find.byTooltip('Mehr Portionen')); await tester.pumpAndSettle(); expect(find.text('5'), findsOneWidget); expect(find.text('375 g'), findsOneWidget); await tester.tap(find.text('Los geht’s')); await tester.pumpAndSettle(); expect(find.text('Schritt 1 von 2'), findsOneWidget); expect(find.text('Kneten.'), findsOneWidget); expect(find.text('Teig'), findsOneWidget); await tester.tap(find.text('Weiter')); await tester.pumpAndSettle(); expect(find.text('Gehen lassen.'), findsOneWidget); await tester.tap(find.text('Fertig')); await tester.pumpAndSettle(); expect(find.text('Guten Appetit!'), findsOneWidget); await tester.tap(find.text('Zurück zum Rezept')); await app.settle(tester); expect(find.text('Kochmodus starten'), findsOneWidget); await app.dispose(tester); }); testWidgets('the heart on a card toggles the favourite', (tester) async { final app = await TestApp.create(tester); await tester.runAsync(() => app.recipes.saveRecipe(recipe())); await tester.pumpWidget(app.build()); await app.settle(tester); await tester.tap(find.descendant(of: find.byType(RecipeCard), matching: find.byTooltip('Favorit'))); await app.settle(tester); expect((await tester.runAsync(app.recipes.allRecipes))!.single.favourite, isTrue); await app.dispose(tester); }); testWidgets('empty collection explains how to start', (tester) async { final app = await TestApp.create(tester); await tester.pumpWidget(app.build()); await app.settle(tester); expect(find.text('Noch keine Rezepte'), findsOneWidget); await app.dispose(tester); }); testWidgets('detail shows the Recipe, and "Erledigt" clears its Review Flag', (tester) async { final app = await TestApp.create(tester); await tester.runAsync(() => app.recipes.saveRecipe(recipe(reviewReasons: ['Portionen fehlen.']))); await tester.pumpWidget(app.build()); await app.settle(tester); await tester.tap(inGrid('Focaccia')); await app.settle(tester); expect(find.text('Bitte prüfen'), findsOneWidget); expect(find.text('• Portionen fehlen.'), findsOneWidget); expect(find.text('300 g'), findsOneWidget); expect(find.text('2–3 EL'), findsOneWidget); expect(find.text('Topping'), findsOneWidget); expect(find.text('775 kcal'), findsOneWidget); expect(find.text('pro Portion'), findsOneWidget); expect(find.text('50 Min.'), findsOneWidget); expect(find.text('22x22 cm Form'), findsOneWidget, reason: 'Notes show under the Zutaten tab too'); await tester.tap(find.text('Zubereitung · 2')); await tester.pumpAndSettle(); expect(find.text('Teig'), findsOneWidget); expect(find.text('Kneten.'), findsOneWidget); expect(find.text('22x22 cm Form'), findsOneWidget); await tester.tap(find.text('Erledigt')); await app.settle(tester); expect(find.text('Bitte prüfen'), findsNothing); await app.dispose(tester); }); testWidgets('a new Recipe can be created with ingredients and steps', (tester) async { final app = await TestApp.create(tester); await tester.pumpWidget(app.build()); await app.settle(tester); await tester.tap(find.byTooltip('Neues Rezept')); await app.settle(tester); await tester.tap(find.text('Speichern')); await tester.pumpAndSettle(); expect(find.text('Bitte gib dem Rezept einen Namen.'), findsOneWidget); await tester.enterText(find.widgetWithText(TextFormField, 'Name'), 'Pfannkuchen'); await tester.enterText(find.widgetWithText(TextFormField, 'Portionen'), '2'); final ingredientName = find.widgetWithText(TextFormField, 'Zutat'); await tester.enterText(find.widgetWithText(TextFormField, 'Menge'), '1,5'); await tester.enterText(ingredientName, 'Mehl'); await tester.tap(find.text('–')); await tester.pumpAndSettle(); expect(find.text('Bund'), findsNothing); await tester.tap(find.text('Weitere Einheiten …')); await tester.pumpAndSettle(); await tester.tap(find.widgetWithText(ChoiceChip, 'Bund')); await tester.pumpAndSettle(); expect(find.text('Bund'), findsOneWidget); await tester.enterText(find.widgetWithText(TextFormField, 'Schritt 1'), 'Alles verrühren.'); await tester.tap(find.text('Speichern')); await app.settle(tester); expect(inGrid('Pfannkuchen'), findsOneWidget); final saved = (await tester.runAsync(app.recipes.allRecipes))!.single; expect(saved.servings, 2); expect(saved.ingredientGroups.single.lines.single.amount, 1.5); expect(saved.ingredientGroups.single.lines.single.name, 'Mehl'); expect(saved.ingredientGroups.single.lines.single.unitKey, 'bunch'); expect(saved.stepSections.single.steps, ['Alles verrühren.']); expect(saved.calories, isNull); expect(saved.needsReview, isFalse); await app.dispose(tester); }); testWidgets('an invalid amount blocks saving', (tester) async { final app = await TestApp.create(tester); await tester.pumpWidget(app.build()); await app.settle(tester); await tester.tap(find.byTooltip('Neues Rezept')); await app.settle(tester); await tester.enterText(find.widgetWithText(TextFormField, 'Name'), 'Test'); await tester.enterText(find.widgetWithText(TextFormField, 'Menge'), 'viel'); await tester.tap(find.text('Speichern')); await app.settle(tester); expect(find.text('z. B. 2, 1,5, ½ oder 2-3'), findsOneWidget); expect(await tester.runAsync(app.recipes.allRecipes), isEmpty); await app.dispose(tester); }); testWidgets('editing keeps favourite and Review Flag', (tester) async { final app = await TestApp.create(tester); await tester.runAsync(() => app.recipes.saveRecipe(recipe(favourite: true, reviewReasons: ['x']))); await tester.pumpWidget(app.build()); await app.settle(tester); await tester.tap(inGrid('Focaccia')); await app.settle(tester); await tester.tap(find.byTooltip('Bearbeiten')); await app.settle(tester); await tester.enterText(find.widgetWithText(TextFormField, 'Name'), 'Focaccia mit Rosmarin'); await tester.tap(find.text('Speichern')); await app.settle(tester); final saved = (await tester.runAsync(app.recipes.allRecipes))!.single; expect(saved.name, 'Focaccia mit Rosmarin'); expect(saved.favourite, isTrue); expect(saved.reviewReasons, ['x']); expect(saved.calories!.basis, CaloriesBasis.perServing); expect(saved.ingredientGroups.map((g) => g.name), [null, 'Topping']); expect(saved.stepSections.single.title, 'Teig'); await app.dispose(tester); }); }