diff --git a/app/src/androidTest/java/com/ivy/wallet/compose/helpers/HomeTab.kt b/app/src/androidTest/java/com/ivy/wallet/compose/helpers/HomeTab.kt index 69658cefa..931bc949b 100644 --- a/app/src/androidTest/java/com/ivy/wallet/compose/helpers/HomeTab.kt +++ b/app/src/androidTest/java/com/ivy/wallet/compose/helpers/HomeTab.kt @@ -20,6 +20,7 @@ class HomeTab( currency: String = "USD" ): HomeTab { composeTestRule.onNodeWithTag("home_balance") + .performScrollTo() .assertTextEquals(currency, amount, amountDecimal) return this } @@ -129,8 +130,10 @@ class HomeTab( composeTestRule.onNodeWithTag( testTag = "upcoming_title", useUnmergedTree = true - ).performClick() - return this + ) + .performScrollTo() + .performClick() + return this } fun clickTransactionPay(): HomeTab { @@ -143,6 +146,16 @@ class HomeTab( return this } + fun clickTransactionSkip(): HomeTab { + composeTestRule.onNode( + hasText("Skip") + .and(hasAnyAncestor(hasTestTag("transaction_card"))) + ) + .performScrollTo() + .performClick() + return this + } + fun assertGreeting( greeting: String ): HomeTab { diff --git a/app/src/androidTest/java/com/ivy/wallet/compose/helpers/ItemStatisticScreen.kt b/app/src/androidTest/java/com/ivy/wallet/compose/helpers/ItemStatisticScreen.kt index 1fd12f873..86fcbfe11 100644 --- a/app/src/androidTest/java/com/ivy/wallet/compose/helpers/ItemStatisticScreen.kt +++ b/app/src/androidTest/java/com/ivy/wallet/compose/helpers/ItemStatisticScreen.kt @@ -1,5 +1,9 @@ package com.ivy.wallet.compose.helpers +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.* +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.compose.ui.test.assertTextEquals import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText @@ -24,10 +28,39 @@ open class ItemStatisticScreen( fun clickClose(next: N): N { composeTestRule.onNodeWithTag("toolbar_close") + .performScrollTo() .performClick() return next } + fun clickUpcoming() : ItemStatisticScreen { + composeTestRule.onNodeWithTag( + testTag = "upcoming_title", + useUnmergedTree = true + ).performClick() + return this + } + + fun clickTransactionSkip() : ItemStatisticScreen{ + composeTestRule.onNode( + hasText("Skip") + .and(hasAnyAncestor(hasTestTag("transaction_card"))) + ) + .performScrollTo() + .performClick() + return this + } + + fun clickTransactionPay(): ItemStatisticScreen{ + composeTestRule.onNode( + hasText("Pay") + .and(hasAnyAncestor(hasTestTag("transaction_card"))) + ) + .performScrollTo() + .performClick() + return this + } + fun assertBalance( balance: String, balanceDecimal: String, diff --git a/app/src/androidTest/java/com/ivy/wallet/compose/scenario/PlannedPaymentsTest.kt b/app/src/androidTest/java/com/ivy/wallet/compose/scenario/PlannedPaymentsTest.kt index c342a4aa8..97406085d 100644 --- a/app/src/androidTest/java/com/ivy/wallet/compose/scenario/PlannedPaymentsTest.kt +++ b/app/src/androidTest/java/com/ivy/wallet/compose/scenario/PlannedPaymentsTest.kt @@ -3,11 +3,14 @@ package com.ivy.wallet.compose.scenario import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import com.ivy.wallet.compose.IvyComposeTest +import com.ivy.wallet.compose.helpers.* +import com.ivy.wallet.compose.waitMillis import com.ivy.wallet.compose.helpers.EditPlannedScreen import com.ivy.wallet.compose.helpers.HomeTab import com.ivy.wallet.compose.helpers.PlannedPaymentsScreen import com.ivy.wallet.domain.data.IntervalType import com.ivy.wallet.domain.data.TransactionType +import com.ivy.wallet.ui.main.MainTab import com.ivy.wallet.utils.timeNowUTC import dagger.hilt.android.testing.HiltAndroidTest import org.junit.Test @@ -15,6 +18,7 @@ import org.junit.Test @HiltAndroidTest class PlannedPaymentsTest : IvyComposeTest() { + @Test fun Onboard_CreatePlannedPaymentFromPrompt() = testWithRetry { quickOnboarding() @@ -249,4 +253,107 @@ class PlannedPaymentsTest : IvyComposeTest() { amountDecimal = ".00" ) } + + @Test + fun skipPlannedPaymentsOnHomeTab() = testWithRetry{ + quickOnboarding() + .clickAddFAB() + .clickAddPlannedPayment() + .addPlannedPayment( + next = HomeTab(composeTestRule), + type = TransactionType.EXPENSE, + oneTime = true, + amount = "530.25", + category = "Transport", + startDate = null, + intervalN = null, + intervalType = null, + title = "Netherlands airplane" + ) + .clickUpcoming() + .clickTransactionSkip() + .assertUpcomingDoesNotExist() + } + + @Test + fun payPlannedPaymentsOnHomeTab() = testWithRetry{ + quickOnboarding() + .clickAddFAB() + .clickAddPlannedPayment() + .addPlannedPayment( + next = HomeTab(composeTestRule), + type = TransactionType.EXPENSE, + oneTime = true, + amount = "530.25", + category = "Transport", + startDate = null, + intervalN = null, + intervalType = null, + title = "Netherlands airplane" + ) + .clickUpcoming() + .clickTransactionPay() + .assertUpcomingDoesNotExist() + .assertBalance( + amount = "-530", + amountDecimal = ".25" + ) + } + + @Test + fun skipPlannedPaymentsOnAccountTab() = testWithRetry{ + quickOnboarding() + .clickAddFAB() + .clickAddPlannedPayment() + .addPlannedPayment( + next = HomeTab(composeTestRule), + type = TransactionType.EXPENSE, + oneTime = true, + amount = "530.25", + category = "Transport", + startDate = null, + intervalN = null, + intervalType = null, + title = "Netherlands airplane" + ) + .clickAccountsTab() + .clickAccount("Cash") + .clickUpcoming() + .clickTransactionSkip() + .clickClose(AccountsTab(composeTestRule)) + .clickHomeTab() + .assertUpcomingDoesNotExist() + + //Wait until the upcoming payments are loaded + /*composeTestRule.waitMillis(500)*/ + } + + @Test + fun payPlannedPaymentsOnAccountTab() = testWithRetry{ + quickOnboarding() + .clickAddFAB() + .clickAddPlannedPayment() + .addPlannedPayment( + next=HomeTab(composeTestRule), + type = TransactionType.EXPENSE, + oneTime = true, + amount = "530.25", + category = "Transport", + startDate = null, + intervalN = null, + intervalType = null, + title = "Netherlands airplane" + ) + .clickAccountsTab() + .clickAccount("Cash") + .clickUpcoming() + .clickTransactionPay() + .clickClose(AccountsTab(composeTestRule)) + .clickHomeTab() + .assertUpcomingDoesNotExist() + .assertBalance( + amount = "-530", + amountDecimal = ".25" + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/ivy/wallet/ui/statistic/level2/ItemStatisticScreen.kt b/app/src/main/java/com/ivy/wallet/ui/statistic/level2/ItemStatisticScreen.kt index d8e1ba61b..44e7ee53c 100644 --- a/app/src/main/java/com/ivy/wallet/ui/statistic/level2/ItemStatisticScreen.kt +++ b/app/src/main/java/com/ivy/wallet/ui/statistic/level2/ItemStatisticScreen.kt @@ -51,6 +51,8 @@ import com.ivy.wallet.ui.theme.modal.edit.CategoryModal import com.ivy.wallet.ui.theme.modal.edit.CategoryModalData import com.ivy.wallet.ui.theme.wallet.PeriodSelector import com.ivy.wallet.utils.* +import java.math.BigDecimal +import java.util.* @Composable @@ -158,6 +160,12 @@ fun BoxWithConstraintsScope.ItemStatisticScreen(screen: ItemStatistic) { }, onPayOrGet = { transaction -> viewModel.payOrGet(screen, transaction) + }, + onSkipTransaction = { transaction -> + viewModel.skipTransaction(screen, transaction) + }, + onSkipAllTransactions = { transactions -> + viewModel.skipTransactions(screen, transactions) } ) } @@ -202,13 +210,16 @@ private fun BoxWithConstraintsScope.UI( onEditAccount: (Account, Double) -> Unit, onEditCategory: (Category) -> Unit, onDelete: () -> Unit, - onPayOrGet: (Transaction) -> Unit = {} + onPayOrGet: (Transaction) -> Unit = {}, + onSkipTransaction: (Transaction) -> Unit = {}, + onSkipAllTransactions: (List) -> Unit = {} ) { val ivyContext = ivyWalletCtx() val nav = navigation() val itemColor = (account?.color ?: category?.color)?.toComposeColor() ?: Gray var deleteModalVisible by remember { mutableStateOf(false) } + var skipAllModalVisible by remember { mutableStateOf(false) } var categoryModalData: CategoryModalData? by remember { mutableStateOf(null) } var accountModalData: AccountModalData? by remember { mutableStateOf(null) } var choosePeriodModal: ChoosePeriodModalData? by remember { mutableStateOf(null) } @@ -368,6 +379,8 @@ private fun BoxWithConstraintsScope.UI( }, onPayOrGet = onPayOrGet, + onSkipTransaction = onSkipTransaction, + onSkipAllTransactions = { skipAllModalVisible = true }, emptyStateTitle = stringRes(R.string.no_transactions), emptyStateText = stringRes( R.string.no_transactions_for_period, @@ -390,6 +403,16 @@ private fun BoxWithConstraintsScope.UI( onDelete() } + DeleteModal( + visible = skipAllModalVisible, + title = stringResource(R.string.confirm_skip_all), + description = stringResource(R.string.confirm_skip_all_description), + dismiss = { skipAllModalVisible = false } + ) { + onSkipAllTransactions(overdue) + skipAllModalVisible = false + } + CategoryModal( modal = categoryModalData, onCreateCategory = { }, @@ -923,4 +946,39 @@ private fun Preview_crypto() { onEditCategory = {} ) } +} + +@Preview +@Composable +private fun Preview_empty_upcoming() { + IvyWalletPreview { + UI( + period = TimePeriod.currentMonth( + startDayOfMonth = 1 + ), //preview + baseCurrency = "BGN", + currency = "BGN", + + categories = emptyList(), + accounts = emptyList(), + + balance = 1314.578, + balanceBaseCurrency = null, + income = 8000.0, + expenses = 6000.0, + + history = emptyList(), + category = null, + account = Account("DSK", color = GreenDark.toArgb(), icon = "pet"), + onSetPeriod = { }, + onPreviousMonth = {}, + onNextMonth = {}, + onDelete = {}, + onEditAccount = { _, _ -> }, + onEditCategory = {}, + upcoming = listOf( + Transaction(UUID(1L,2L),TransactionType.EXPENSE, BigDecimal.valueOf(10L)) + ) + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/ivy/wallet/ui/statistic/level2/ItemStatisticViewModel.kt b/app/src/main/java/com/ivy/wallet/ui/statistic/level2/ItemStatisticViewModel.kt index dd4bc7b5c..7afdfb333 100644 --- a/app/src/main/java/com/ivy/wallet/ui/statistic/level2/ItemStatisticViewModel.kt +++ b/app/src/main/java/com/ivy/wallet/ui/statistic/level2/ItemStatisticViewModel.kt @@ -622,4 +622,40 @@ class ItemStatisticViewModel @Inject constructor( TestIdlingResource.decrement() } } + + fun skipTransaction(screen: ItemStatistic, transaction: Transaction){ + viewModelScope.launch { + TestIdlingResource.increment() + + plannedPaymentsLogic.payOrGet( + transaction = transaction, + skipTransaction = true + ) { + start( + screen = screen, + reset = false + ) + } + + TestIdlingResource.decrement() + } + } + + fun skipTransactions(screen: ItemStatistic, transactions: List){ + viewModelScope.launch{ + TestIdlingResource.increment() + + plannedPaymentsLogic.payOrGet( + transactions = transactions, + skipTransaction = true + ) { + start( + screen = screen, + reset = false + ) + } + + TestIdlingResource.decrement() + } + } } \ No newline at end of file