Skip to content

[Payment Method Improvements] Add more tests #11607

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

Merged
merged 27 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bd486b1
Add more tests
backwardstruck May 29, 2024
2833cd3
All tests pass
backwardstruck May 29, 2024
638eb51
More test coverage
backwardstruck May 29, 2024
6222d40
Add correct template
backwardstruck May 29, 2024
f8956ef
Cleanup
backwardstruck May 29, 2024
2bb10b8
Merge branch '11604-gray-out-button-until-payment-amount' into 11542-…
backwardstruck May 30, 2024
d2d9bfd
Resolve conflicts with target branch
backwardstruck May 30, 2024
bab80db
Detekt
backwardstruck May 30, 2024
32df0e7
FF to true for launch
backwardstruck May 30, 2024
b33493f
Default to true
backwardstruck May 30, 2024
205efe3
Detekt
backwardstruck May 30, 2024
78fe9d4
amount Recieved should initally equal the order total
backwardstruck May 30, 2024
6fa3adb
Default can complete order to true
backwardstruck May 30, 2024
39c546b
Merge branch 'trunk' into 11542-update-tests
backwardstruck May 30, 2024
c84b9ad
Update tests to pass
backwardstruck May 30, 2024
dcae133
Detekt
backwardstruck May 30, 2024
ab1f777
Test clean up
backwardstruck May 30, 2024
f1a018a
Set correct title
backwardstruck May 30, 2024
db3aa4f
Fix test
backwardstruck May 30, 2024
9f5d188
Fix the label
backwardstruck May 30, 2024
6b8d6eb
Update the preview
backwardstruck May 30, 2024
c48db29
Show correct currency symbol
backwardstruck May 30, 2024
c169707
Merge branch 'trunk' into 11542-update-tests
backwardstruck May 30, 2024
2cf1ad4
Add unit test for new class
backwardstruck May 30, 2024
6f03d5d
Detekt
backwardstruck May 30, 2024
cc6657d
See if the FF is breaking a UI test
backwardstruck May 30, 2024
84194cb
Change FF back to false
backwardstruck May 30, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ class ChangeDueCalculatorFragment : BaseFragment() {
uiState = uiState,
onNavigateUp = viewModel::onBackPressed,
onCompleteOrderClick = viewModel::onOrderComplete,
onAmountReceivedChanged = { viewModel.updateAmountReceived(it) },
onAmountReceivedChanged = {
if (it != null) {
viewModel.updateAmountReceived(it)
}
},
onRecordTransactionDetailsCheckedChanged = {
viewModel.updateRecordTransactionDetailsChecked(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.woocommerce.android.R
import com.woocommerce.android.ui.compose.component.BigDecimalTextFieldValueMapper
import com.woocommerce.android.ui.compose.component.NullableCurrencyTextFieldValueMapper
import com.woocommerce.android.ui.compose.component.WCColoredButton
import com.woocommerce.android.ui.compose.component.WCOutlinedTypedTextField
import com.woocommerce.android.ui.compose.component.WCSwitch
Expand All @@ -54,7 +54,7 @@ fun ChangeDueCalculatorScreen(
uiState: ChangeDueCalculatorViewModel.UiState,
onNavigateUp: () -> Unit,
onCompleteOrderClick: () -> Unit,
onAmountReceivedChanged: (BigDecimal) -> Unit,
onAmountReceivedChanged: (BigDecimal?) -> Unit,
onRecordTransactionDetailsCheckedChanged: (Boolean) -> Unit
) {
WooThemeWithBackground {
Expand Down Expand Up @@ -88,7 +88,7 @@ fun ChangeDueCalculatorScreen(
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally
) {
var inputText by remember { mutableStateOf(uiState.amountReceived) }
var inputText by remember { mutableStateOf<BigDecimal?>(uiState.amountDue) }

LaunchedEffect(uiState.amountReceived) {
inputText = uiState.amountReceived
Expand All @@ -108,13 +108,19 @@ fun ChangeDueCalculatorScreen(
.focusRequester(focusRequester),
value = inputText,
label = stringResource(R.string.cash_payments_cash_received),
valueMapper = NullableCurrencyTextFieldValueMapper.create(
decimalSeparator = ".",
numberOfDecimals = 2
),
onValueChange = { newValue ->
inputText = newValue
onAmountReceivedChanged(newValue)
},
visualTransformation = CurrencyVisualTransformation(uiState.currencySymbol),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
valueMapper = BigDecimalTextFieldValueMapper.create(supportsNegativeValue = true),
onValueChange = {
inputText = it
onAmountReceivedChanged(it)
}
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Decimal
)
)

Spacer(modifier = Modifier.height(24.dp))
Expand Down Expand Up @@ -207,14 +213,10 @@ fun MarkOrderAsCompleteButton(

@Composable
private fun getTitleText(uiState: ChangeDueCalculatorViewModel.UiState): String {
return if (uiState.amountDue != BigDecimal.ZERO) {
stringResource(
R.string.cash_payments_take_payment_title,
uiState.amountDue
)
} else {
""
}
return stringResource(
R.string.cash_payments_take_payment_title,
"${uiState.currencySymbol}${uiState.amountDue}"
)
}

@Composable
Expand All @@ -224,7 +226,7 @@ fun ChangeDueCalculatorScreenSuccessPreviewUnchecked() {
uiState = ChangeDueCalculatorViewModel.UiState(
amountDue = BigDecimal("666.00"),
change = BigDecimal("0.00"),
amountReceived = BigDecimal("0.00"),
amountReceived = BigDecimal("666.00"),
loading = false,
canCompleteOrder = true,
currencySymbol = "$",
Expand All @@ -244,7 +246,7 @@ fun ChangeDueCalculatorScreenSuccessPreviewChecked() {
uiState = ChangeDueCalculatorViewModel.UiState(
amountDue = BigDecimal("666.00"),
change = BigDecimal("0.00"),
amountReceived = BigDecimal("0.00"),
amountReceived = BigDecimal("666.00"),
loading = true,
canCompleteOrder = true,
currencySymbol = "€",
Expand All @@ -264,7 +266,7 @@ fun ChangeDueCalculatorScreenSuccessPreviewDisabled() {
uiState = ChangeDueCalculatorViewModel.UiState(
amountDue = BigDecimal("666.00"),
change = BigDecimal("0.00"),
amountReceived = BigDecimal("0.00"),
amountReceived = BigDecimal("666.00"),
loading = false,
canCompleteOrder = false,
currencySymbol = "€",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ class ChangeDueCalculatorViewModel @Inject constructor(
_uiState.value = UiState(
amountDue = order.total,
change = BigDecimal.ZERO,
amountReceived = BigDecimal.ZERO,
canCompleteOrder = false,
amountReceived = order.total,
canCompleteOrder = true,
currencySymbol = getCurrencySymbol(),
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.woocommerce.android.ui.payments.changeduecalculator

import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.input.OffsetMapping
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation

class CurrencyVisualTransformation(private val currencySymbol: String) : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
val prefix = "$currencySymbol "
val transformedText = prefix + text.text
val prefixOffset = prefix.length

val offsetMapping = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
return offset + prefixOffset
}

override fun transformedToOriginal(offset: Int): Int {
return (offset - prefixOffset).coerceAtLeast(0)
}
}

return TransformedText(AnnotatedString(transformedText), offsetMapping)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,14 @@ enum class FeatureFlag {
PackageUtils.isDebugBuild() || context != null && PackageUtils.isBetaBuild(context)
}

OTHER_PAYMENT_METHODS -> false

MORE_MENU_INBOX,
WOO_POS,
WC_SHIPPING_BANNER,
BETTER_CUSTOMER_SEARCH_M2,
ORDER_CREATION_AUTO_TAX_RATE,
DYNAMIC_DASHBOARD_M2 -> PackageUtils.isDebugBuild()

OTHER_PAYMENT_METHODS,
CONNECTIVITY_TOOL,
CUSTOM_RANGE_ANALYTICS,
NEW_SHIPPING_SUPPORT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.woocommerce.android.ui.payments.methodselection.NavigateBackToOrderLi
import com.woocommerce.android.ui.payments.methodselection.NavigateToCardReaderHubFlow
import com.woocommerce.android.ui.payments.methodselection.NavigateToCardReaderPaymentFlow
import com.woocommerce.android.ui.payments.methodselection.NavigateToCardReaderRefundFlow
import com.woocommerce.android.ui.payments.methodselection.NavigateToChangeDueCalculatorScreen
import com.woocommerce.android.ui.payments.methodselection.OpenGenericWebView
import com.woocommerce.android.ui.payments.methodselection.SelectPaymentMethodFragmentArgs
import com.woocommerce.android.ui.payments.methodselection.SelectPaymentMethodViewModel
Expand All @@ -36,7 +37,6 @@ import com.woocommerce.android.util.CurrencyFormatter
import com.woocommerce.android.util.captureValues
import com.woocommerce.android.viewmodel.BaseUnitTest
import com.woocommerce.android.viewmodel.MultiLiveEvent
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowDialog
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.advanceUntilIdle
Expand Down Expand Up @@ -323,7 +323,7 @@ class SelectPaymentMethodViewModelTest : BaseUnitTest() {
}

@Test
fun `given order payment flow, when on cash payment clicked, then show dialog event emitted`() = testBlocking {
fun `given order payment flow, when on cash payment clicked, then show navigate event emitted`() = testBlocking {
// GIVEN
val orderId = 1L
val viewModel = initViewModel(Payment(orderId, ORDER))
Expand All @@ -333,15 +333,12 @@ class SelectPaymentMethodViewModelTest : BaseUnitTest() {

// THEN
val events = viewModel.event.captureValues()
assertThat(events.last()).isInstanceOf(ShowDialog::class.java)
assertThat((events.last() as ShowDialog).titleId).isEqualTo(R.string.simple_payments_cash_dlg_title)
assertThat((events.last() as ShowDialog).messageId).isEqualTo(R.string.existing_order_cash_dlg_message)
assertThat((events.last() as ShowDialog).positiveButtonId).isEqualTo(R.string.simple_payments_cash_dlg_button)
assertThat((events.last() as ShowDialog).negativeButtonId).isEqualTo(R.string.cancel)
assertThat(events.last()).isInstanceOf(NavigateToChangeDueCalculatorScreen::class.java)
assertThat((events.last() as NavigateToChangeDueCalculatorScreen).order.id).isEqualTo(orderId)
}

@Test
fun `given simple payment flow, when on cash payment clicked, then show dialog event emitted`() =
fun `given simple payment flow, when on cash payment clicked, then show navigate event emitted`() =
testBlocking {
// GIVEN
val orderId = 1L
Expand All @@ -352,13 +349,8 @@ class SelectPaymentMethodViewModelTest : BaseUnitTest() {

// THEN
val events = viewModel.event.captureValues()
assertThat(events.last()).isInstanceOf(ShowDialog::class.java)
assertThat((events.last() as ShowDialog).titleId).isEqualTo(R.string.simple_payments_cash_dlg_title)
assertThat((events.last() as ShowDialog).messageId).isEqualTo(R.string.simple_payments_cash_dlg_message)
assertThat((events.last() as ShowDialog).positiveButtonId).isEqualTo(
R.string.simple_payments_cash_dlg_button
)
assertThat((events.last() as ShowDialog).negativeButtonId).isEqualTo(R.string.cancel)
assertThat(events.last()).isInstanceOf(NavigateToChangeDueCalculatorScreen::class.java)
assertThat((events.last() as NavigateToChangeDueCalculatorScreen).order.id).isEqualTo(orderId)
}

@Test
Expand All @@ -373,13 +365,8 @@ class SelectPaymentMethodViewModelTest : BaseUnitTest() {

// THEN
val events = viewModel.event.captureValues()
assertThat(events.last()).isInstanceOf(ShowDialog::class.java)
assertThat((events.last() as ShowDialog).titleId).isEqualTo(R.string.simple_payments_cash_dlg_title)
assertThat((events.last() as ShowDialog).messageId).isEqualTo(R.string.simple_payments_cash_dlg_message)
assertThat((events.last() as ShowDialog).positiveButtonId).isEqualTo(
R.string.simple_payments_cash_dlg_button
)
assertThat((events.last() as ShowDialog).negativeButtonId).isEqualTo(R.string.cancel)
assertThat(events.last()).isInstanceOf(NavigateToChangeDueCalculatorScreen::class.java)
assertThat((events.last() as NavigateToChangeDueCalculatorScreen).order.id).isEqualTo(orderId)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class ChangeDueCalculatorViewModelTest : BaseUnitTest() {
val uiState = viewModel.uiState.value
assertThat(uiState.change).isEqualTo(BigDecimal.ZERO)
assertThat(uiState.amountDue).isEqualTo(BigDecimal(ORDER_TOTAL))
assertThat(uiState.change).isEqualTo(BigDecimal.ZERO)
assertThat(uiState.amountReceived).isEqualTo(ORDER_TOTAL)
}

@Test
Expand All @@ -81,4 +83,120 @@ class ChangeDueCalculatorViewModelTest : BaseUnitTest() {
assertThat(uiState.amountReceived).isEqualTo(amountReceived)
assertThat(uiState.change).isEqualTo(BigDecimal("50.00"))
}

@Test
fun `given amount due is zero, when amount received is zero, then change is zero`() = runTest {
// GIVEN
val emptyOrder: Order = mock {
on { total }.thenReturn(BigDecimal.ZERO)
}
whenever(orderDetailRepository.getOrderById(any())).thenReturn(emptyOrder)

// WHEN
viewModel = ChangeDueCalculatorViewModel(
savedStateHandle = savedStateHandle,
orderDetailRepository = orderDetailRepository,
parameterRepository = parameterRepository,
resourceProvider = resourceProvider
)
viewModel.updateAmountReceived(BigDecimal.ZERO)
advanceUntilIdle()

// THEN
val uiState = viewModel.uiState.value
assertThat(uiState.amountDue).isEqualTo(BigDecimal.ZERO)
assertThat(uiState.amountReceived).isEqualTo(BigDecimal.ZERO)
assertThat(uiState.change).isEqualTo(BigDecimal.ZERO)
}

@Test
fun `when amount received is less than amount due, then change is negative`() = runTest {
// GIVEN
whenever(orderDetailRepository.getOrderById(any())).thenReturn(order)
val amountReceived = BigDecimal("50.00")

// WHEN
viewModel = ChangeDueCalculatorViewModel(
savedStateHandle = savedStateHandle,
orderDetailRepository = orderDetailRepository,
parameterRepository = parameterRepository,
resourceProvider = resourceProvider
)
viewModel.updateAmountReceived(amountReceived)
advanceUntilIdle()

// THEN
val uiState = viewModel.uiState.value
assertThat(uiState.amountDue).isEqualTo(BigDecimal(ORDER_TOTAL))
assertThat(uiState.amountReceived).isEqualTo(amountReceived)
assertThat(uiState.change).isEqualTo(BigDecimal("-50.00"))
}

@Test
fun `when amount received is greater than or equal to amount due, then order can be completed`() = runTest {
// GIVEN
whenever(orderDetailRepository.getOrderById(any())).thenReturn(order)
viewModel = ChangeDueCalculatorViewModel(
savedStateHandle = savedStateHandle,
orderDetailRepository = orderDetailRepository,
parameterRepository = parameterRepository,
resourceProvider = resourceProvider
)

// WHEN
val amountReceived = BigDecimal("100.00")
viewModel.updateAmountReceived(amountReceived)
advanceUntilIdle()
val canCompleteOrder = viewModel.uiState.value.canCompleteOrder

// THEN
val uiState = viewModel.uiState.value
assertThat(uiState.amountDue).isEqualTo(BigDecimal(ORDER_TOTAL))
assertThat(uiState.amountReceived).isEqualTo(amountReceived)
assertThat(uiState.change).isEqualTo(BigDecimal("0.00"))
assertThat(canCompleteOrder).isTrue
}

@Test
fun `when updateRecordTransactionDetailsChecked is called, then recordTransactionDetailsChecked state is updated`() =
runTest {
// GIVEN
whenever(orderDetailRepository.getOrderById(any())).thenReturn(order)
viewModel = ChangeDueCalculatorViewModel(
savedStateHandle = savedStateHandle,
orderDetailRepository = orderDetailRepository,
parameterRepository = parameterRepository,
resourceProvider = resourceProvider
)

// WHEN
viewModel.updateRecordTransactionDetailsChecked(true)
advanceUntilIdle()

// THEN
val isChecked = viewModel.uiState.value.recordTransactionDetailsChecked
assertThat(isChecked).isTrue
}

@Test
fun `when getCurrencySymbol is called, then currency symbol from parameter repository is returned`() = runTest {
// GIVEN
val currencySymbol = "$"
whenever(orderDetailRepository.getOrderById(any())).thenReturn(order)
val siteParameters: SiteParameters = mock()
whenever(siteParameters.currencySymbol).thenReturn(currencySymbol)
whenever(parameterRepository.getParameters()).thenReturn(siteParameters)
viewModel = ChangeDueCalculatorViewModel(
savedStateHandle = savedStateHandle,
orderDetailRepository = orderDetailRepository,
parameterRepository = parameterRepository,
resourceProvider = resourceProvider
)

// WHEN
val result = viewModel.uiState.value.currencySymbol

// THEN
assertThat(result).isEqualTo(currencySymbol)
}
}
Loading
Loading