Initial commit: CookIT recipe collection and week planner
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
7d7a0bc60b
173 files changed
+22803
No files matched your search
@@ -0,0 +1,232 @@
|
||||
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);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user