diff --git a/sdk/src/androidTest/java/co/omise/android/ui/PaymentCreatorActivityTest.kt b/sdk/src/androidTest/java/co/omise/android/ui/PaymentCreatorActivityTest.kt index a66e4692..085aec5d 100644 --- a/sdk/src/androidTest/java/co/omise/android/ui/PaymentCreatorActivityTest.kt +++ b/sdk/src/androidTest/java/co/omise/android/ui/PaymentCreatorActivityTest.kt @@ -5,12 +5,10 @@ import android.app.Activity.RESULT_OK import android.app.Application import android.content.Intent import android.os.Bundle -import android.util.Log import android.view.WindowManager import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.intent.Intents.intended @@ -27,7 +25,6 @@ import co.omise.android.api.Client import co.omise.android.api.Request import co.omise.android.api.RequestListener import co.omise.android.models.Capability -import co.omise.android.models.PaymentMethod import co.omise.android.models.SourceType import co.omise.android.models.Token import co.omise.android.models.TokenizationMethod @@ -51,12 +48,14 @@ import org.mockito.kotlin.whenever class PaymentCreatorActivityTest { @get:Rule val intentRule = IntentsRule() - // capabilities requested by the merchant - private val capability = Capability.create( - allowCreditCard = true, - sourceTypes = listOf(SourceType.Fpx(), SourceType.TrueMoney), - tokenizationMethods = listOf(TokenizationMethod.GooglePay) - ) + + // capabilities requested by the merchant + private val capability = + Capability.create( + allowCreditCard = true, + sourceTypes = listOf(SourceType.Fpx(), SourceType.TrueMoney), + tokenizationMethods = listOf(TokenizationMethod.GooglePay), + ) private val mockClient: Client = mock() private val intent = Intent( @@ -93,24 +92,29 @@ class PaymentCreatorActivityTest { override fun onActivityDestroyed(activity: Activity) {} } + @Before fun setUp() { application.registerActivityLifecycleCallbacks(activityLifecycleCallbacks) whenever(mockClient.send(any>(), any())).doAnswer { invocation -> val callback = invocation.getArgument>(1) // Capabilities retrieved from api - callback.onRequestSucceed(Capability.create( - allowCreditCard = true, - sourceTypes = listOf(SourceType.TrueMoney,SourceType.PromptPay), - tokenizationMethods = listOf(TokenizationMethod.GooglePay,TokenizationMethod.Card) - )) + callback.onRequestSucceed( + Capability.create( + allowCreditCard = true, + sourceTypes = listOf(SourceType.TrueMoney, SourceType.PromptPay), + tokenizationMethods = listOf(TokenizationMethod.GooglePay, TokenizationMethod.Card), + ), + ) } } + @After fun tearDown() { reset(mockClient) application.unregisterActivityLifecycleCallbacks(activityLifecycleCallbacks) } + @Test fun initialActivity_collectExtrasIntent() { ActivityScenario.launchActivityForResult(intent) @@ -129,9 +133,9 @@ class PaymentCreatorActivityTest { intended(hasComponent(hasClassName(CreditCardActivity::class.java.name))) } + @Test fun shouldShowOnlyPaymentMethodsRequestedByMerchantAndAvailableInCapability() { - ActivityScenario.launchActivityForResult(intent) onView( @@ -149,7 +153,6 @@ class PaymentCreatorActivityTest { onView(ViewMatchers.withText(R.string.payment_method_fpx_title)).check(doesNotExist()) onView(withId(R.id.recycler_view)) .check(matches(itemCount(3))) - } @Test diff --git a/sdk/src/main/java/co/omise/android/extensions/IntentExtensions.kt b/sdk/src/main/java/co/omise/android/extensions/IntentExtensions.kt index 6140a23a..36e5d587 100644 --- a/sdk/src/main/java/co/omise/android/extensions/IntentExtensions.kt +++ b/sdk/src/main/java/co/omise/android/extensions/IntentExtensions.kt @@ -14,6 +14,7 @@ internal inline fun Intent.parcelable(key: String?): T? getParcelableExtra(key) as? T } + internal inline fun Intent.parcelableNullable(key: String?): T? = when { // https://stackoverflow.com/questions/72571804/getserializableextra-and-getparcelableextra-are-deprecated-what-is-the-alternat/73543350#73543350 @@ -21,5 +22,5 @@ internal inline fun Intent.parcelableNullable(key: Str else -> @Suppress("DEPRECATION") getParcelableExtra(key) - as? T + as? T } diff --git a/sdk/src/main/java/co/omise/android/models/PaymentMethod.kt b/sdk/src/main/java/co/omise/android/models/PaymentMethod.kt index b42a5bf4..9ed8ebde 100644 --- a/sdk/src/main/java/co/omise/android/models/PaymentMethod.kt +++ b/sdk/src/main/java/co/omise/android/models/PaymentMethod.kt @@ -35,7 +35,8 @@ data class PaymentMethod( fun createSourceTypeMethod(sourceType: SourceType): PaymentMethod = PaymentMethod( name = sourceType.name, - installmentTerms = listOf(), // empty list as it will be replaced by the actual terms from capability + // empty list as it will be replaced by the actual terms from capability + installmentTerms = listOf(), banks = when (sourceType) { is SourceType.Fpx -> sourceType.banks diff --git a/sdk/src/main/java/co/omise/android/ui/PaymentCreatorActivity.kt b/sdk/src/main/java/co/omise/android/ui/PaymentCreatorActivity.kt index 633a1cb5..afc377d7 100644 --- a/sdk/src/main/java/co/omise/android/ui/PaymentCreatorActivity.kt +++ b/sdk/src/main/java/co/omise/android/ui/PaymentCreatorActivity.kt @@ -57,6 +57,7 @@ class PaymentCreatorActivity : OmiseActivity() { private val snackbar: Snackbar by lazy { Snackbar.make(payment_creator_container, "", Snackbar.LENGTH_SHORT) } private lateinit var client: Client + @TestOnly fun setClient(client: Client) { this.client = client @@ -100,14 +101,16 @@ class PaymentCreatorActivity : OmiseActivity() { loadCapability() } + // Set the menu button to close the view by the user override fun onCreateOptionsMenu(menu: Menu): Boolean { - if(supportFragmentManager.findFragmentById(R.id.payment_creator_container) !is PaymentChooserFragment){ + if (supportFragmentManager.findFragmentById(R.id.payment_creator_container) !is PaymentChooserFragment) { menuInflater.inflate(R.menu.menu_toolbar, menu) return true } - return false + return false } + override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.close_menu -> { @@ -125,24 +128,26 @@ class PaymentCreatorActivity : OmiseActivity() { errorMessage.visibility = TextView.GONE // Get capability val capabilityRequest = Capability.GetCapabilitiesRequestBuilder().build() - client.send(capabilityRequest, object : RequestListener { - override fun onRequestSucceed(model: Capability) { - - updateActivityWithCapability(model) - // Invalidate the options menu to trigger a refresh and hide the menu button - // as new button will come from the next view - invalidateOptionsMenu() - // Hide loading - progressBar.visibility = ProgressBar.GONE - } + client.send( + capabilityRequest, + object : RequestListener { + override fun onRequestSucceed(model: Capability) { + updateActivityWithCapability(model) + // Invalidate the options menu to trigger a refresh and hide the menu button + // as new button will come from the next view + invalidateOptionsMenu() + // Hide loading + progressBar.visibility = ProgressBar.GONE + } - override fun onRequestFailed(throwable: Throwable) { - progressBar.visibility = ProgressBar.GONE - // Show the error message - errorMessage.text = "Unable to load payment methods" - errorMessage.visibility = TextView.VISIBLE - } - }) + override fun onRequestFailed(throwable: Throwable) { + progressBar.visibility = ProgressBar.GONE + // Show the error message + errorMessage.text = "Unable to load payment methods" + errorMessage.visibility = TextView.VISIBLE + } + }, + ) } // Detect if the current activity is still active @@ -154,29 +159,29 @@ class PaymentCreatorActivity : OmiseActivity() { capability = newCapability requester = PaymentCreatorRequesterImpl(client, amount, currency, newCapability) requester.capability = newCapability - navigation = PaymentCreatorNavigationImpl( - this, - pkey, - amount, - currency, - cardBrands, - googlepayMerchantId, - googlepayRequestBillingAddress, - googlepayRequestPhoneNumber, - REQUEST_CREDIT_CARD, - requester, - newCapability, - ) + navigation = + PaymentCreatorNavigationImpl( + this, + pkey, + amount, + currency, + cardBrands, + googlepayMerchantId, + googlepayRequestBillingAddress, + googlepayRequestPhoneNumber, + REQUEST_CREDIT_CARD, + requester, + newCapability, + ) capability = filterCapabilities(newCapability) // Replace the capability passed from merchant by the new capability intent.putExtra(EXTRA_CAPABILITY, capability) // Open the payment method chooser if the activity is still active - if(isActivityActive()){ + if (isActivityActive()) { navigation.navigateToPaymentChooser(capability) } - requester.listener = object : PaymentCreatorRequestListener { override fun onSourceCreated(result: Result) { @@ -210,40 +215,41 @@ class PaymentCreatorActivity : OmiseActivity() { } } } + // Filter the capabilities based on the merchant request and what is available in the capabilities of the merchant account - private fun filterCapabilities(capability:Capability):Capability{ + private fun filterCapabilities(capability: Capability): Capability { val merchantPassedCapabilities = intent.parcelableNullable(EXTRA_CAPABILITY) - var filteredPaymentMethods : List? = null - var filteredTokenizationMethods : List? = null + var filteredPaymentMethods: List? = null + var filteredTokenizationMethods: List? = null - if(merchantPassedCapabilities != null){ + if (merchantPassedCapabilities != null) { val selectedPaymentMethods = merchantPassedCapabilities.paymentMethods val selectedTokenizationMethods = merchantPassedCapabilities.tokenizationMethods - if(selectedPaymentMethods != null){ - - filteredPaymentMethods = capability.paymentMethods!!.filter {capMethod-> - selectedPaymentMethods.map { it.name }.contains(capMethod.name) - } + if (selectedPaymentMethods != null) { + filteredPaymentMethods = + capability.paymentMethods!!.filter { capMethod -> + selectedPaymentMethods.map { it.name }.contains(capMethod.name) + } capability.paymentMethods = filteredPaymentMethods.toMutableList() } - if(selectedTokenizationMethods != null){ - filteredTokenizationMethods= capability.tokenizationMethods!!.filter { - selectedTokenizationMethods.contains(it) - } + if (selectedTokenizationMethods != null) { + filteredTokenizationMethods = + capability.tokenizationMethods!!.filter { + selectedTokenizationMethods.contains(it) + } capability.tokenizationMethods = filteredTokenizationMethods } capability.zeroInterestInstallments = merchantPassedCapabilities.zeroInterestInstallments // add the tokenization methods into payment methods since the SDK only shows paymentMethods val combinedMethods = capability.paymentMethods?.toMutableList() - capability.tokenizationMethods?.forEach { method-> + capability.tokenizationMethods?.forEach { method -> run { combinedMethods?.add(PaymentMethod(method)) } } capability.paymentMethods = combinedMethods - } - return capability + return capability } // TODO: find a way to unit test ActivityResult launcher in order to be able to move from deprecated onActivityResult @@ -483,7 +489,7 @@ private class PaymentCreatorNavigationImpl( } override fun navigateToDuitNowOBWBankChooser(capability: Capability) { - val banks = capability.paymentMethods?.find { it.name == SourceType.DuitNowOBW.name }?.banks?: emptyList() + val banks = capability.paymentMethods?.find { it.name == SourceType.DuitNowOBW.name }?.banks ?: emptyList() val fragment = DuitNowOBWBankChooserFragment.newInstance(banks).apply {