Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add testing for recipe_cubit #365

Merged
merged 2 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions kitchenowl/lib/cubits/item_search_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,15 @@ class ItemSearchCubit extends Cubit<ItemSearchState> {

void itemSelected(Item item) {
final List<Item> selectedItems = List.from(state.selectedItems);
final bool containsItem = state.selectedItems.contains(item);
if (containsItem) {
selectedItems.removeWhere((e) => e == item);
} else {
if(!selectedItems.remove(item)) {
selectedItems.add(item);
}
emit(ItemSearchState(selectedItems, '', state.searchResults));
}

Future<void> search(String query) async {
if (query.isNotEmpty) {
final splitIndex = query.indexOf(',');
String queryName = query;
String? queryDescription;
if (splitIndex >= 0) {
queryName = query.substring(0, splitIndex).trim();
queryDescription = query.substring(splitIndex + 1).trim();
}
final (queryName, queryDescription) = parseQuery(query);

List<Item> items = [];
for (Item item
Expand Down Expand Up @@ -58,6 +49,21 @@ class ItemSearchCubit extends Cubit<ItemSearchState> {
emit(ItemSearchState(state.selectedItems, query, state.searchResults));
}
}

/// Scans the [query] for a comma and if found,
/// returns a tuple consisting of the part before
/// the comma and the remaining string.
/// Otherwise returns the [query].
(String, String?) parseQuery(String query) {
final splitIndex = query.indexOf(",");
if (splitIndex >= 0) {
return (
query.substring(0, splitIndex).trim(),
query.substring(splitIndex + 1).trim()
);
}
return (query, null);
}
}

class ItemSearchState extends Equatable {
Expand Down
36 changes: 21 additions & 15 deletions kitchenowl/lib/cubits/recipe_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@ import 'package:kitchenowl/services/transactions/shoppinglist.dart';

class RecipeCubit extends Cubit<RecipeState> {
final Household? household;
final TransactionHandler _transactionHandler;

RecipeCubit({this.household, required Recipe recipe, int? selectedYields})
: super(RecipeState(recipe: recipe, selectedYields: selectedYields)) {
RecipeCubit(Household? household, Recipe recipe, int? selectedYields)
: this.forTesting(TransactionHandler.getInstance(), household, recipe, selectedYields);

RecipeCubit.forTesting(
TransactionHandler transactionHandler,
this.household,
Recipe recipe,
int? selectedYields)
: _transactionHandler = transactionHandler,
super(RecipeState(recipe: recipe, selectedYields: selectedYields)) {
refresh();
}

void itemSelected(RecipeItem item) {
final List<String> selectedItems = List.from(state.selectedItems);
if (selectedItems.contains(item.name)) {
selectedItems.remove(item.name);
} else {
final Set<String> selectedItems = Set.from(state.selectedItems);
if (!selectedItems.remove(item.name)) {
selectedItems.add(item.name);
}
emit(state.copyWith(selectedItems: selectedItems));
Expand All @@ -40,11 +47,11 @@ class RecipeCubit extends Cubit<RecipeState> {
}

Future<void> refresh() async {
final recipe = TransactionHandler.getInstance()
final recipe = _transactionHandler
.runTransaction(TransactionRecipeGetRecipe(recipe: state.recipe));
Future<List<ShoppingList>>? shoppingLists;
if (household != null) {
shoppingLists = TransactionHandler.getInstance().runTransaction(
shoppingLists = _transactionHandler.runTransaction(
TransactionShoppingListGet(household: household!),
forceOffline: true,
);
Expand All @@ -60,7 +67,7 @@ class RecipeCubit extends Cubit<RecipeState> {
Future<void> addItemsToList([ShoppingList? shoppingList]) async {
shoppingList ??= household?.defaultShoppingList;
if (shoppingList != null) {
await TransactionHandler.getInstance()
await _transactionHandler
.runTransaction(TransactionShoppingListAddRecipeItems(
shoppinglist: shoppingList,
items: state.dynamicRecipe.items
Expand All @@ -72,8 +79,7 @@ class RecipeCubit extends Cubit<RecipeState> {

Future<void> addRecipeToPlanner({int? day, bool updateOnAdd = false}) async {
if (household != null) {
await TransactionHandler.getInstance()
.runTransaction(TransactionPlannerAddRecipe(
await _transactionHandler.runTransaction(TransactionPlannerAddRecipe(
household: household!,
recipePlan: RecipePlan(
recipe: state.recipe,
Expand All @@ -89,8 +95,8 @@ class RecipeCubit extends Cubit<RecipeState> {
}
}

class RecipeState extends Equatable {
final List<String> selectedItems;
final class RecipeState extends Equatable {
final Set<String> selectedItems;
final Recipe recipe;
final Recipe dynamicRecipe;
final int selectedYields;
Expand All @@ -113,11 +119,11 @@ class RecipeState extends Equatable {
}) : selectedYields = selectedYields ?? recipe.yields,
dynamicRecipe = recipe.withYields(selectedYields ?? recipe.yields),
selectedItems =
recipe.items.where((e) => !e.optional).map((e) => e.name).toList();
recipe.items.where((e) => !e.optional).map((e) => e.name).toSet();

RecipeState copyWith({
Recipe? recipe,
List<String>? selectedItems,
Set<String>? selectedItems,
int? selectedYields,
UpdateEnum? updateState,
List<ShoppingList>? shoppingLists,
Expand Down
6 changes: 1 addition & 5 deletions kitchenowl/lib/cubits/recipe_list_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,7 @@ class RecipeListCubit extends Cubit<RecipeListState> {
if (state is SearchRecipeListState) {
query = query ?? state.query;
}
if (_refreshThread != null && query != _refreshCurrentQuery) {
_refreshCurrentQuery = query;
_refreshThread = _refresh(query);
}
if (_refreshThread == null) {
if (_refreshThread == null || query != _refreshCurrentQuery) {
_refreshCurrentQuery = query;
_refreshThread = _refresh(query);
}
Expand Down
6 changes: 3 additions & 3 deletions kitchenowl/lib/pages/recipe_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ class _RecipePageState extends State<RecipePage> {
void initState() {
super.initState();
cubit = RecipeCubit(
household: widget.household,
recipe: widget.recipe,
selectedYields: widget.selectedYields,
widget.household,
widget.recipe,
widget.selectedYields,
);
}

Expand Down
5 changes: 3 additions & 2 deletions kitchenowl/lib/services/transaction_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import 'package:kitchenowl/services/storage/transaction_storage.dart';
class TransactionHandler {
static TransactionHandler? _instance;

TransactionHandler._internal();
TransactionHandler.internal();

static TransactionHandler getInstance() {
_instance ??= TransactionHandler._internal();
_instance ??= TransactionHandler.internal();

return _instance!;
}
Expand Down
12 changes: 12 additions & 0 deletions kitchenowl/test/cubits/local_only_transaction_handler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'package:kitchenowl/services/transaction.dart';
import 'package:kitchenowl/services/transaction_handler.dart';

class LocalOnlyTransactionHandler extends TransactionHandler {
LocalOnlyTransactionHandler() : super.internal();

@override
Future<T> runTransaction<T>(Transaction<T> t,
{bool forceOffline = false, bool saveTransaction = true}) {
return t.runLocal();
}
}
45 changes: 45 additions & 0 deletions kitchenowl/test/cubits/recipe_cubit_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:kitchenowl/cubits/recipe_cubit.dart';
import 'package:kitchenowl/models/item.dart';
import 'package:kitchenowl/models/recipe.dart';

import 'local_only_transaction_handler.dart';

const flour = RecipeItem(name: "Flour");
const salt = RecipeItem(name: "Salt");
const recipe = Recipe(
id: 100,
name: "foo",
description: "The desc",
items: [flour, salt],
yields: 1);

RecipeCubit createSampleCubit() =>
RecipeCubit.forTesting(LocalOnlyTransactionHandler(), null, recipe, 1);

void main() {
test("Item selection works", () {
final cubit = createSampleCubit();
final allItems = recipe.mandatoryItems.map((e) => e.name).toSet();

expect(cubit.state.selectedItems, allItems);

cubit.itemSelected(flour);
expect(cubit.state.selectedItems, {salt.name});

cubit.itemSelected(flour);
expect(cubit.state.selectedItems, allItems);

cubit.itemSelected(flour);
cubit.itemSelected(salt);
expect(cubit.state.selectedItems, isEmpty);
});

test("Changing the yield works", () {
final cubit = createSampleCubit();
expect(cubit.state.selectedYields, 1);

cubit.setSelectedYields(4);
expect(cubit.state.selectedYields, 4);
});
}
Loading