From 19bfd5a0a90d8bdd212ee133a0ce4f2feac674c4 Mon Sep 17 00:00:00 2001 From: Daniel Kift Date: Thu, 23 Nov 2023 11:35:49 +0000 Subject: [PATCH] add tests for default checkout event processor --- .../checkoutkit/CheckoutEventProcessor.kt | 11 ++- .../com/shopify/checkoutkit/LogWrapper.kt | 16 ++++ .../DefaultCheckoutEventProcessorTest.kt | 89 +++++++++++++++++++ 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 lib/src/main/java/com/shopify/checkoutkit/LogWrapper.kt create mode 100644 lib/src/test/java/com/shopify/checkoutkit/DefaultCheckoutEventProcessorTest.kt diff --git a/lib/src/main/java/com/shopify/checkoutkit/CheckoutEventProcessor.kt b/lib/src/main/java/com/shopify/checkoutkit/CheckoutEventProcessor.kt index e174b9a4..118294ae 100644 --- a/lib/src/main/java/com/shopify/checkoutkit/CheckoutEventProcessor.kt +++ b/lib/src/main/java/com/shopify/checkoutkit/CheckoutEventProcessor.kt @@ -114,14 +114,17 @@ internal class NoopEventProcessor : CheckoutEventProcessor { * for handling checkout events and interacting with the Android operating system. * @param context from which we will launch intents. */ -public abstract class DefaultCheckoutEventProcessor(private val context: Context) : CheckoutEventProcessor { +public abstract class DefaultCheckoutEventProcessor( + private val context: Context, + private val log: LogWrapper = LogWrapper(), +) : CheckoutEventProcessor { override fun onCheckoutLinkClicked(uri: Uri) { when (uri.scheme) { "tel" -> context.launchPhoneApp(uri.schemeSpecificPart) "mailto" -> context.launchEmailApp(uri.schemeSpecificPart) "https", "http" -> context.launchBrowser(uri) - else -> println("Unrecognized scheme for uri $uri") + else -> log.w(TAG, "Unrecognized scheme for link clicked in checkout '$uri'") } } @@ -142,4 +145,8 @@ public abstract class DefaultCheckoutEventProcessor(private val context: Context val intent = Intent(Intent.ACTION_DIAL, Uri.fromParts("tel", phone, null)) startActivity(intent) } + + private companion object { + private const val TAG = "DefaultCheckoutEventProcessor" + } } diff --git a/lib/src/main/java/com/shopify/checkoutkit/LogWrapper.kt b/lib/src/main/java/com/shopify/checkoutkit/LogWrapper.kt new file mode 100644 index 00000000..6ed5ec2c --- /dev/null +++ b/lib/src/main/java/com/shopify/checkoutkit/LogWrapper.kt @@ -0,0 +1,16 @@ +package com.shopify.checkoutkit + +import android.util.Log + +/** + * Wrap Log class static methods to allow testing + */ +public class LogWrapper { + public fun w(tag: String, msg: String) { + Log.w(tag, msg) + } + + public fun e(tag: String, msg: String) { + Log.e(tag, msg) + } +} diff --git a/lib/src/test/java/com/shopify/checkoutkit/DefaultCheckoutEventProcessorTest.kt b/lib/src/test/java/com/shopify/checkoutkit/DefaultCheckoutEventProcessorTest.kt new file mode 100644 index 00000000..0ec3519d --- /dev/null +++ b/lib/src/test/java/com/shopify/checkoutkit/DefaultCheckoutEventProcessorTest.kt @@ -0,0 +1,89 @@ +package com.shopify.checkoutkit + +import android.content.Intent +import android.net.Uri +import androidx.activity.ComponentActivity +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.Shadows.shadowOf +import org.robolectric.shadows.ShadowActivity + +@RunWith(RobolectricTestRunner::class) +class DefaultCheckoutEventProcessorTest { + + private lateinit var activity: ComponentActivity + private lateinit var shadowActivity: ShadowActivity + + @Before + fun setUp() { + activity = Robolectric.buildActivity(ComponentActivity::class.java).get() + shadowActivity = shadowOf(activity) + } + + @Test + fun `onCheckoutLinkClicked with http scheme launches action view intent with uri as data`() { + val processor = processor(activity) + val uri = Uri.parse("https://shopify.com") + + processor.onCheckoutLinkClicked(uri) + + val intent = shadowActivity.peekNextStartedActivityForResult().intent + assertThat(intent.data).isEqualTo(uri) + intent.type = Intent.ACTION_VIEW + } + + @Test + fun `onCheckoutLinkClicked with mailto scheme launches email intent with to address`() { + val processor = processor(activity) + val uri = Uri.parse("mailto:test.user@shopify.com") + + processor.onCheckoutLinkClicked(uri) + + val intent = shadowActivity.peekNextStartedActivityForResult().intent + assertThat(intent.getStringArrayExtra(Intent.EXTRA_EMAIL)).isEqualTo(arrayOf("test.user@shopify.com")) + intent.type = "vnd.android.cursor.item/email" + } + + @Test + fun `onCheckoutLinkClicked with tel scheme launches action dial intent with phone number`() { + val processor = processor(activity) + val uri = Uri.parse("tel:0123456789") + + processor.onCheckoutLinkClicked(uri) + + val intent = shadowActivity.peekNextStartedActivityForResult().intent + assertThat(intent.data).isEqualTo(uri) + intent.type = Intent.ACTION_DIAL + } + + @Test + fun `onCheckoutLinkedClick with unhandled scheme logs warning`() { + val log = mock() + val processor = object: DefaultCheckoutEventProcessor(activity, log) { + override fun onCheckoutCompleted() {/* not implemented */} + override fun onCheckoutFailed(error: CheckoutException) {/* not implemented */} + override fun onCheckoutCanceled() {/* not implemented */} + } + + val uri = Uri.parse("ftp:lsklsm") + + processor.onCheckoutLinkClicked(uri) + + assertThat(shadowActivity.peekNextStartedActivityForResult()).isNull() + verify(log).w("DefaultCheckoutEventProcessor", "Unrecognized scheme for link clicked in checkout 'ftp:lsklsm'") + } + + private fun processor(activity: ComponentActivity): DefaultCheckoutEventProcessor { + return object: DefaultCheckoutEventProcessor(activity) { + override fun onCheckoutCompleted() {/* not implemented */} + override fun onCheckoutFailed(error: CheckoutException) {/* not implemented */} + override fun onCheckoutCanceled() {/* not implemented */} + } + } +}