Repository: wordpress-mobile/WordPress-Android (language: kotlin)

Issue:
🤖 Handle webview checkout result
When the domain purchase is complete in the domain management flow:
* On success the flow returns to a refreshed domain management list
* On failure an error is shown


Discussion hints:
nan

Pull request: Handle webview checkout result
Fixes #19544

### Description

This PR adds completion handling for the domain purchase flow (webview checkout). When the checkout result is an error state, a generic error screen is shown (same as the existing screen for cart failure). On success, the "all domains" screen is shown (and activities in the back stack above that one should be cleared).

To test:

#### Success

1. Enter the domain management flow (Me -> Domains)
2. Tap the "+" sign
3. Search for a new domain
4. Tap a result to purchase (please use an obscure domain if testing a real purchase to not waste a good domain)
   * Adding a timestamp or random numbers / letters, nonce, etc. should suffice
5. Continue with the purchase (via standalone, or connected with a site flows)
6. Finish the purchase
7. Expect to be brought back to the domain management screen (aka all domains screen)
8. Expect that the newly purchased domain is visible in the list (or searchable if it is a long list already 😅 )

#### Failure

1. Perform steps 1-5 from above
2. Tap the back button in the web view before completing the purchase
3. Expect to see the error screen

Note: I am still investigating a better way to introduce an error in the web view checkout process. 

## Regression Notes
1. Potential unintended areas of impact
Domain management feature

10. What I did to test those areas of impact (or what existing automated tests I relied on)
Manual and automated tests

11. What automated tests I added (or what prevented me from doing so)
Unit tests were added for the checkout completion events

PR submission checklist:

- [x] I have completed the Regression Notes.
- [x] I have considered adding accessibility improvements for my changes.
- [x] I have considered if this change warrants user-facing release notes and have added them to `RELEASE-NOTES.txt` if necessary.

UI Changes testing checklist:

- [ ] Portrait and landscape orientations.
- [ ] Light and dark modes.
- [ ] Fonts: Larger, smaller and bold text.
- [ ] High contrast.
- [ ] Talkback.
- [ ] Languages with large words or with letters/accents not frequently used in English.
- [ ] Right-to-left languages. (Even if translation isn’t complete, formatting should still respect the right-to-left layout)
- [ ] Large and small screen sizes. (Tablet and smaller phones)
- [ ] Multi-tasking: Split screen and Pop-up view. (Android 10 or higher)


Test command: ./gradlew :WordPress:testWordpressVanillaDebugUnitTest --tests "org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModelTest"

Fix patch:
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java
index b789b372eb11..6722836cd815 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java
@@ -1927,6 +1927,7 @@ public static void showJetpackStaticPoster(@NonNull Context context) {
 
     public static void openDomainManagement(@NonNull Context context) {
         Intent intent = new Intent(context, DomainManagementActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
         context.startActivity(intent);
     }
 
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainActivity.kt
index 5d5730f1b2c0..a7df53d7ec35 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainActivity.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainActivity.kt
@@ -12,6 +12,7 @@ import dagger.hilt.android.AndroidEntryPoint
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import org.wordpress.android.fluxc.store.SiteStore
+import org.wordpress.android.ui.ActivityLauncher
 import org.wordpress.android.ui.domains.DomainRegistrationCheckoutWebViewActivity
 import org.wordpress.android.ui.domains.management.M3Theme
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.ActionEvent.GoBack
@@ -19,6 +20,7 @@ import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomain
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.ActionEvent.GoToSitePicker
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.ActionEvent.GoToExistingSiteCheckout
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.ActionEvent.GoToExistingSitePlans
+import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.ActionEvent.OpenDomainManagement
 import org.wordpress.android.ui.domains.management.purchasedomain.composable.PurchaseDomainScreen
 import org.wordpress.android.ui.main.SitePickerContract
 import javax.inject.Inject
@@ -108,6 +110,9 @@ class PurchaseDomainActivity : AppCompatActivity() {
                 )
             }
             GoBack -> onBackPressedDispatcher.onBackPressed()
+            OpenDomainManagement -> {
+                ActivityLauncher.openDomainManagement(this)
+            }
         }
     }
 
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainViewModel.kt
index 0755288cc91f..649dc90b9983 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainViewModel.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainViewModel.kt
@@ -67,9 +67,12 @@ class PurchaseDomainViewModel @AssistedInject constructor(
         }
     }
 
-    @Suppress("UNUSED_PARAMETER")
-    fun onDomainRegistrationComplete(event: DomainRegistrationCompletedEvent?) {
-        // TODO Handle domain registration complete
+    fun onDomainRegistrationComplete(event: DomainRegistrationCompletedEvent?) = event?.also {
+        launch {
+            _actionEvents.emit(ActionEvent.OpenDomainManagement)
+        }
+    } ?: run {
+        _uiStateFlow.value = UiState.ErrorInCheckout
     }
 
     private val SiteModel.shouldOfferPlans
@@ -112,6 +115,7 @@ class PurchaseDomainViewModel @AssistedInject constructor(
         object SubmittingJustDomainCart : UiState
         object SubmittingSiteDomainCart : UiState
         object ErrorSubmittingCart : UiState
+        object ErrorInCheckout : UiState
     }
 
     sealed class ActionEvent {
@@ -120,6 +124,7 @@ class PurchaseDomainViewModel @AssistedInject constructor(
         data class GoToSitePicker(val domain: String) : ActionEvent()
         data class GoToExistingSiteCheckout(val domain: String, val siteModel: SiteModel) : ActionEvent()
         data class GoToExistingSitePlans(val domain: String, val siteModel: SiteModel) : ActionEvent()
+        object OpenDomainManagement : ActionEvent()
     }
 
     @AssistedFactory
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/composable/PurchaseDomainScreen.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/composable/PurchaseDomainScreen.kt
index 1241e68bd43e..86fe6d1df044 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/composable/PurchaseDomainScreen.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/management/purchasedomain/composable/PurchaseDomainScreen.kt
@@ -67,7 +67,7 @@ fun PurchaseDomainScreen(
             )
         },
         content = {
-            if (uiState == UiState.ErrorSubmittingCart) {
+            if (uiState == UiState.ErrorSubmittingCart || uiState == UiState.ErrorInCheckout) {
                 ErrorScreen(onButtonTapped = onErrorButtonTapped)
             } else {
                 Box(


Test patch:
diff --git a/WordPress/src/test/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainViewModelTest.kt
index d21bbbb02c47..2fd151dd855b 100644
--- a/WordPress/src/test/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainViewModelTest.kt
+++ b/WordPress/src/test/java/org/wordpress/android/ui/domains/management/purchasedomain/PurchaseDomainViewModelTest.kt
@@ -22,6 +22,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.transactions.TransactionsR
 import org.wordpress.android.fluxc.network.rest.wpcom.transactions.TransactionsRestClient.CreateShoppingCartResponse.Extra
 import org.wordpress.android.fluxc.network.rest.wpcom.transactions.TransactionsRestClient.CreateShoppingCartResponse.Product
 import org.wordpress.android.fluxc.store.TransactionsStore
+import org.wordpress.android.ui.domains.DomainRegistrationCompletedEvent
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.ActionEvent
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.ActionEvent.GoBack
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.ActionEvent.GoToDomainPurchasing
@@ -30,6 +31,7 @@ import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomain
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.UiState.SubmittingJustDomainCart
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.UiState.SubmittingSiteDomainCart
 import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.UiState.ErrorSubmittingCart
+import org.wordpress.android.ui.domains.management.purchasedomain.PurchaseDomainViewModel.UiState.ErrorInCheckout
 import org.wordpress.android.ui.domains.usecases.CreateCartUseCase
 import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper
 
@@ -119,6 +121,33 @@ class PurchaseDomainViewModelTest : BaseUnitTest() {
         assertThat(viewModel.uiStateFlow.value).isEqualTo(ErrorSubmittingCart)
     }
 
+    @Test
+    fun `WHEN check out fails THEN the ui is set to the ErrorInCheckout state`() = test {
+        viewModel.onDomainRegistrationComplete(null)
+        assertThat(viewModel.uiStateFlow.value).isEqualTo(ErrorInCheckout)
+    }
+
+    @Test
+    fun `WHEN check out is successful THEN go to the all domains screen`() = testWithActionEvents { events ->
+        viewModel.onDomainRegistrationComplete(
+            DomainRegistrationCompletedEvent("example.com", "joe@schmo.co")
+        )
+        advanceUntilIdle()
+
+        // Then
+        assertThat(events.last()).isEqualTo(ActionEvent.OpenDomainManagement)
+    }
+
+    @Test
+    fun `WHEN check out is cancelled THEN go to the all domains screen`() = testWithActionEvents { events ->
+        viewModel.onDomainRegistrationComplete(
+            DomainRegistrationCompletedEvent("example.com", "joe@schmo.co", true)
+        )
+        advanceUntilIdle()
+
+        // Then
+        assertThat(events.last()).isEqualTo(ActionEvent.OpenDomainManagement)
+    }
 
     @Test
     fun `WHEN the error button is tapped THEN the ui is set to the Initial state`() = test {