From a69741e2dd432ef42520c2065629837ae5c2e9a7 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Mon, 20 May 2019 09:40:55 -0700 Subject: [PATCH 01/21] Adding ViewModel. --- .../android/modules/ViewModelModule.java | 6 + .../DomainregistrationDetailsViewModel.kt | 273 ++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java index dbdd3b0883ab..fd5ad0f324ac 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java @@ -26,6 +26,7 @@ import org.wordpress.android.viewmodel.ViewModelKey; import org.wordpress.android.viewmodel.activitylog.ActivityLogDetailViewModel; import org.wordpress.android.viewmodel.activitylog.ActivityLogViewModel; +import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel; import org.wordpress.android.viewmodel.domains.DomainSuggestionsViewModel; import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel; import org.wordpress.android.viewmodel.history.HistoryViewModel; @@ -198,6 +199,11 @@ abstract class ViewModelModule { @ViewModelKey(DomainSuggestionsViewModel.class) abstract ViewModel domainSuggestionsViewModel(DomainSuggestionsViewModel viewModel); + @Binds + @IntoMap + @ViewModelKey(DomainRegistrationDetailsViewModel.class) + abstract ViewModel domainRegistrationDetailsViewModel(DomainRegistrationDetailsViewModel viewModel); + @Binds abstract ViewModelProvider.Factory provideViewModelFactory(ViewModelFactory viewModelFactory); } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt new file mode 100644 index 000000000000..14af911c6197 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt @@ -0,0 +1,273 @@ +package org.wordpress.android.viewmodel.domains + +import android.arch.lifecycle.LiveData +import android.arch.lifecycle.MutableLiveData +import android.arch.lifecycle.Transformations +import android.arch.lifecycle.ViewModel +import android.text.TextUtils +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.action.TransactionAction.FETCH_SUPPORTED_COUNTRIES +import org.wordpress.android.fluxc.generated.AccountActionBuilder +import org.wordpress.android.fluxc.generated.SiteActionBuilder +import org.wordpress.android.fluxc.generated.TransactionActionBuilder +import org.wordpress.android.fluxc.model.DomainContactModel +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.network.rest.wpcom.site.SupportedStateResponse +import org.wordpress.android.fluxc.network.rest.wpcom.transactions.SupportedDomainCountry +import org.wordpress.android.fluxc.store.AccountStore.OnDomainContactFetched +import org.wordpress.android.fluxc.store.SiteStore.OnDomainSupportedStatesFetched +import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged +import org.wordpress.android.fluxc.store.TransactionsStore +import org.wordpress.android.fluxc.store.TransactionsStore.CreateShoppingCartPayload +import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated +import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartRedeemed +import org.wordpress.android.fluxc.store.TransactionsStore.OnSupportedCountriesFetched +import org.wordpress.android.fluxc.store.TransactionsStore.RedeemShoppingCartError +import org.wordpress.android.fluxc.store.TransactionsStore.RedeemShoppingCartPayload +import org.wordpress.android.ui.domains.DomainProductDetails +import org.wordpress.android.util.AppLog +import org.wordpress.android.util.AppLog.T +import org.wordpress.android.viewmodel.SingleLiveEvent +import javax.inject.Inject + +class DomainRegistrationDetailsViewModel @Inject constructor( + private val dispatcher: Dispatcher, + private val transactionsStore: TransactionsStore +) : ViewModel() { + private lateinit var site: SiteModel + private lateinit var domainProductDetails: DomainProductDetails + private var isStarted = false + + private var supportedCountries: List? = null + private val supportedStates = MutableLiveData>() + + val stateInputVisible: LiveData = Transformations.map(supportedStates) { it?.isNotEmpty() ?: false } + + private val _selectedCountry = MutableLiveData() + val selectedCountry: LiveData + get() = _selectedCountry + + private val _selectedState = MutableLiveData() + val selectedState: LiveData + get() = _selectedState + + private val _showErrorMessage = SingleLiveEvent() + val showErrorMessage: LiveData + get() = _showErrorMessage + + private val _formError = SingleLiveEvent() + val formError: LiveData + get() = _formError + + private val _formProgressIndicatorVisible = MutableLiveData() + val formProgressIndicatorVisible: LiveData + get() = _formProgressIndicatorVisible + + private val _statesProgressIndicatorVisible = MutableLiveData() + val statesProgressIndicatorVisible: LiveData + get() = _statesProgressIndicatorVisible + + private val _registrationProgressIndicatorVisible = MutableLiveData() + val registrationProgressIndicatorVisible: LiveData + get() = _registrationProgressIndicatorVisible + + private val _domainRegistrationButtonEnabled = MutableLiveData() + val domainRegistrationButtonEnabled: LiveData + get() = _domainRegistrationButtonEnabled + + private val _privacyProtectionState = MutableLiveData() + val privacyProtectionState: LiveData + get() = _privacyProtectionState + + private val _showCountryPickerDialog = SingleLiveEvent>() + val showCountryPickerDialog: LiveData> + get() = _showCountryPickerDialog + + private val _showStatePickerDialog = SingleLiveEvent>() + val showStatePickerDialog: LiveData> + get() = _showStatePickerDialog + + private val _domainContactDetails = MutableLiveData() + val domainContactDetails: LiveData + get() = _domainContactDetails + + private val _handleCompletedDomainRegistration = SingleLiveEvent() + val handleCompletedDomainRegistration: LiveData + get() = _handleCompletedDomainRegistration + + private val _showTos = SingleLiveEvent() + val showTos: LiveData + get() = _showTos + + init { + dispatcher.register(this) + } + + override fun onCleared() { + dispatcher.unregister(this) + super.onCleared() + } + + fun start(site: SiteModel, domainProductDetails: DomainProductDetails) { + if (isStarted) { + return + } + this.site = site + this.domainProductDetails = domainProductDetails + if (domainContactDetails.value == null) { + fetchSupportedCountries() + } + + if (privacyProtectionState.value == null) { + _privacyProtectionState.value = true + } + } + + private fun fetchSupportedCountries() { + _formProgressIndicatorVisible.value = true + dispatcher.dispatch(TransactionActionBuilder.generateNoPayloadAction(FETCH_SUPPORTED_COUNTRIES)) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onSupportedCountriesFetched(event: OnSupportedCountriesFetched) { + if (event.isError) { + _formProgressIndicatorVisible.value = false + _showErrorMessage.value = event.error.message + AppLog.e(T.DOMAIN_REGISTRATION, "An error occurred while fetching supported countries") + } else { + supportedCountries = event.countries?.toCollection(ArrayList()) + dispatcher.dispatch(AccountActionBuilder.newFetchDomainContactAction()) + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onDomainContactFetched(event: OnDomainContactFetched) { + _formProgressIndicatorVisible.value = false + if (event.isError) { + _showErrorMessage.value = event.error.message + AppLog.e(T.DOMAIN_REGISTRATION, "An error occurred while fetching domain contact details") + } else { + _domainContactDetails.value = event.contactModel + + if (event.contactModel != null && !TextUtils.isEmpty(event.contactModel!!.countryCode)) { + _selectedCountry.value = supportedCountries!!.firstOrNull { it.code == event.contactModel!!.countryCode } + _statesProgressIndicatorVisible.value = true + _domainRegistrationButtonEnabled.value = false + dispatcher.dispatch(SiteActionBuilder.newFetchDomainSupportedStatesAction(event.contactModel!!.countryCode)) + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onDomainSupportedStatesFetched(event: OnDomainSupportedStatesFetched) { + _domainRegistrationButtonEnabled.value = true + _statesProgressIndicatorVisible.value = false + if (event.isError) { + _showErrorMessage.value = event.error.message + AppLog.e(T.DOMAIN_REGISTRATION, "An error occurred while fetching supported countries") + } else { + _selectedState.value = event.supportedStates?.firstOrNull { it.code == domainContactDetails.value!!.state } + supportedStates.value = event.supportedStates + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onShoppingCartCreated(event: OnShoppingCartCreated) { + if (event.isError) { + _registrationProgressIndicatorVisible.value = false + AppLog.e( + T.DOMAIN_REGISTRATION, + "An error occurred while creating a shopping cart : " + event.error.message + ) + _showErrorMessage.value = event.error.message + return + } + + dispatcher.dispatch( + TransactionActionBuilder.newRedeemCartWithCreditsAction( + RedeemShoppingCartPayload( + event.cartDetails!!, domainContactDetails.value!! + ) + ) + ) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onCartRedeemed(event: OnShoppingCartRedeemed) { + if (event.isError) { + _registrationProgressIndicatorVisible.value = false + _formError.value = event.error + _showErrorMessage.value = event.error.message + AppLog.e( + T.DOMAIN_REGISTRATION, + "An error occurred while redeeming a shopping cart : " + event.error.type + + " " + event.error.message + ) + return + } + + dispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(site)) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onSiteChanged(event: OnSiteChanged) { + _registrationProgressIndicatorVisible.value = false + if (event.isError) { + AppLog.e( + T.DOMAIN_REGISTRATION, + "An error occurred while updating site details : " + event.error.message + ) + _showErrorMessage.value = event.error.message + } + + _handleCompletedDomainRegistration.call() + } + + fun onCountrySelectorClicked() { + _showCountryPickerDialog.value = supportedCountries!! + } + + fun onStateSelectorClicked() { + _showStatePickerDialog.value = supportedStates.value + } + + fun onRegisterDomainButtonClicked() { + _registrationProgressIndicatorVisible.value = true + dispatcher.dispatch( + TransactionActionBuilder.newCreateShoppingCartAction( + CreateShoppingCartPayload( + site, + domainProductDetails.productId, + domainProductDetails.domainName, + privacyProtectionState.value!! + ) + ) + ) + } + + fun onCountrySelected(country: SupportedDomainCountry) { + _selectedCountry.value = country + _selectedState.value = null + _statesProgressIndicatorVisible.value = true + _domainRegistrationButtonEnabled.value = false + dispatcher.dispatch(SiteActionBuilder.newFetchDomainSupportedStatesAction(country.code)) + } + + fun onStateSelected(state: SupportedStateResponse) { + _selectedState.value = state + } + + fun onTosLinkClicked() { + _showTos.call() + } + + fun onDomainContactDetailsChanged(domainContactModel: DomainContactModel) { + _domainContactDetails.value = domainContactModel + } + + fun togglePrivacyProtection(isEnabled: Boolean) { + _privacyProtectionState.value = isEnabled + } +} From 3886279f7701d9e9f8420c11875f770c0904abf9 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Mon, 20 May 2019 09:41:16 -0700 Subject: [PATCH 02/21] ViewModel tests. --- .../org/wordpress/android/util/AppLog.java | 3 +- .../DomainRegistrationDetailsViewModelTest.kt | 619 ++++++++++++++++++ 2 files changed, 621 insertions(+), 1 deletion(-) create mode 100644 WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt diff --git a/WordPress/src/test/java/org/wordpress/android/util/AppLog.java b/WordPress/src/test/java/org/wordpress/android/util/AppLog.java index ce057256aea5..340fb602ce0d 100644 --- a/WordPress/src/test/java/org/wordpress/android/util/AppLog.java +++ b/WordPress/src/test/java/org/wordpress/android/util/AppLog.java @@ -38,7 +38,8 @@ public enum T { ACTIVITY_LOG, JETPACK_REMOTE_INSTALL, SUPPORT, - SITE_CREATION + SITE_CREATION, + DOMAIN_REGISTRATION } public static final String TAG = "WordPress"; diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt new file mode 100644 index 000000000000..6cfdd704d7a9 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -0,0 +1,619 @@ +package org.wordpress.android.viewmodel.domains + +import android.arch.core.executor.testing.InstantTaskExecutorRule +import android.arch.lifecycle.Observer +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.argWhere +import com.nhaarman.mockitokotlin2.times +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import org.assertj.core.api.Assertions +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.action.AccountAction +import org.wordpress.android.fluxc.action.SiteAction +import org.wordpress.android.fluxc.action.TransactionAction +import org.wordpress.android.fluxc.action.TransactionAction.FETCH_SUPPORTED_COUNTRIES +import org.wordpress.android.fluxc.annotations.action.Action +import org.wordpress.android.fluxc.model.DomainContactModel +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.network.rest.wpcom.site.SupportedStateResponse +import org.wordpress.android.fluxc.network.rest.wpcom.transactions.SupportedDomainCountry +import org.wordpress.android.fluxc.network.rest.wpcom.transactions.TransactionsRestClient.CreateShoppingCartResponse +import org.wordpress.android.fluxc.network.rest.wpcom.transactions.TransactionsRestClient.CreateShoppingCartResponse.Product +import org.wordpress.android.fluxc.store.AccountStore.DomainContactError +import org.wordpress.android.fluxc.store.AccountStore.DomainContactErrorType +import org.wordpress.android.fluxc.store.AccountStore.OnDomainContactFetched +import org.wordpress.android.fluxc.store.SiteStore.DomainSupportedStatesError +import org.wordpress.android.fluxc.store.SiteStore.DomainSupportedStatesErrorType +import org.wordpress.android.fluxc.store.SiteStore.OnDomainSupportedStatesFetched +import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged +import org.wordpress.android.fluxc.store.SiteStore.SiteError +import org.wordpress.android.fluxc.store.SiteStore.SiteErrorType +import org.wordpress.android.fluxc.store.TransactionsStore +import org.wordpress.android.fluxc.store.TransactionsStore.CreateCartErrorType.GENERIC_ERROR +import org.wordpress.android.fluxc.store.TransactionsStore.CreateShoppingCartError +import org.wordpress.android.fluxc.store.TransactionsStore.CreateShoppingCartPayload +import org.wordpress.android.fluxc.store.TransactionsStore.FetchSupportedCountriesError +import org.wordpress.android.fluxc.store.TransactionsStore.FetchSupportedCountriesErrorType +import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated +import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartRedeemed +import org.wordpress.android.fluxc.store.TransactionsStore.OnSupportedCountriesFetched +import org.wordpress.android.fluxc.store.TransactionsStore.RedeemShoppingCartError +import org.wordpress.android.fluxc.store.TransactionsStore.RedeemShoppingCartPayload +import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType.PHONE +import org.wordpress.android.test +import org.wordpress.android.ui.domains.DomainProductDetails + +@RunWith(MockitoJUnitRunner::class) +class DomainRegistrationDetailsViewModelTest { + @Rule @JvmField val rule = InstantTaskExecutorRule() + @Mock private lateinit var store: TransactionsStore + @Mock private lateinit var dispatcher: Dispatcher + @Mock private lateinit var site: SiteModel + + @Mock private lateinit var formProgressIndicatorObserver: Observer + @Mock private lateinit var domainContactDetailsObserver: Observer + @Mock private lateinit var stateProgressIndicatorObserver: Observer + @Mock private lateinit var domainRegistrationButtonObserver: Observer + @Mock private lateinit var selectedStateObserver: Observer + @Mock private lateinit var selectedCountryObserver: Observer + @Mock private lateinit var countryPickerDialogObserver: Observer> + @Mock private lateinit var statePickerDialogObserver: Observer> + @Mock private lateinit var tosLinkObserver: Observer + @Mock private lateinit var privacyProtectionObserver: Observer + @Mock private lateinit var domainRegistrationProgressIndicatorObserver: Observer + @Mock private lateinit var completedDomainRegistrationObserver: Observer + @Mock private lateinit var stateInputVisibleObserver: Observer + @Mock private lateinit var errorMessageObserver: Observer + + private lateinit var viewModel: DomainRegistrationDetailsViewModel + + private val selectedCountry = SupportedDomainCountry("US", "United States") + private val testCountries = listOf( + selectedCountry, + SupportedDomainCountry("UK", "United Kingdom") + ) + + private val selectedState = SupportedStateResponse("CA", "California") + private val testStates = listOf( + selectedState, + SupportedStateResponse("WA", "Washington") + ) + + private val siteId = 1234L + private val productId = "76" + private val testDomainName = "testdomain.blog" + private val cartId = "123" + + private val domainContactModel = DomainContactModel( + "John", + "Smith", + "", + "Street 1", + "Apt 1", + "10018", + "First City", + "CA", + "US", + "email@wordpress.org", + "3124567890", + "" + ) + + private val shoppingCartCreateError = CreateShoppingCartError(GENERIC_ERROR, "Error Creating Cart") + private val shoppingCartRedeemError = RedeemShoppingCartError(PHONE, "Wrong phone number") + private val siteChangedError = SiteError(SiteErrorType.GENERIC_ERROR, "Error fetching site") + private val domainContactInformationFetchError = DomainContactError( + DomainContactErrorType.GENERIC_ERROR, + "Error fetching domain contact information" + ) + private val domainSupportedStatesFetchError = DomainSupportedStatesError( + DomainSupportedStatesErrorType.GENERIC_ERROR, + "Error fetching domain supported states" + ) + private val fetchSupportedCountriesError = FetchSupportedCountriesError( + FetchSupportedCountriesErrorType.GENERIC_ERROR, + "Error fetching countries" + ) + + private val createShoppingCartResponse = CreateShoppingCartResponse( + siteId.toInt(), + cartId, + listOf(Product(productId, testDomainName)) + ) + + private val domainProductDetails = DomainProductDetails(productId, testDomainName) + + @Before + fun setUp() { + site.siteId = siteId + + viewModel = DomainRegistrationDetailsViewModel(dispatcher, store) + // Setting up chain of actions + setupFetchSupportedCountriesDispatcher(false) + setupFetchDomainContactInformationDispatcher(false) + setupFetchStatesDispatcher(false) + } + + @Test + fun errorFetchingCountriesDuringPreload() = test { + viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) + viewModel.showErrorMessage.observeForever(errorMessageObserver) + + setupFetchSupportedCountriesDispatcher(true) + + viewModel.start(site, domainProductDetails) + + // Verifying that correct actions with expected payloads were dispatched + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(1)).dispatch(captor.capture()) + + val actionsDispatched = captor.allValues + validateFetchSupportedCountriesAction(actionsDispatched[0]) + + verify(formProgressIndicatorObserver, times(1)).onChanged(true) + verify(formProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) + + verify(errorMessageObserver, times(1)).onChanged(fetchSupportedCountriesError.message) + } + + @Test + fun errorFetchingDomainContactInformationDuringPreload() = test { + viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) + viewModel.showErrorMessage.observeForever(errorMessageObserver) + viewModel.domainContactDetails.observeForever(domainContactDetailsObserver) + + setupFetchSupportedCountriesDispatcher(false) + setupFetchDomainContactInformationDispatcher(true) + + viewModel.start(site, domainProductDetails) + + // Verifying that correct actions with expected payloads were dispatched + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(2)).dispatch(captor.capture()) + + val actionsDispatched = captor.allValues + validateFetchSupportedCountriesAction(actionsDispatched[0]) + validateFetchDomainContactAction(actionsDispatched[1]) + + verify(errorMessageObserver, times(1)).onChanged(domainContactInformationFetchError.message) + + verify(formProgressIndicatorObserver, times(1)).onChanged(true) + verify(formProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) + + verify(domainContactDetailsObserver, times(0)).onChanged(any()) + Assertions.assertThat(viewModel.domainContactDetails.value).isNull() + } + + @Test + fun errorFetchingStatesDuringPreload() = test { + viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) + viewModel.showErrorMessage.observeForever(errorMessageObserver) + viewModel.domainRegistrationButtonEnabled.observeForever(domainRegistrationButtonObserver) + viewModel.selectedState.observeForever(selectedStateObserver) + viewModel.stateInputVisible.observeForever(stateInputVisibleObserver) + viewModel.statesProgressIndicatorVisible.observeForever(stateProgressIndicatorObserver) + + setupFetchSupportedCountriesDispatcher(false) + setupFetchDomainContactInformationDispatcher(false) + setupFetchStatesDispatcher(true) + + viewModel.start(site, domainProductDetails) + + // Verifying that correct actions with expected payloads were dispatched + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(3)).dispatch(captor.capture()) + + val actionsDispatched = captor.allValues + validateFetchSupportedCountriesAction(actionsDispatched[0]) + validateFetchDomainContactAction(actionsDispatched[1]) + validateFetchStatesAction(actionsDispatched[2]) + + verify(errorMessageObserver, times(1)).onChanged(domainSupportedStatesFetchError.message) + + verify(formProgressIndicatorObserver, times(1)).onChanged(true) + verify(formProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) + + verify(stateProgressIndicatorObserver, times(1)).onChanged(true) + verify(stateProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.statesProgressIndicatorVisible.value).isEqualTo(false) + + // domain registration button was disabled and then enabled + verify(domainRegistrationButtonObserver, times(1)).onChanged(true) + verify(domainRegistrationButtonObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) + } + + @Test + fun contactDetailsPreload() = test { + // Setting up all observes for all engaged LiveData + viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) + viewModel.statesProgressIndicatorVisible.observeForever(stateProgressIndicatorObserver) + viewModel.domainRegistrationButtonEnabled.observeForever(domainRegistrationButtonObserver) + viewModel.domainContactDetails.observeForever(domainContactDetailsObserver) + viewModel.selectedState.observeForever(selectedStateObserver) + viewModel.selectedCountry.observeForever(selectedCountryObserver) + viewModel.stateInputVisible.observeForever(stateInputVisibleObserver) + + viewModel.start(site, domainProductDetails) + + // Verifying that correct actions with expected payloads were dispatched + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(3)).dispatch(captor.capture()) + + val actionsDispatched = captor.allValues + validateFetchSupportedCountriesAction(actionsDispatched[0]) + validateFetchDomainContactAction(actionsDispatched[1]) + validateFetchStatesAction(actionsDispatched[2]) + + // form progress indicator was shown and dismissed + verify(formProgressIndicatorObserver, times(1)).onChanged(true) + verify(formProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) + + // states progress indicator was shown and dismissed + verify(stateProgressIndicatorObserver, times(1)).onChanged(true) + verify(stateProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.statesProgressIndicatorVisible.value).isEqualTo(false) + + // domain registration button was disabled and then enabled + verify(domainRegistrationButtonObserver, times(1)).onChanged(true) + verify(domainRegistrationButtonObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) + + verify(domainContactDetailsObserver, times(1)).onChanged(domainContactModel) + + verify(selectedStateObserver, times(1)).onChanged(selectedState) + Assertions.assertThat(viewModel.selectedState.value).isEqualTo(selectedState) + + verify(selectedCountryObserver, times(1)).onChanged(selectedCountry) + Assertions.assertThat(viewModel.selectedCountry.value).isEqualTo(selectedCountry) + + verify(stateInputVisibleObserver, times(1)).onChanged(true) + Assertions.assertThat(viewModel.stateInputVisible.value).isEqualTo(true) + } + + @Test + fun onCountrySelectorClicked() = test { + viewModel.showCountryPickerDialog.observeForever(countryPickerDialogObserver) + + viewModel.start(site, domainProductDetails) + + viewModel.onCountrySelectorClicked() + + verify(countryPickerDialogObserver, times(1)).onChanged(testCountries) + } + + @Test + fun onStateSelectorClicked() = test { + viewModel.showStatePickerDialog.observeForever(statePickerDialogObserver) + + viewModel.start(site, domainProductDetails) + + viewModel.onStateSelectorClicked() + + verify(statePickerDialogObserver, times(1)).onChanged(testStates) + } + + @Test + fun onCountrySelected() = test { + viewModel.selectedCountry.observeForever(selectedCountryObserver) + viewModel.selectedState.observeForever(selectedStateObserver) + viewModel.statesProgressIndicatorVisible.observeForever(stateProgressIndicatorObserver) + viewModel.domainRegistrationButtonEnabled.observeForever(domainRegistrationButtonObserver) + viewModel.stateInputVisible.observeForever(stateInputVisibleObserver) + + viewModel.start(site, domainProductDetails) + + viewModel.onCountrySelected(selectedCountry) + + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(4)).dispatch(captor.capture()) + + val actionsDispatched = captor.allValues + validateFetchStatesAction(actionsDispatched[3]) + + verify(selectedStateObserver, times(2)).onChanged(selectedState) + Assertions.assertThat(viewModel.selectedState.value).isEqualTo(selectedState) + + Assertions.assertThat(viewModel.selectedState.value).isEqualTo(selectedState) + verify(selectedCountryObserver, times(2)).onChanged(selectedCountry) + + // states progress indicator was shown and dismissed + verify(stateProgressIndicatorObserver, times(2)).onChanged(true) + verify(stateProgressIndicatorObserver, times(2)).onChanged(false) + Assertions.assertThat(viewModel.statesProgressIndicatorVisible.value).isEqualTo(false) + + // domain registration button was disabled and then enabled + verify(domainRegistrationButtonObserver, times(2)).onChanged(true) + verify(domainRegistrationButtonObserver, times(2)).onChanged(false) + Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) + + verify(stateInputVisibleObserver, times(2)).onChanged(true) + Assertions.assertThat(viewModel.stateInputVisible.value).isEqualTo(true) + } + + @Test + fun onStateSelected() = test { + viewModel.selectedState.observeForever(selectedStateObserver) + + viewModel.start(site, domainProductDetails) + + viewModel.onStateSelected(selectedState) + + verify(selectedStateObserver, times(2)).onChanged(selectedState) + Assertions.assertThat(viewModel.selectedState.value).isEqualTo(selectedState) + } + + @Test + fun onRegisterDomainButtonClicked() = test { + setupCreateShoppingCartDispatcher(false) + setupRedeemShoppingCartDispatcher(false) + setupFetchSiteDispatcher(false) + + viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) + viewModel.handleCompletedDomainRegistration.observeForever(completedDomainRegistrationObserver) + + viewModel.start(site, domainProductDetails) + + viewModel.onRegisterDomainButtonClicked() + + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(6)).dispatch(captor.capture()) + + val actionsDispatched = captor.allValues + + validateCreateCartAction(actionsDispatched[3]) + validateRedeemCartAction(actionsDispatched[4]) + validateFetchSiteAction(actionsDispatched[5]) + + verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(true) + verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.registrationProgressIndicatorVisible.value).isEqualTo(false) + + verify(completedDomainRegistrationObserver, times(1)).onChanged(null) + } + + @Test + fun onErrorCreatingCart() = test { + setupCreateShoppingCartDispatcher(true) + + viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) + viewModel.showErrorMessage.observeForever(errorMessageObserver) + + viewModel.start(site, domainProductDetails) + + viewModel.onRegisterDomainButtonClicked() + + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(4)).dispatch(captor.capture()) + + val actionsDispatched = captor.allValues + validateCreateCartAction(actionsDispatched[3]) + + verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(true) + verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.registrationProgressIndicatorVisible.value).isEqualTo(false) + + verify(errorMessageObserver, times(1)).onChanged(shoppingCartCreateError.message) + } + + @Test + fun onErrorRedeemingCart() = test { + setupCreateShoppingCartDispatcher(false) + setupRedeemShoppingCartDispatcher(true) + + viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) + viewModel.showErrorMessage.observeForever(errorMessageObserver) + + viewModel.start(site, domainProductDetails) + + viewModel.onRegisterDomainButtonClicked() + + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(5)).dispatch(captor.capture()) + + val actionsDispatched = captor.allValues + validateCreateCartAction(actionsDispatched[3]) + validateRedeemCartAction(actionsDispatched[4]) + + verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(true) + verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.registrationProgressIndicatorVisible.value).isEqualTo(false) + + verify(errorMessageObserver, times(1)).onChanged(shoppingCartRedeemError.message) + } + + @Test + fun onErrorFetchingSite() = test { + setupCreateShoppingCartDispatcher(false) + setupRedeemShoppingCartDispatcher(false) + setupFetchSiteDispatcher(true) + + viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) + viewModel.showErrorMessage.observeForever(errorMessageObserver) + viewModel.handleCompletedDomainRegistration.observeForever(completedDomainRegistrationObserver) + + viewModel.start(site, domainProductDetails) + + viewModel.onRegisterDomainButtonClicked() + + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(6)).dispatch(captor.capture()) + + val actionsDispatched = captor.allValues + + validateCreateCartAction(actionsDispatched[3]) + validateRedeemCartAction(actionsDispatched[4]) + validateFetchSiteAction(actionsDispatched[5]) + + verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(true) + verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.registrationProgressIndicatorVisible.value).isEqualTo(false) + + verify(errorMessageObserver, times(1)).onChanged(siteChangedError.message) + + verify(completedDomainRegistrationObserver, times(1)).onChanged(null) + } + + @Test + fun onTosLinkClicked() = test { + viewModel.showTos.observeForever(tosLinkObserver) + + viewModel.start(site, domainProductDetails) + + viewModel.onTosLinkClicked() + + verify(tosLinkObserver, times(1)).onChanged(null) + } + + @Test + fun onDomainContactDetailsChanged() = test { + viewModel.domainContactDetails.observeForever(domainContactDetailsObserver) + + viewModel.start(site, domainProductDetails) + + val updatedDomainContactDetails = domainContactModel.copy(firstName = "Peter") + + viewModel.onDomainContactDetailsChanged(updatedDomainContactDetails) + + verify(domainContactDetailsObserver, times(1)).onChanged(updatedDomainContactDetails) + Assertions.assertThat(viewModel.domainContactDetails.value).isEqualTo(updatedDomainContactDetails) + } + + @Test + fun togglePrivacyProtection() = test { + viewModel.privacyProtectionState.observeForever(privacyProtectionObserver) + + viewModel.start(site, domainProductDetails) + + Assertions.assertThat(viewModel.privacyProtectionState.value).isTrue() + + viewModel.togglePrivacyProtection(true) + verify(privacyProtectionObserver, times(2)).onChanged(true) + + viewModel.togglePrivacyProtection(false) + verify(privacyProtectionObserver, times(1)).onChanged(false) + } + + private fun setupFetchSupportedCountriesDispatcher(isError: Boolean) { + val event = if (isError) { + OnSupportedCountriesFetched(fetchSupportedCountriesError) + } else { + OnSupportedCountriesFetched(testCountries) + } + whenever(dispatcher.dispatch(argWhere> { it.type == FETCH_SUPPORTED_COUNTRIES })).then { + viewModel.onSupportedCountriesFetched(event) + } + } + + private fun setupFetchStatesDispatcher(isError: Boolean) { + val event = if (isError) { + OnDomainSupportedStatesFetched(null, domainSupportedStatesFetchError) + } else { + OnDomainSupportedStatesFetched(testStates, null) + } + whenever(dispatcher.dispatch(argWhere> { it.type == SiteAction.FETCH_DOMAIN_SUPPORTED_STATES })).then { + viewModel.onDomainSupportedStatesFetched(event) + } + } + + private fun setupFetchDomainContactInformationDispatcher(isError: Boolean) { + val event = if (isError) { + OnDomainContactFetched(null, domainContactInformationFetchError) + } else { + OnDomainContactFetched(domainContactModel, null) + } + whenever(dispatcher.dispatch(argWhere> { it.type == AccountAction.FETCH_DOMAIN_CONTACT })).then { + viewModel.onDomainContactFetched(event) + } + } + + private fun setupCreateShoppingCartDispatcher(isError: Boolean) { + val event = if (isError) { + OnShoppingCartCreated(shoppingCartCreateError) + } else { + OnShoppingCartCreated(createShoppingCartResponse) + } + whenever(dispatcher.dispatch(argWhere> { it.type == TransactionAction.CREATE_SHOPPING_CART })).then { + viewModel.onShoppingCartCreated(event) + } + } + + private fun setupRedeemShoppingCartDispatcher(isError: Boolean) { + val event = if (isError) { + OnShoppingCartRedeemed(shoppingCartRedeemError) + } else { + OnShoppingCartRedeemed(true) + } + whenever(dispatcher.dispatch(argWhere> { it.type == TransactionAction.REDEEM_CART_WITH_CREDITS })).then { + viewModel.onCartRedeemed(event) + } + } + + private fun setupFetchSiteDispatcher(isError: Boolean) { + val event = OnSiteChanged(1) + if (isError) { + event.error = siteChangedError + } + whenever(dispatcher.dispatch(argWhere> { it.type == SiteAction.FETCH_SITE })).then { + viewModel.onSiteChanged(event) + } + } + + private fun validateFetchSupportedCountriesAction(action: Action<*>) { + Assertions.assertThat(action.type).isEqualTo(FETCH_SUPPORTED_COUNTRIES) + Assertions.assertThat(action.payload).isNull() + } + + private fun validateFetchDomainContactAction(action: Action<*>) { + Assertions.assertThat(action.type).isEqualTo(AccountAction.FETCH_DOMAIN_CONTACT) + Assertions.assertThat(action.payload).isNull() + } + + private fun validateFetchStatesAction(action: Action<*>) { + Assertions.assertThat(action.type).isEqualTo(SiteAction.FETCH_DOMAIN_SUPPORTED_STATES) + Assertions.assertThat(action.payload).isEqualTo("US") + } + + private fun validateCreateCartAction(action: Action<*>) { + Assertions.assertThat(action.type).isEqualTo(TransactionAction.CREATE_SHOPPING_CART) + Assertions.assertThat(action.payload).isNotNull + Assertions.assertThat(action.payload).isInstanceOf(CreateShoppingCartPayload::class.java) + + val createShoppingCartPayload = action.payload as CreateShoppingCartPayload + Assertions.assertThat(createShoppingCartPayload.site).isEqualTo(site) + Assertions.assertThat(createShoppingCartPayload.domainName).isEqualTo(testDomainName) + Assertions.assertThat(createShoppingCartPayload.productId).isEqualTo(productId) + Assertions.assertThat(createShoppingCartPayload.isPrivacyEnabled).isEqualTo(true) + } + + private fun validateRedeemCartAction(action: Action<*>) { + Assertions.assertThat(action.type).isEqualTo(TransactionAction.REDEEM_CART_WITH_CREDITS) + Assertions.assertThat(action.payload).isNotNull + Assertions.assertThat(action.payload).isInstanceOf(RedeemShoppingCartPayload::class.java) + + val redeemShoppingCartPayload = action.payload as RedeemShoppingCartPayload + Assertions.assertThat(redeemShoppingCartPayload.cartDetails).isEqualTo(createShoppingCartResponse) + Assertions.assertThat(redeemShoppingCartPayload.domainContactModel).isEqualTo(domainContactModel) + } + + private fun validateFetchSiteAction(action: Action<*>) { + Assertions.assertThat(action.type).isEqualTo(SiteAction.FETCH_SITE) + Assertions.assertThat(action.payload).isNotNull + Assertions.assertThat(action.payload).isInstanceOf(SiteModel::class.java) + + val fetchSitePayload = action.payload as SiteModel + Assertions.assertThat(fetchSitePayload).isEqualTo(site) + } +} From 0838f6cbb252bc644c151a2c3cad4ecc25628423 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Mon, 20 May 2019 09:41:50 -0700 Subject: [PATCH 03/21] Added ViewModel to fragment. --- .../DomainRegistrationDetailsFragment.kt | 576 ++++++++---------- .../ui/domains/OnCountrySelectedListener.kt | 7 + .../ui/domains/OnStateSelectedListener.kt | 7 + 3 files changed, 276 insertions(+), 314 deletions(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/domains/OnCountrySelectedListener.kt create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/domains/OnStateSelectedListener.kt diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index 18995f1ed509..bb123737333d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -1,13 +1,20 @@ package org.wordpress.android.ui.domains +import android.app.Dialog import android.app.ProgressDialog +import android.arch.lifecycle.Observer +import android.arch.lifecycle.ViewModelProvider +import android.arch.lifecycle.ViewModelProviders import android.os.Bundle import android.support.design.widget.TextInputEditText import android.support.design.widget.TextInputLayout +import android.support.v4.app.DialogFragment import android.support.v4.app.Fragment import android.support.v7.app.AlertDialog +import android.text.Editable import android.text.SpannableString import android.text.TextUtils +import android.text.TextWatcher import android.text.method.LinkMovementMethod import android.text.style.ClickableSpan import android.text.style.UnderlineSpan @@ -16,29 +23,13 @@ import android.view.View import android.view.ViewGroup import android.widget.EditText import kotlinx.android.synthetic.main.domain_registration_details_fragment.* -import org.apache.commons.text.StringEscapeUtils -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode +import org.apache.commons.lang3.StringEscapeUtils import org.wordpress.android.R import org.wordpress.android.WordPress -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.action.TransactionAction.FETCH_SUPPORTED_COUNTRIES -import org.wordpress.android.fluxc.generated.AccountActionBuilder -import org.wordpress.android.fluxc.generated.SiteActionBuilder -import org.wordpress.android.fluxc.generated.TransactionActionBuilder import org.wordpress.android.fluxc.model.DomainContactModel import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.network.rest.wpcom.site.SupportedStateResponse import org.wordpress.android.fluxc.network.rest.wpcom.transactions.SupportedDomainCountry -import org.wordpress.android.fluxc.store.AccountStore.OnDomainContactFetched -import org.wordpress.android.fluxc.store.SiteStore.OnDomainSupportedStatesFetched -import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged -import org.wordpress.android.fluxc.store.TransactionsStore -import org.wordpress.android.fluxc.store.TransactionsStore.CreateShoppingCartPayload -import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartCreated -import org.wordpress.android.fluxc.store.TransactionsStore.OnShoppingCartRedeemed -import org.wordpress.android.fluxc.store.TransactionsStore.OnSupportedCountriesFetched -import org.wordpress.android.fluxc.store.TransactionsStore.RedeemShoppingCartPayload import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType.ADDRESS_1 import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType.ADDRESS_2 import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType.CITY @@ -51,14 +42,13 @@ import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType. import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType.POSTAL_CODE import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType.STATE import org.wordpress.android.ui.ActivityLauncher -import org.wordpress.android.util.AppLog -import org.wordpress.android.util.AppLog.T import org.wordpress.android.util.StringUtils import org.wordpress.android.util.ToastUtils import org.wordpress.android.util.WPUrlUtils +import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel import javax.inject.Inject -class DomainRegistrationDetailsFragment : Fragment() { +class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, OnCountrySelectedListener { companion object { private const val PHONE_NUMBER_PREFIX = "+" private const val PHONE_NUMBER_CONNECTING_CHARACTER = "." @@ -66,17 +56,6 @@ class DomainRegistrationDetailsFragment : Fragment() { private const val EXTRA_DOMAIN_PRODUCT_DETAILS = "EXTRA_DOMAIN_PRODUCT_DETAILS" const val TAG = "DOMAIN_SUGGESTION_FRAGMENT_TAG" - private const val EXTRA_STATES_FETCH_PROGRESS_VISIBLE = "EXTRA_STATES_FETCH_PROGRESS_VISIBLE" - private const val EXTRA_PROGRESS_DIALOG_VISIBLE = "EXTRA_PROGRESS_DIALOG_VISIBLE" - private const val EXTRA_FORM_PROGRESS_INDICATOR_VISIBLE = "EXTRA_FORM_PROGRESS_INDICATOR_VISIBLE" - - private const val EXTRA_SUPPORTED_COUNTRIES = "EXTRA_SUPPORTED_COUNTRIES" - private const val EXTRA_SUPPORTED_STATES = "EXTRA_SUPPORTED_STATES" - - private const val EXTRA_SELECTED_COUNTRY = "EXTRA_SELECTED_COUNTRY" - private const val EXTRA_SELECTED_STATE = "EXTRA_SELECTED_STATE" - private const val EXTRA_INITIAL_DOMAIN_CONTACT_MODEL = "EXTRA_INITIAL_DOMAIN_CONTACT_MODEL" - fun newInstance(domainProductDetails: DomainProductDetails): DomainRegistrationDetailsFragment { val fragment = DomainRegistrationDetailsFragment() val bundle = Bundle() @@ -86,19 +65,12 @@ class DomainRegistrationDetailsFragment : Fragment() { } } - @Inject lateinit var transactionStore: TransactionsStore // needs to be included - @Inject lateinit var dispatcher: Dispatcher + @Inject lateinit var viewModelFactory: ViewModelProvider.Factory + private lateinit var viewModel: DomainRegistrationDetailsViewModel private var site: SiteModel? = null private var domainProductDetails: DomainProductDetails? = null - private var supportedCountries: ArrayList? = null - private var supportedStates: ArrayList? = null - - private var selectedCountry: SupportedDomainCountry? = null - private var selectedState: SupportedStateResponse? = null - private var initialDomainContactModel: DomainContactModel? = null - private var loadingProgressDialog: ProgressDialog? = null override fun onCreate(savedInstanceState: Bundle?) { @@ -109,39 +81,6 @@ class DomainRegistrationDetailsFragment : Fragment() { site = nonNullActivity.intent?.getSerializableExtra(WordPress.SITE) as SiteModel domainProductDetails = arguments?.getParcelable(EXTRA_DOMAIN_PRODUCT_DETAILS) - - if (savedInstanceState != null) { - supportedCountries = savedInstanceState.getParcelableArrayList( - EXTRA_SUPPORTED_COUNTRIES - ) - supportedStates = savedInstanceState.getParcelableArrayList(EXTRA_SUPPORTED_STATES) - - selectedCountry = savedInstanceState.getParcelable(EXTRA_SELECTED_COUNTRY) - selectedState = savedInstanceState.getParcelable(EXTRA_SELECTED_STATE) - - initialDomainContactModel = savedInstanceState.getParcelable(EXTRA_INITIAL_DOMAIN_CONTACT_MODEL) - } - } - - override fun onSaveInstanceState(outState: Bundle) { - outState.putSerializable(WordPress.SITE, site) - outState.putParcelable(EXTRA_DOMAIN_PRODUCT_DETAILS, domainProductDetails) - outState.putParcelableArrayList(EXTRA_SUPPORTED_COUNTRIES, supportedCountries) - outState.putParcelableArrayList(EXTRA_SUPPORTED_STATES, supportedStates) - outState.putParcelable(EXTRA_SELECTED_COUNTRY, selectedCountry) - outState.putParcelable(EXTRA_SELECTED_STATE, selectedState) - outState.putParcelable(EXTRA_INITIAL_DOMAIN_CONTACT_MODEL, initialDomainContactModel) - outState.putBoolean( - EXTRA_PROGRESS_DIALOG_VISIBLE, - loadingProgressDialog != null && loadingProgressDialog!!.isShowing - ) - - outState.putBoolean( - EXTRA_STATES_FETCH_PROGRESS_VISIBLE, - states_loading_progress_indicator.visibility == View.VISIBLE - ) - outState.putBoolean(EXTRA_FORM_PROGRESS_INDICATOR_VISIBLE, form_progress_indicator.visibility == View.VISIBLE) - super.onSaveInstanceState(outState) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -151,23 +90,59 @@ class DomainRegistrationDetailsFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(DomainRegistrationDetailsViewModel::class.java) + setupObservers() + viewModel.start(site!!, domainProductDetails!!) + // Country and State input could only be populated from the dialog country_input.inputType = 0 country_input.setOnClickListener { - showCountryPicker(supportedCountries!!) + viewModel.onCountrySelectorClicked() } state_input.inputType = 0 state_input.setOnClickListener { - showStatePicker(supportedStates!!) + viewModel.onStateSelectorClicked() } register_domain_button.setOnClickListener { if (validateForm()) { - registerDomain() + viewModel.onRegisterDomainButtonClicked() } } + setupTosLink() + setupInputFieldTextWatchers() + } + + private fun setupInputFieldTextWatchers() { + arrayOf( + first_name_input, + last_name_input, + organization_input, + email_input, + country_code_input, + phone_number_input, + address_first_line_input, + address_second_line_input, + city_input, + postal_code_input + ).forEach { + it.addTextChangedListener(object : TextWatcher { + override fun afterTextChanged(p0: Editable?) { + viewModel.onDomainContactDetailsChanged(contactFormToDomainContactModel()) + } + + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + } + + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + } + }) + } + } + + private fun setupTosLink() { // make link to ToS clickable val spannableTosString = SpannableString(tos_explanation.text) val tosUnderlineSpan = spannableTosString.getSpans( @@ -179,7 +154,7 @@ class DomainRegistrationDetailsFragment : Fragment() { if (tosUnderlineSpan.size == 1) { val tosClickableSpan = object : ClickableSpan() { override fun onClick(widget: View?) { - ActivityLauncher.openUrlExternal(context, WPUrlUtils.buildTermsOfServiceUrl(context)) + viewModel.onTosLinkClicked() } } @@ -197,38 +172,143 @@ class DomainRegistrationDetailsFragment : Fragment() { tos_explanation.movementMethod = LinkMovementMethod.getInstance() } else { tos_explanation.setOnClickListener { - ActivityLauncher.openUrlExternal(context, WPUrlUtils.buildTermsOfServiceUrl(context)) + viewModel.onTosLinkClicked() } } + } - if (supportedStates == null || supportedStates!!.isEmpty()) { - toggleStatesInputFieldVisibility(false) - } - - if (savedInstanceState != null) { - val isStatesLoadingProgressVisible = savedInstanceState.getBoolean(EXTRA_STATES_FETCH_PROGRESS_VISIBLE) - val isFormProgressIndicatorVisible = savedInstanceState.getBoolean(EXTRA_FORM_PROGRESS_INDICATOR_VISIBLE) - val isProgressDialogVisible = savedInstanceState.getBoolean(EXTRA_PROGRESS_DIALOG_VISIBLE) - - if (isFormProgressIndicatorVisible) { - showFormProgressIndicator() - } else { - hideFormProgressIndicator() - } + private fun setupObservers() { + viewModel.formProgressIndicatorVisible.observe(this, + Observer { isVisible -> + if (isVisible == true) { + showFormProgressIndicator() + } else { + hideFormProgressIndicator() + } + }) + + viewModel.statesProgressIndicatorVisible.observe(this, + Observer { isVisible -> + if (isVisible == true) { + showStateProgress() + } else { + hideStateProgress() + } + }) + + viewModel.registrationProgressIndicatorVisible.observe(this, + Observer { isVisible -> + if (isVisible == true) { + showDomainRegistrationProgressDialog() + } else { + hideDomainRegistrationProgressDialog() + } + }) + + viewModel.domainRegistrationButtonEnabled.observe(this, + Observer { isEnabled -> + register_domain_button.isEnabled = isEnabled == true + }) + + viewModel.privacyProtectionState.observe(this, object : Observer { + override fun onChanged(privacyEnabled: Boolean?) { + if (privacyEnabled != null && privacyEnabled) { + domain_privacy_options_radiogroup.check(R.id.domain_privacy_on_radio_button) + } else { + domain_privacy_options_radiogroup.check(R.id.domain_privacy_off_radio_button) + } - if (isStatesLoadingProgressVisible) { - showStatesProgressIndicator() - } else { - hideStatesProgressIndicator() + domain_privacy_options_radiogroup.setOnCheckedChangeListener { _, _ -> + viewModel.togglePrivacyProtection(domain_privacy_on_radio_button.isChecked) + } + viewModel.privacyProtectionState.removeObserver(this) } + }) - if (isProgressDialogVisible) { - showDomainRegistrationProgressDialog() + viewModel.domainContactDetails.observe(this, object : Observer { + override fun onChanged(domainContactModel: DomainContactModel?) { + populateContactForm(domainContactModel!!) + viewModel.domainContactDetails.removeObserver(this) } - } else { - showFormProgressIndicator() - fetchInitialData() - } + }) + + viewModel.stateInputVisible.observe(this, + Observer { stateInputVisible -> + if (stateInputVisible != null && stateInputVisible) { + showStateInput() + } else { + hideStatesInput() + } + }) + + viewModel.selectedCountry.observe(this, + Observer { country -> + if (country != null) { + country_input.setText(country.name) + } + }) + + viewModel.selectedState.observe(this, + Observer { state -> + state_input.setText(state?.name) + }) + + viewModel.showCountryPickerDialog.observe(this, + Observer { + if (it != null && it.isNotEmpty()) { + showCountryPicker(it) + } + }) + + viewModel.showStatePickerDialog.observe(this, + Observer { + if (it != null && it.isNotEmpty()) { + showStatePicker(it) + } + }) + + viewModel.formError.observe(this, + Observer { error -> + var affectedInputFields: Array? = null + + when (error!!.type) { + FIRST_NAME -> affectedInputFields = arrayOf(first_name_input) + LAST_NAME -> affectedInputFields = arrayOf(last_name_input) + ORGANIZATION -> affectedInputFields = arrayOf(organization_input) + ADDRESS_1 -> affectedInputFields = arrayOf(address_first_line_input) + ADDRESS_2 -> affectedInputFields = arrayOf(address_second_line_input) + POSTAL_CODE -> affectedInputFields = arrayOf(postal_code_input) + CITY -> affectedInputFields = arrayOf(city_input) + STATE -> affectedInputFields = arrayOf(state_input) + COUNTRY_CODE -> affectedInputFields = arrayOf(country_code_input) + EMAIL -> affectedInputFields = arrayOf(email_input) + PHONE -> affectedInputFields = arrayOf(country_code_input, phone_number_input) + else -> { + } // Something else, will just show a Toast with an error message + } + affectedInputFields?.forEach { + showFieldError( + it, + StringEscapeUtils.unescapeHtml4(error.message) + ) + } + affectedInputFields?.firstOrNull { it.requestFocus() } + }) + + viewModel.showErrorMessage.observe(this, + Observer { errorMessage -> + ToastUtils.showToast(context, errorMessage) + }) + + viewModel.handleCompletedDomainRegistration.observe(this, + Observer { + (activity as DomainRegistrationActivity).onDomainRegistered(domainProductDetails!!.domainName) + }) + + viewModel.showTos.observe(this, + Observer { + ActivityLauncher.openUrlExternal(context, WPUrlUtils.buildTermsOfServiceUrl(context)) + }) } private fun populateContactForm(domainContactInformation: DomainContactModel) { @@ -236,8 +316,6 @@ class DomainRegistrationDetailsFragment : Fragment() { last_name_input.setText(domainContactInformation.lastName) organization_input.setText(domainContactInformation.organization) email_input.setText(domainContactInformation.email) - country_input.setText(selectedCountry?.name) - state_input.setText(domainContactInformation.state) if (!TextUtils.isEmpty(domainContactInformation.phone)) { val phoneParts = domainContactInformation.phone!!.split(PHONE_NUMBER_CONNECTING_CHARACTER) @@ -291,20 +369,6 @@ class DomainRegistrationDetailsFragment : Fragment() { editText.error = errorMessage } - private fun registerDomain() { - showDomainRegistrationProgressDialog() - dispatcher.dispatch( - TransactionActionBuilder.newCreateShoppingCartAction( - CreateShoppingCartPayload( - site!!, - domainProductDetails!!.productId, - domainProductDetails!!.domainName, - domain_privacy_on_radio_button.isChecked - ) - ) - ) - } - private fun contactFormToDomainContactModel(): DomainContactModel { val combinedPhoneNumber = getString( R.string.domain_registration_phone_number_format, @@ -320,53 +384,32 @@ class DomainRegistrationDetailsFragment : Fragment() { address_second_line_input.text.toString(), postal_code_input.text.toString(), city_input.text.toString(), - selectedState?.code, - selectedCountry?.code, + null, // state code will be added in ViewModel + null, // country code will be added in ViewModel email_input.text.toString(), combinedPhoneNumber, null ) } - private fun showStatePicker(states: List?) { - if (states == null || states.isEmpty()) { - return - } - - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(R.string.domain_registration_state_picker_dialog_title) - builder.setItems(states.map { it.name }.toTypedArray()) { _, which -> - selectedState = states[which] - state_input.setText(selectedState!!.name) - } - - builder.setPositiveButton(R.string.dialog_button_cancel) { dialog, _ -> - dialog.dismiss() - } - - builder.show() + private fun showStatePicker(states: List) { + val dialogFragment = StatePickerDialogFragment.newInstance(states.toCollection(ArrayList())) + dialogFragment.setTargetFragment(this, 0) + dialogFragment.show(fragmentManager, StatePickerDialogFragment.TAG) } private fun showCountryPicker(countries: List) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(R.string.domain_registration_country_picker_dialog_title) - builder.setItems(countries.map { it.name }.toTypedArray()) { _, which -> - val pickedCountry = countries[which] - - if (selectedCountry != pickedCountry) { - selectedCountry = pickedCountry - country_input.setText(selectedCountry!!.name) - selectedState = null - state_input.text = null - fetchStates() - } - } + val dialogFragment = CountryPickerDialogFragment.newInstance(countries.toCollection(ArrayList())) + dialogFragment.setTargetFragment(this, 0) + dialogFragment.show(fragmentManager, CountryPickerDialogFragment.TAG) + } - builder.setPositiveButton(R.string.dialog_button_cancel) { dialog, _ -> - dialog.dismiss() - } + override fun OnCountrySelected(country: SupportedDomainCountry) { + viewModel.onCountrySelected(country) + } - builder.show() + override fun onStateSelected(state: SupportedStateResponse) { + viewModel.onStateSelected(state) } private fun showFormProgressIndicator() { @@ -377,14 +420,22 @@ class DomainRegistrationDetailsFragment : Fragment() { form_progress_indicator.visibility = View.GONE } - private fun showStatesProgressIndicator() { + private fun showStateProgress() { states_loading_progress_indicator.visibility = View.VISIBLE } - private fun hideStatesProgressIndicator() { + private fun hideStateProgress() { states_loading_progress_indicator.visibility = View.GONE } + private fun showStateInput() { + state_container.visibility = View.VISIBLE + } + + private fun hideStatesInput() { + state_container.visibility = View.GONE + } + private fun showDomainRegistrationProgressDialog() { if (loadingProgressDialog == null) { loadingProgressDialog = ProgressDialog(context) @@ -399,188 +450,85 @@ class DomainRegistrationDetailsFragment : Fragment() { } } - private fun hideProgressDialog() { + private fun hideDomainRegistrationProgressDialog() { if (loadingProgressDialog != null && loadingProgressDialog!!.isShowing) { loadingProgressDialog!!.cancel() } } - private fun fetchContactInformation() { - dispatcher.dispatch(AccountActionBuilder.newFetchDomainContactAction()) - } + class StatePickerDialogFragment : DialogFragment() { + private lateinit var states: ArrayList - private fun fetchInitialData() { - dispatcher.dispatch(TransactionActionBuilder.generateNoPayloadAction(FETCH_SUPPORTED_COUNTRIES)) - } + companion object { + private const val EXTRA_STATES = "EXTRA_STATES" + const val TAG = "STATE_PICKER_DIALOG_FRAGMENT" - private fun toggleStatesInputFieldVisibility(isEnabled: Boolean) { - state_input_container.visibility = if (isEnabled) { - View.VISIBLE - } else { - View.GONE + fun newInstance(states: ArrayList): StatePickerDialogFragment { + val fragment = StatePickerDialogFragment() + val bundle = Bundle() + bundle.putParcelableArrayList(EXTRA_STATES, states) + fragment.arguments = bundle + return fragment + } } - } - - private fun fetchStates() { - showStatesProgressIndicator() - toggleStatesInputFieldVisibility(false) - dispatcher.dispatch(SiteActionBuilder.newFetchDomainSupportedStatesAction(selectedCountry!!.code)) - } - @Subscribe(threadMode = ThreadMode.MAIN) - fun onSupportedCountriesFetched(event: OnSupportedCountriesFetched) { - if (event.isError) { - hideFormProgressIndicator() - AppLog.e( - T.DOMAIN_REGISTRATION, - "An error occurred while fetching supported countries : " + event.error.message - ) - ToastUtils.showToast( - context, - getString(R.string.domain_registration_error_fetching_contact_information, event.error.message) - ) - return + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + states = arguments!!.getParcelableArrayList(EXTRA_STATES) as ArrayList } - supportedCountries = event.countries?.toCollection(ArrayList()) - fetchContactInformation() - } - @Subscribe(threadMode = ThreadMode.MAIN) - fun onDomainContactFetched(event: OnDomainContactFetched) { - if (event.isError) { - hideFormProgressIndicator() - AppLog.e( - T.DOMAIN_REGISTRATION, - "An error occurred while fetching domain contact information : " + event.error.message - ) - ToastUtils.showToast( - context, - getString(R.string.domain_registration_error_fetching_contact_information, event.error.message) - ) - } else { - initialDomainContactModel = event.contactModel - if (initialDomainContactModel != null && !TextUtils.isEmpty(initialDomainContactModel!!.countryCode)) { - selectedCountry = supportedCountries?.firstOrNull { it.code == initialDomainContactModel!!.countryCode } - populateContactForm(initialDomainContactModel!!) - fetchStates() - } else { - hideFormProgressIndicator() + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val builder = AlertDialog.Builder(requireContext()) + builder.setTitle(R.string.domain_registration_country_picker_dialog_title) + builder.setItems(states.map { it.name }.toTypedArray()) { _, which -> + if (targetFragment != null && targetFragment is OnStateSelectedListener) { + (targetFragment as OnStateSelectedListener).onStateSelected(states[which]) + } } - } - } - @Subscribe(threadMode = ThreadMode.MAIN) - fun onDomainSupportedStatesFetched(event: OnDomainSupportedStatesFetched) { - hideFormProgressIndicator() - hideStatesProgressIndicator() - if (event.isError) { - AppLog.e( - T.DOMAIN_REGISTRATION, - "An error occurred while fetching supported states : " + event.error.message - ) - ToastUtils.showToast( - context, - getString(R.string.domain_registration_error_fetching_contact_information, event.error.message) - ) - return - } - supportedStates = event.supportedStates?.toCollection(ArrayList()) - if (supportedStates != null && supportedStates!!.isNotEmpty()) { - toggleStatesInputFieldVisibility(true) - if (initialDomainContactModel != null && !TextUtils.isEmpty(initialDomainContactModel!!.state)) { - selectedState = supportedStates!!.firstOrNull { it.code == initialDomainContactModel?.state } - state_input.setText(selectedState?.name) + builder.setPositiveButton(R.string.dialog_button_cancel) { dialog, _ -> + dialog.dismiss() } + + return builder.create() } } - @Subscribe(threadMode = ThreadMode.MAIN) - fun onShoppingCartCreated(event: OnShoppingCartCreated) { - if (event.isError) { - hideProgressDialog() - AppLog.e( - T.DOMAIN_REGISTRATION, - "An error occurred while creating a shopping cart : " + event.error.message - ) - ToastUtils.showToast( - context, - getString(R.string.domain_registration_error_registering_domain, event.error.message) - ) - return - } + class CountryPickerDialogFragment : DialogFragment() { + private lateinit var countries: ArrayList - val domainContactInformation = contactFormToDomainContactModel() - dispatcher.dispatch( - TransactionActionBuilder.newRedeemCartWithCreditsAction( - RedeemShoppingCartPayload( - event.cartDetails!!, domainContactInformation - ) - ) - ) - } + companion object { + private const val EXTRA_COUNTRIES = "EXTRA_COUNTRIES" + const val TAG = "COUNTRY_PICKER_DIALOG_FRAGMENT" - @Subscribe(threadMode = ThreadMode.MAIN) - fun onCartRedeemed(event: OnShoppingCartRedeemed) { - if (event.isError) { - hideProgressDialog() - AppLog.e( - T.DOMAIN_REGISTRATION, - "An error occurred while redeeming a shopping cart : " + event.error.type + - " " + event.error.message - ) - ToastUtils.showToast( - context, - getString(R.string.domain_registration_error_registering_domain, event.error.message) - ) - var affectedInputFields: Array? = null - - when (event.error.type) { - FIRST_NAME -> affectedInputFields = arrayOf(first_name_input) - LAST_NAME -> affectedInputFields = arrayOf(last_name_input) - ORGANIZATION -> affectedInputFields = arrayOf(organization_input) - ADDRESS_1 -> affectedInputFields = arrayOf(address_first_line_input) - ADDRESS_2 -> affectedInputFields = arrayOf(address_second_line_input) - POSTAL_CODE -> affectedInputFields = arrayOf(postal_code_input) - CITY -> affectedInputFields = arrayOf(city_input) - STATE -> affectedInputFields = arrayOf(state_input) - COUNTRY_CODE -> affectedInputFields = arrayOf(country_code_input) - EMAIL -> affectedInputFields = arrayOf(email_input) - PHONE -> affectedInputFields = arrayOf(country_code_input, phone_number_input) - else -> { - } // Something else, will just show a Toast with an error message + fun newInstance(countries: ArrayList): CountryPickerDialogFragment { + val fragment = CountryPickerDialogFragment() + val bundle = Bundle() + bundle.putParcelableArrayList(EXTRA_COUNTRIES, countries) + fragment.arguments = bundle + return fragment } - affectedInputFields?.forEach { showFieldError(it, StringEscapeUtils.unescapeHtml4(event.error.message)) } - affectedInputFields?.firstOrNull { it.requestFocus() } - return } - dispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(site)) - } - - @Subscribe(threadMode = ThreadMode.MAIN) - fun onSiteChanged(event: OnSiteChanged) { - hideProgressDialog() - if (event.isError) { - AppLog.e( - T.DOMAIN_REGISTRATION, - "An error occurred while updating site details : " + event.error.message - ) - ToastUtils.showToast( - context, - getString(R.string.domain_registration_error_updating_site, event.error.message) - ) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + countries = arguments!!.getParcelableArrayList(EXTRA_COUNTRIES) as ArrayList } - // if domain registration was successful proceed to result screen anyway - (activity as DomainRegistrationActivity).onDomainRegistered(domainProductDetails!!.domainName) - } - override fun onStart() { - super.onStart() - dispatcher.register(this) - } + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val builder = AlertDialog.Builder(requireContext()) + builder.setTitle(R.string.domain_registration_country_picker_dialog_title) + builder.setItems(countries.map { it.name }.toTypedArray()) { _, which -> + if (targetFragment != null && targetFragment is OnStateSelectedListener) { + (targetFragment as OnCountrySelectedListener).OnCountrySelected(countries[which]) + } + } - override fun onStop() { - super.onStop() - dispatcher.unregister(this) + builder.setPositiveButton(R.string.dialog_button_cancel) { dialog, _ -> + dialog.dismiss() + } + + return builder.create() + } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/OnCountrySelectedListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/OnCountrySelectedListener.kt new file mode 100644 index 000000000000..3681d0aeb6de --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/OnCountrySelectedListener.kt @@ -0,0 +1,7 @@ +package org.wordpress.android.ui.domains + +import org.wordpress.android.fluxc.network.rest.wpcom.transactions.SupportedDomainCountry + +interface OnCountrySelectedListener { + fun OnCountrySelected(country: SupportedDomainCountry) +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/OnStateSelectedListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/OnStateSelectedListener.kt new file mode 100644 index 000000000000..a3ded426f6f8 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/OnStateSelectedListener.kt @@ -0,0 +1,7 @@ +package org.wordpress.android.ui.domains + +import org.wordpress.android.fluxc.network.rest.wpcom.site.SupportedStateResponse + +interface OnStateSelectedListener { + fun onStateSelected(state: SupportedStateResponse) +} From 1ca6e5cb95040f3fe4e09cc7c62d4c0ec05abb16 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Mon, 20 May 2019 09:42:06 -0700 Subject: [PATCH 04/21] Updated layout and resources. --- .../res/layout/domain_registration_details_fragment.xml | 8 +++++--- WordPress/src/main/res/values/strings.xml | 3 --- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/res/layout/domain_registration_details_fragment.xml b/WordPress/src/main/res/layout/domain_registration_details_fragment.xml index d70e16ed17b3..cc7ee100880c 100644 --- a/WordPress/src/main/res/layout/domain_registration_details_fragment.xml +++ b/WordPress/src/main/res/layout/domain_registration_details_fragment.xml @@ -49,8 +49,7 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_large" android:checkedButton="@+id/domain_privacy_on_radio_button" - tools:ignore="UnusedAttribute" - tools:visibility="visible"> + tools:ignore="UnusedAttribute"> @@ -257,7 +258,7 @@ android:layout_alignParentEnd="true" android:layout_alignTop="@+id/state_input_container" android:layout_centerInParent="true" - android:visibility="visible" + android:visibility="gone" /> @@ -312,6 +313,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/background_default" + android:visibility="gone" tools:visibility="gone"> Select Country Select State Registering domain name… - Error occurred during domain registration: %s - Error occurred fetching domain contact information: %s - Error occurred while updating your site details: %s +%s.%s From 4cf6a19742a7462a65c87a068eb1f7e42352a047 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Mon, 20 May 2019 18:08:10 -0700 Subject: [PATCH 05/21] Changed state selector visibility logic. --- .../DomainRegistrationDetailsFragment.kt | 18 ++++++----- .../DomainregistrationDetailsViewModel.kt | 30 +++++++++++-------- WordPress/src/main/res/values/strings.xml | 1 + 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index bb123737333d..977f27a9d5cc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -232,12 +232,12 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O } }) - viewModel.stateInputVisible.observe(this, + viewModel.stateInputEnabled.observe(this, Observer { stateInputVisible -> if (stateInputVisible != null && stateInputVisible) { - showStateInput() + enableStateInput() } else { - hideStatesInput() + disableStateInput() } }) @@ -422,18 +422,22 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O private fun showStateProgress() { states_loading_progress_indicator.visibility = View.VISIBLE + state_input_container.isEnabled = false } private fun hideStateProgress() { states_loading_progress_indicator.visibility = View.GONE + state_input_container.isEnabled = true } - private fun showStateInput() { - state_container.visibility = View.VISIBLE + private fun enableStateInput() { + state_input_container.isEnabled = true + state_input_container.hint = getString(R.string.domain_contact_information_state_hint) } - private fun hideStatesInput() { - state_container.visibility = View.GONE + private fun disableStateInput() { + state_input_container.isEnabled = false + state_input_container.hint = getString(R.string.domain_contact_information_state_not_available_hint) } private fun showDomainRegistrationProgressDialog() { diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt index 14af911c6197..d5c4a734d8fe 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt @@ -41,9 +41,9 @@ class DomainRegistrationDetailsViewModel @Inject constructor( private var isStarted = false private var supportedCountries: List? = null - private val supportedStates = MutableLiveData>() + private val _supportedStates = MutableLiveData>() - val stateInputVisible: LiveData = Transformations.map(supportedStates) { it?.isNotEmpty() ?: false } + val stateInputEnabled: LiveData = Transformations.map(_supportedStates) { it?.isNotEmpty() ?: false } private val _selectedCountry = MutableLiveData() val selectedCountry: LiveData @@ -116,13 +116,12 @@ class DomainRegistrationDetailsViewModel @Inject constructor( } this.site = site this.domainProductDetails = domainProductDetails - if (domainContactDetails.value == null) { - fetchSupportedCountries() - } + fetchSupportedCountries() if (privacyProtectionState.value == null) { _privacyProtectionState.value = true } + isStarted = true } private fun fetchSupportedCountries() { @@ -169,7 +168,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( AppLog.e(T.DOMAIN_REGISTRATION, "An error occurred while fetching supported countries") } else { _selectedState.value = event.supportedStates?.firstOrNull { it.code == domainContactDetails.value!!.state } - supportedStates.value = event.supportedStates + _supportedStates.value = event.supportedStates } } @@ -230,7 +229,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( } fun onStateSelectorClicked() { - _showStatePickerDialog.value = supportedStates.value + _showStatePickerDialog.value = _supportedStates.value } fun onRegisterDomainButtonClicked() { @@ -248,11 +247,14 @@ class DomainRegistrationDetailsViewModel @Inject constructor( } fun onCountrySelected(country: SupportedDomainCountry) { - _selectedCountry.value = country - _selectedState.value = null - _statesProgressIndicatorVisible.value = true - _domainRegistrationButtonEnabled.value = false - dispatcher.dispatch(SiteActionBuilder.newFetchDomainSupportedStatesAction(country.code)) + if (country != _selectedCountry.value) { + _selectedCountry.value = country + _domainContactDetails.value = _domainContactDetails.value?.copy(countryCode = country.code, state = null) + _selectedState.value = null + _statesProgressIndicatorVisible.value = true + _domainRegistrationButtonEnabled.value = false + dispatcher.dispatch(SiteActionBuilder.newFetchDomainSupportedStatesAction(country.code)) + } } fun onStateSelected(state: SupportedStateResponse) { @@ -264,7 +266,9 @@ class DomainRegistrationDetailsViewModel @Inject constructor( } fun onDomainContactDetailsChanged(domainContactModel: DomainContactModel) { - _domainContactDetails.value = domainContactModel + if (formProgressIndicatorVisible.value == false) { + _domainContactDetails.value = domainContactModel + } } fun togglePrivacyProtection(isEnabled: Boolean) { diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 6bba3985fe29..adf600672eff 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -1991,6 +1991,7 @@ Address 2 City State + State (Not Available) Postal code Register Domain Congratulations From 2c01961c845226fedcdbb4dc09231dc13b692f03 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Mon, 20 May 2019 18:08:22 -0700 Subject: [PATCH 06/21] Updated tests. --- .../DomainRegistrationDetailsViewModelTest.kt | 201 +++++++----------- 1 file changed, 79 insertions(+), 122 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt index 6cfdd704d7a9..acbf0bca8acb 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -75,17 +75,13 @@ class DomainRegistrationDetailsViewModelTest { private lateinit var viewModel: DomainRegistrationDetailsViewModel - private val selectedCountry = SupportedDomainCountry("US", "United States") - private val testCountries = listOf( - selectedCountry, - SupportedDomainCountry("UK", "United Kingdom") - ) + private val primaryCountry = SupportedDomainCountry("US", "United States") + private val secondaryCountry = SupportedDomainCountry("AU", "Australia") + private val countries = listOf(primaryCountry, secondaryCountry) - private val selectedState = SupportedStateResponse("CA", "California") - private val testStates = listOf( - selectedState, - SupportedStateResponse("WA", "Washington") - ) + private val primaryState = SupportedStateResponse("CA", "California") + private val secondaryState = SupportedStateResponse("NSW", "New South Wales") + private val states = listOf(primaryState, secondaryState) private val siteId = 1234L private val productId = "76" @@ -140,110 +136,113 @@ class DomainRegistrationDetailsViewModelTest { setupFetchSupportedCountriesDispatcher(false) setupFetchDomainContactInformationDispatcher(false) setupFetchStatesDispatcher(false) - } - @Test - fun errorFetchingCountriesDuringPreload() = test { viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) + viewModel.domainContactDetails.observeForever(domainContactDetailsObserver) + viewModel.statesProgressIndicatorVisible.observeForever(stateProgressIndicatorObserver) + viewModel.domainRegistrationButtonEnabled.observeForever(domainRegistrationButtonObserver) + viewModel.selectedState.observeForever(selectedStateObserver) + viewModel.selectedCountry.observeForever(selectedCountryObserver) + viewModel.showCountryPickerDialog.observeForever(countryPickerDialogObserver) + viewModel.showStatePickerDialog.observeForever(statePickerDialogObserver) + viewModel.showTos.observeForever(tosLinkObserver) + viewModel.privacyProtectionState.observeForever(privacyProtectionObserver) + viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) + viewModel.handleCompletedDomainRegistration.observeForever(completedDomainRegistrationObserver) + viewModel.stateInputEnabled.observeForever(stateInputVisibleObserver) viewModel.showErrorMessage.observeForever(errorMessageObserver) + } - setupFetchSupportedCountriesDispatcher(true) - + @Test + fun contactDetailsPreload() = test { viewModel.start(site, domainProductDetails) // Verifying that correct actions with expected payloads were dispatched val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher, times(1)).dispatch(captor.capture()) + verify(dispatcher, times(3)).dispatch(captor.capture()) val actionsDispatched = captor.allValues validateFetchSupportedCountriesAction(actionsDispatched[0]) + validateFetchDomainContactAction(actionsDispatched[1]) + validateFetchStatesAction(actionsDispatched[2], primaryCountry.code) + // form progress indicator was shown and dismissed verify(formProgressIndicatorObserver, times(1)).onChanged(true) verify(formProgressIndicatorObserver, times(1)).onChanged(false) Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) - verify(errorMessageObserver, times(1)).onChanged(fetchSupportedCountriesError.message) + // states progress indicator was shown and dismissed + verify(stateProgressIndicatorObserver, times(1)).onChanged(true) + verify(stateProgressIndicatorObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.statesProgressIndicatorVisible.value).isEqualTo(false) + + // domain registration button was disabled and then enabled + verify(domainRegistrationButtonObserver, times(1)).onChanged(true) + verify(domainRegistrationButtonObserver, times(1)).onChanged(false) + Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) + + verify(domainContactDetailsObserver, times(1)).onChanged(domainContactModel) + + verify(selectedStateObserver, times(1)).onChanged(primaryState) + Assertions.assertThat(viewModel.selectedState.value).isEqualTo(primaryState) + + verify(selectedCountryObserver, times(1)).onChanged(primaryCountry) + Assertions.assertThat(viewModel.selectedCountry.value).isEqualTo(primaryCountry) + + verify(stateInputVisibleObserver, times(1)).onChanged(true) + Assertions.assertThat(viewModel.stateInputEnabled.value).isEqualTo(true) } @Test - fun errorFetchingDomainContactInformationDuringPreload() = test { - viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) - viewModel.showErrorMessage.observeForever(errorMessageObserver) - viewModel.domainContactDetails.observeForever(domainContactDetailsObserver) - - setupFetchSupportedCountriesDispatcher(false) - setupFetchDomainContactInformationDispatcher(true) + fun errorFetchingCountriesDuringPreload() = test { + setupFetchSupportedCountriesDispatcher(true) viewModel.start(site, domainProductDetails) // Verifying that correct actions with expected payloads were dispatched val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher, times(2)).dispatch(captor.capture()) + verify(dispatcher, times(1)).dispatch(captor.capture()) val actionsDispatched = captor.allValues validateFetchSupportedCountriesAction(actionsDispatched[0]) - validateFetchDomainContactAction(actionsDispatched[1]) - - verify(errorMessageObserver, times(1)).onChanged(domainContactInformationFetchError.message) verify(formProgressIndicatorObserver, times(1)).onChanged(true) verify(formProgressIndicatorObserver, times(1)).onChanged(false) Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) - verify(domainContactDetailsObserver, times(0)).onChanged(any()) - Assertions.assertThat(viewModel.domainContactDetails.value).isNull() + verify(errorMessageObserver, times(1)).onChanged(fetchSupportedCountriesError.message) } @Test - fun errorFetchingStatesDuringPreload() = test { - viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) - viewModel.showErrorMessage.observeForever(errorMessageObserver) - viewModel.domainRegistrationButtonEnabled.observeForever(domainRegistrationButtonObserver) - viewModel.selectedState.observeForever(selectedStateObserver) - viewModel.stateInputVisible.observeForever(stateInputVisibleObserver) - viewModel.statesProgressIndicatorVisible.observeForever(stateProgressIndicatorObserver) - + fun errorFetchingDomainContactInformationDuringPreload() = test { setupFetchSupportedCountriesDispatcher(false) - setupFetchDomainContactInformationDispatcher(false) - setupFetchStatesDispatcher(true) + setupFetchDomainContactInformationDispatcher(true) viewModel.start(site, domainProductDetails) // Verifying that correct actions with expected payloads were dispatched val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher, times(3)).dispatch(captor.capture()) + verify(dispatcher, times(2)).dispatch(captor.capture()) val actionsDispatched = captor.allValues validateFetchSupportedCountriesAction(actionsDispatched[0]) validateFetchDomainContactAction(actionsDispatched[1]) - validateFetchStatesAction(actionsDispatched[2]) - verify(errorMessageObserver, times(1)).onChanged(domainSupportedStatesFetchError.message) + verify(errorMessageObserver, times(1)).onChanged(domainContactInformationFetchError.message) verify(formProgressIndicatorObserver, times(1)).onChanged(true) verify(formProgressIndicatorObserver, times(1)).onChanged(false) Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) - verify(stateProgressIndicatorObserver, times(1)).onChanged(true) - verify(stateProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.statesProgressIndicatorVisible.value).isEqualTo(false) - - // domain registration button was disabled and then enabled - verify(domainRegistrationButtonObserver, times(1)).onChanged(true) - verify(domainRegistrationButtonObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) + verify(domainContactDetailsObserver, times(0)).onChanged(any()) + Assertions.assertThat(viewModel.domainContactDetails.value).isNull() } @Test - fun contactDetailsPreload() = test { - // Setting up all observes for all engaged LiveData - viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) - viewModel.statesProgressIndicatorVisible.observeForever(stateProgressIndicatorObserver) - viewModel.domainRegistrationButtonEnabled.observeForever(domainRegistrationButtonObserver) - viewModel.domainContactDetails.observeForever(domainContactDetailsObserver) - viewModel.selectedState.observeForever(selectedStateObserver) - viewModel.selectedCountry.observeForever(selectedCountryObserver) - viewModel.stateInputVisible.observeForever(stateInputVisibleObserver) + fun errorFetchingStatesDuringPreload() = test { + setupFetchSupportedCountriesDispatcher(false) + setupFetchDomainContactInformationDispatcher(false) + setupFetchStatesDispatcher(true) viewModel.start(site, domainProductDetails) @@ -254,14 +253,14 @@ class DomainRegistrationDetailsViewModelTest { val actionsDispatched = captor.allValues validateFetchSupportedCountriesAction(actionsDispatched[0]) validateFetchDomainContactAction(actionsDispatched[1]) - validateFetchStatesAction(actionsDispatched[2]) + validateFetchStatesAction(actionsDispatched[2], primaryCountry.code) + + verify(errorMessageObserver, times(1)).onChanged(domainSupportedStatesFetchError.message) - // form progress indicator was shown and dismissed verify(formProgressIndicatorObserver, times(1)).onChanged(true) verify(formProgressIndicatorObserver, times(1)).onChanged(false) Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) - // states progress indicator was shown and dismissed verify(stateProgressIndicatorObserver, times(1)).onChanged(true) verify(stateProgressIndicatorObserver, times(1)).onChanged(false) Assertions.assertThat(viewModel.statesProgressIndicatorVisible.value).isEqualTo(false) @@ -270,64 +269,44 @@ class DomainRegistrationDetailsViewModelTest { verify(domainRegistrationButtonObserver, times(1)).onChanged(true) verify(domainRegistrationButtonObserver, times(1)).onChanged(false) Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) - - verify(domainContactDetailsObserver, times(1)).onChanged(domainContactModel) - - verify(selectedStateObserver, times(1)).onChanged(selectedState) - Assertions.assertThat(viewModel.selectedState.value).isEqualTo(selectedState) - - verify(selectedCountryObserver, times(1)).onChanged(selectedCountry) - Assertions.assertThat(viewModel.selectedCountry.value).isEqualTo(selectedCountry) - - verify(stateInputVisibleObserver, times(1)).onChanged(true) - Assertions.assertThat(viewModel.stateInputVisible.value).isEqualTo(true) } @Test fun onCountrySelectorClicked() = test { - viewModel.showCountryPickerDialog.observeForever(countryPickerDialogObserver) - viewModel.start(site, domainProductDetails) viewModel.onCountrySelectorClicked() - verify(countryPickerDialogObserver, times(1)).onChanged(testCountries) + verify(countryPickerDialogObserver, times(1)).onChanged(countries) } @Test fun onStateSelectorClicked() = test { - viewModel.showStatePickerDialog.observeForever(statePickerDialogObserver) - viewModel.start(site, domainProductDetails) viewModel.onStateSelectorClicked() - verify(statePickerDialogObserver, times(1)).onChanged(testStates) + verify(statePickerDialogObserver, times(1)).onChanged(states) } @Test fun onCountrySelected() = test { - viewModel.selectedCountry.observeForever(selectedCountryObserver) - viewModel.selectedState.observeForever(selectedStateObserver) - viewModel.statesProgressIndicatorVisible.observeForever(stateProgressIndicatorObserver) - viewModel.domainRegistrationButtonEnabled.observeForever(domainRegistrationButtonObserver) - viewModel.stateInputVisible.observeForever(stateInputVisibleObserver) - viewModel.start(site, domainProductDetails) - viewModel.onCountrySelected(selectedCountry) + viewModel.onCountrySelected(secondaryCountry) val captor = ArgumentCaptor.forClass(Action::class.java) verify(dispatcher, times(4)).dispatch(captor.capture()) val actionsDispatched = captor.allValues - validateFetchStatesAction(actionsDispatched[3]) + validateFetchStatesAction(actionsDispatched[3], secondaryCountry.code) - verify(selectedStateObserver, times(2)).onChanged(selectedState) - Assertions.assertThat(viewModel.selectedState.value).isEqualTo(selectedState) + Assertions.assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo("AU") - Assertions.assertThat(viewModel.selectedState.value).isEqualTo(selectedState) - verify(selectedCountryObserver, times(2)).onChanged(selectedCountry) + verify(selectedStateObserver, times(2)).onChanged(null) + Assertions.assertThat(viewModel.selectedState.value).isNull() + + verify(selectedCountryObserver, times(1)).onChanged(secondaryCountry) // states progress indicator was shown and dismissed verify(stateProgressIndicatorObserver, times(2)).onChanged(true) @@ -340,19 +319,17 @@ class DomainRegistrationDetailsViewModelTest { Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) verify(stateInputVisibleObserver, times(2)).onChanged(true) - Assertions.assertThat(viewModel.stateInputVisible.value).isEqualTo(true) + Assertions.assertThat(viewModel.stateInputEnabled.value).isEqualTo(true) } @Test fun onStateSelected() = test { - viewModel.selectedState.observeForever(selectedStateObserver) - viewModel.start(site, domainProductDetails) - viewModel.onStateSelected(selectedState) + viewModel.onStateSelected(primaryState) - verify(selectedStateObserver, times(2)).onChanged(selectedState) - Assertions.assertThat(viewModel.selectedState.value).isEqualTo(selectedState) + verify(selectedStateObserver, times(2)).onChanged(primaryState) + Assertions.assertThat(viewModel.selectedState.value).isEqualTo(primaryState) } @Test @@ -361,9 +338,6 @@ class DomainRegistrationDetailsViewModelTest { setupRedeemShoppingCartDispatcher(false) setupFetchSiteDispatcher(false) - viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) - viewModel.handleCompletedDomainRegistration.observeForever(completedDomainRegistrationObserver) - viewModel.start(site, domainProductDetails) viewModel.onRegisterDomainButtonClicked() @@ -388,9 +362,6 @@ class DomainRegistrationDetailsViewModelTest { fun onErrorCreatingCart() = test { setupCreateShoppingCartDispatcher(true) - viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) - viewModel.showErrorMessage.observeForever(errorMessageObserver) - viewModel.start(site, domainProductDetails) viewModel.onRegisterDomainButtonClicked() @@ -413,9 +384,6 @@ class DomainRegistrationDetailsViewModelTest { setupCreateShoppingCartDispatcher(false) setupRedeemShoppingCartDispatcher(true) - viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) - viewModel.showErrorMessage.observeForever(errorMessageObserver) - viewModel.start(site, domainProductDetails) viewModel.onRegisterDomainButtonClicked() @@ -440,10 +408,6 @@ class DomainRegistrationDetailsViewModelTest { setupRedeemShoppingCartDispatcher(false) setupFetchSiteDispatcher(true) - viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) - viewModel.showErrorMessage.observeForever(errorMessageObserver) - viewModel.handleCompletedDomainRegistration.observeForever(completedDomainRegistrationObserver) - viewModel.start(site, domainProductDetails) viewModel.onRegisterDomainButtonClicked() @@ -468,8 +432,6 @@ class DomainRegistrationDetailsViewModelTest { @Test fun onTosLinkClicked() = test { - viewModel.showTos.observeForever(tosLinkObserver) - viewModel.start(site, domainProductDetails) viewModel.onTosLinkClicked() @@ -479,12 +441,9 @@ class DomainRegistrationDetailsViewModelTest { @Test fun onDomainContactDetailsChanged() = test { - viewModel.domainContactDetails.observeForever(domainContactDetailsObserver) - viewModel.start(site, domainProductDetails) val updatedDomainContactDetails = domainContactModel.copy(firstName = "Peter") - viewModel.onDomainContactDetailsChanged(updatedDomainContactDetails) verify(domainContactDetailsObserver, times(1)).onChanged(updatedDomainContactDetails) @@ -493,8 +452,6 @@ class DomainRegistrationDetailsViewModelTest { @Test fun togglePrivacyProtection() = test { - viewModel.privacyProtectionState.observeForever(privacyProtectionObserver) - viewModel.start(site, domainProductDetails) Assertions.assertThat(viewModel.privacyProtectionState.value).isTrue() @@ -510,7 +467,7 @@ class DomainRegistrationDetailsViewModelTest { val event = if (isError) { OnSupportedCountriesFetched(fetchSupportedCountriesError) } else { - OnSupportedCountriesFetched(testCountries) + OnSupportedCountriesFetched(countries) } whenever(dispatcher.dispatch(argWhere> { it.type == FETCH_SUPPORTED_COUNTRIES })).then { viewModel.onSupportedCountriesFetched(event) @@ -521,7 +478,7 @@ class DomainRegistrationDetailsViewModelTest { val event = if (isError) { OnDomainSupportedStatesFetched(null, domainSupportedStatesFetchError) } else { - OnDomainSupportedStatesFetched(testStates, null) + OnDomainSupportedStatesFetched(states, null) } whenever(dispatcher.dispatch(argWhere> { it.type == SiteAction.FETCH_DOMAIN_SUPPORTED_STATES })).then { viewModel.onDomainSupportedStatesFetched(event) @@ -581,9 +538,9 @@ class DomainRegistrationDetailsViewModelTest { Assertions.assertThat(action.payload).isNull() } - private fun validateFetchStatesAction(action: Action<*>) { + private fun validateFetchStatesAction(action: Action<*>, targetCountryCode: String) { Assertions.assertThat(action.type).isEqualTo(SiteAction.FETCH_DOMAIN_SUPPORTED_STATES) - Assertions.assertThat(action.payload).isEqualTo("US") + Assertions.assertThat(action.payload).isEqualTo(targetCountryCode) } private fun validateCreateCartAction(action: Action<*>) { From ee8aa7f7615da86a1d203c9e0efadf6fb1e026e3 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Mon, 20 May 2019 20:12:13 -0700 Subject: [PATCH 07/21] Added test for same country selected. --- .../DomainRegistrationDetailsViewModelTest.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt index acbf0bca8acb..09f1b734e8eb 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -322,6 +322,26 @@ class DomainRegistrationDetailsViewModelTest { Assertions.assertThat(viewModel.stateInputEnabled.value).isEqualTo(true) } + @Test + fun onSameCountrySelected() = test { + viewModel.start(site, domainProductDetails) + + Assertions.assertThat(viewModel.selectedCountry.value).isEqualTo(primaryCountry) + viewModel.onCountrySelected(primaryCountry) + + val captor = ArgumentCaptor.forClass(Action::class.java) + verify(dispatcher, times(3)).dispatch(captor.capture()) + + Assertions.assertThat(viewModel.selectedCountry.value).isEqualTo(primaryCountry) + + verify(selectedStateObserver, times(1)).onChanged(primaryState) + Assertions.assertThat(viewModel.selectedState.value).isEqualTo(primaryState) + + verify(selectedCountryObserver, times(1)).onChanged(primaryCountry) + + verify(stateInputVisibleObserver, times(1)).onChanged(true) + } + @Test fun onStateSelected() = test { viewModel.start(site, domainProductDetails) From d02cf8d7edf77794cef83cda55c0aed691a96ab6 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 21 May 2019 00:15:05 -0700 Subject: [PATCH 08/21] Fixed wrong field for country code validation. Added more tests. --- .../DomainRegistrationDetailsFragment.kt | 2 +- .../DomainregistrationDetailsViewModel.kt | 4 ++++ .../DomainRegistrationDetailsViewModelTest.kt | 17 +++++++---------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index 977f27a9d5cc..69368ac9debb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -280,7 +280,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O POSTAL_CODE -> affectedInputFields = arrayOf(postal_code_input) CITY -> affectedInputFields = arrayOf(city_input) STATE -> affectedInputFields = arrayOf(state_input) - COUNTRY_CODE -> affectedInputFields = arrayOf(country_code_input) + COUNTRY_CODE -> affectedInputFields = arrayOf(country_input) EMAIL -> affectedInputFields = arrayOf(email_input) PHONE -> affectedInputFields = arrayOf(country_code_input, phone_number_input) else -> { diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt index d5c4a734d8fe..8f9ada0f0660 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt @@ -234,6 +234,10 @@ class DomainRegistrationDetailsViewModel @Inject constructor( fun onRegisterDomainButtonClicked() { _registrationProgressIndicatorVisible.value = true + _domainContactDetails.value = _domainContactDetails.value?.copy( + countryCode = selectedCountry.value?.code, + state = selectedState.value?.code + ) dispatcher.dispatch( TransactionActionBuilder.newCreateShoppingCartAction( CreateShoppingCartPayload( diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt index 09f1b734e8eb..f1efba34a743 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -136,6 +136,9 @@ class DomainRegistrationDetailsViewModelTest { setupFetchSupportedCountriesDispatcher(false) setupFetchDomainContactInformationDispatcher(false) setupFetchStatesDispatcher(false) + setupCreateShoppingCartDispatcher(false) + setupRedeemShoppingCartDispatcher(false) + setupFetchSiteDispatcher(false) viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) viewModel.domainContactDetails.observeForever(domainContactDetailsObserver) @@ -215,7 +218,6 @@ class DomainRegistrationDetailsViewModelTest { @Test fun errorFetchingDomainContactInformationDuringPreload() = test { - setupFetchSupportedCountriesDispatcher(false) setupFetchDomainContactInformationDispatcher(true) viewModel.start(site, domainProductDetails) @@ -240,8 +242,6 @@ class DomainRegistrationDetailsViewModelTest { @Test fun errorFetchingStatesDuringPreload() = test { - setupFetchSupportedCountriesDispatcher(false) - setupFetchDomainContactInformationDispatcher(false) setupFetchStatesDispatcher(true) viewModel.start(site, domainProductDetails) @@ -302,6 +302,7 @@ class DomainRegistrationDetailsViewModelTest { validateFetchStatesAction(actionsDispatched[3], secondaryCountry.code) Assertions.assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo("AU") + Assertions.assertThat(viewModel.domainContactDetails.value?.state).isNull() verify(selectedStateObserver, times(2)).onChanged(null) Assertions.assertThat(viewModel.selectedState.value).isNull() @@ -354,14 +355,13 @@ class DomainRegistrationDetailsViewModelTest { @Test fun onRegisterDomainButtonClicked() = test { - setupCreateShoppingCartDispatcher(false) - setupRedeemShoppingCartDispatcher(false) - setupFetchSiteDispatcher(false) - viewModel.start(site, domainProductDetails) viewModel.onRegisterDomainButtonClicked() + Assertions.assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo(primaryCountry.code) + Assertions.assertThat(viewModel.domainContactDetails.value?.state).isEqualTo(primaryState.code) + val captor = ArgumentCaptor.forClass(Action::class.java) verify(dispatcher, times(6)).dispatch(captor.capture()) @@ -401,7 +401,6 @@ class DomainRegistrationDetailsViewModelTest { @Test fun onErrorRedeemingCart() = test { - setupCreateShoppingCartDispatcher(false) setupRedeemShoppingCartDispatcher(true) viewModel.start(site, domainProductDetails) @@ -424,8 +423,6 @@ class DomainRegistrationDetailsViewModelTest { @Test fun onErrorFetchingSite() = test { - setupCreateShoppingCartDispatcher(false) - setupRedeemShoppingCartDispatcher(false) setupFetchSiteDispatcher(true) viewModel.start(site, domainProductDetails) From f9badc1536d433f646a1709c3d1674a79543c013 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 21 May 2019 00:51:38 -0700 Subject: [PATCH 09/21] ktlint fixes, added more comments --- .../DomainRegistrationDetailsFragment.kt | 17 +++++++++++------ ...kt => DomainRegistrationDetailsViewModel.kt} | 17 +++++++++-------- .../DomainRegistrationDetailsViewModelTest.kt | 12 +++++++++--- 3 files changed, 29 insertions(+), 17 deletions(-) rename WordPress/src/main/java/org/wordpress/android/viewmodel/domains/{DomainregistrationDetailsViewModel.kt => DomainRegistrationDetailsViewModel.kt} (95%) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index 69368ac9debb..d096ebffef51 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -142,8 +142,8 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O } } + // make link to ToS clickable private fun setupTosLink() { - // make link to ToS clickable val spannableTosString = SpannableString(tos_explanation.text) val tosUnderlineSpan = spannableTosString.getSpans( 0, @@ -228,6 +228,8 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O viewModel.domainContactDetails.observe(this, object : Observer { override fun onChanged(domainContactModel: DomainContactModel?) { populateContactForm(domainContactModel!!) + // we need to remove observer to avoid loop when data is sent back to ViewModel + // after initial load we let EditText maintain it's content viewModel.domainContactDetails.removeObserver(this) } }) @@ -271,7 +273,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O Observer { error -> var affectedInputFields: Array? = null - when (error!!.type) { + when (error?.type) { FIRST_NAME -> affectedInputFields = arrayOf(first_name_input) LAST_NAME -> affectedInputFields = arrayOf(last_name_input) ORGANIZATION -> affectedInputFields = arrayOf(organization_input) @@ -289,7 +291,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O affectedInputFields?.forEach { showFieldError( it, - StringEscapeUtils.unescapeHtml4(error.message) + StringEscapeUtils.unescapeHtml4(error?.message) ) } affectedInputFields?.firstOrNull { it.requestFocus() } @@ -338,6 +340,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O postal_code_input.setText(domainContactInformation.postalCode) } + // local validation private fun validateForm(): Boolean { var formIsCompleted = true @@ -384,7 +387,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O address_second_line_input.text.toString(), postal_code_input.text.toString(), city_input.text.toString(), - null, // state code will be added in ViewModel + null, // state code will be added in ViewModel null, // country code will be added in ViewModel email_input.text.toString(), combinedPhoneNumber, @@ -478,7 +481,8 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - states = arguments!!.getParcelableArrayList(EXTRA_STATES) as ArrayList + states = arguments!!.getParcelableArrayList(EXTRA_STATES) + as ArrayList } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -516,7 +520,8 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - countries = arguments!!.getParcelableArrayList(EXTRA_COUNTRIES) as ArrayList + countries = arguments?.getParcelableArrayList(EXTRA_COUNTRIES) + as ArrayList } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt similarity index 95% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt index 8f9ada0f0660..0b91212e4603 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainregistrationDetailsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt @@ -34,10 +34,11 @@ import javax.inject.Inject class DomainRegistrationDetailsViewModel @Inject constructor( private val dispatcher: Dispatcher, - private val transactionsStore: TransactionsStore + private val transactionsStore: TransactionsStore // needed for events to work ) : ViewModel() { private lateinit var site: SiteModel private lateinit var domainProductDetails: DomainProductDetails + private var isStarted = false private var supportedCountries: List? = null @@ -117,10 +118,8 @@ class DomainRegistrationDetailsViewModel @Inject constructor( this.site = site this.domainProductDetails = domainProductDetails fetchSupportedCountries() + _privacyProtectionState.value = true - if (privacyProtectionState.value == null) { - _privacyProtectionState.value = true - } isStarted = true } @@ -150,11 +149,13 @@ class DomainRegistrationDetailsViewModel @Inject constructor( } else { _domainContactDetails.value = event.contactModel - if (event.contactModel != null && !TextUtils.isEmpty(event.contactModel!!.countryCode)) { - _selectedCountry.value = supportedCountries!!.firstOrNull { it.code == event.contactModel!!.countryCode } + if (event.contactModel != null && !TextUtils.isEmpty(event.contactModel?.countryCode)) { + _selectedCountry.value = supportedCountries?.firstOrNull { it.code == event.contactModel?.countryCode } _statesProgressIndicatorVisible.value = true _domainRegistrationButtonEnabled.value = false - dispatcher.dispatch(SiteActionBuilder.newFetchDomainSupportedStatesAction(event.contactModel!!.countryCode)) + dispatcher.dispatch( + SiteActionBuilder.newFetchDomainSupportedStatesAction(event.contactModel?.countryCode) + ) } } } @@ -167,7 +168,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( _showErrorMessage.value = event.error.message AppLog.e(T.DOMAIN_REGISTRATION, "An error occurred while fetching supported countries") } else { - _selectedState.value = event.supportedStates?.firstOrNull { it.code == domainContactDetails.value!!.state } + _selectedState.value = event.supportedStates?.firstOrNull { it.code == domainContactDetails.value?.state } _supportedStates.value = event.supportedStates } } diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt index f1efba34a743..8cd53e84f3e3 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -497,7 +497,9 @@ class DomainRegistrationDetailsViewModelTest { } else { OnDomainSupportedStatesFetched(states, null) } - whenever(dispatcher.dispatch(argWhere> { it.type == SiteAction.FETCH_DOMAIN_SUPPORTED_STATES })).then { + whenever(dispatcher.dispatch(argWhere> { + it.type == SiteAction.FETCH_DOMAIN_SUPPORTED_STATES + })).then { viewModel.onDomainSupportedStatesFetched(event) } } @@ -519,7 +521,9 @@ class DomainRegistrationDetailsViewModelTest { } else { OnShoppingCartCreated(createShoppingCartResponse) } - whenever(dispatcher.dispatch(argWhere> { it.type == TransactionAction.CREATE_SHOPPING_CART })).then { + whenever(dispatcher.dispatch(argWhere> { + it.type == TransactionAction.CREATE_SHOPPING_CART + })).then { viewModel.onShoppingCartCreated(event) } } @@ -530,7 +534,9 @@ class DomainRegistrationDetailsViewModelTest { } else { OnShoppingCartRedeemed(true) } - whenever(dispatcher.dispatch(argWhere> { it.type == TransactionAction.REDEEM_CART_WITH_CREDITS })).then { + whenever(dispatcher.dispatch(argWhere> { + it.type == TransactionAction.REDEEM_CART_WITH_CREDITS + })).then { viewModel.onCartRedeemed(event) } } From 0b9ae72392bd43c4067fa308c8ea96aa00a9197e Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 21 May 2019 01:00:06 -0700 Subject: [PATCH 10/21] Fixed wrong state picked dialog title. --- .../android/ui/domains/DomainRegistrationDetailsFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index d096ebffef51..6d68b5cc5e9c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -487,7 +487,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(R.string.domain_registration_country_picker_dialog_title) + builder.setTitle(R.string.domain_registration_state_picker_dialog_title) builder.setItems(states.map { it.name }.toTypedArray()) { _, which -> if (targetFragment != null && targetFragment is OnStateSelectedListener) { (targetFragment as OnStateSelectedListener).onStateSelected(states[which]) From 5d91dae90480d0414995ed18c51ff2a6bfed336f Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 29 May 2019 16:55:04 -0700 Subject: [PATCH 11/21] Moved site and domainProductDetails to onViewCreated --- .../DomainRegistrationDetailsFragment.kt | 17 +++++++---------- .../DomainRegistrationDetailsViewModel.kt | 6 +++--- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index 6d68b5cc5e9c..bd6b22344462 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -68,19 +68,12 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O @Inject lateinit var viewModelFactory: ViewModelProvider.Factory private lateinit var viewModel: DomainRegistrationDetailsViewModel - private var site: SiteModel? = null - private var domainProductDetails: DomainProductDetails? = null - private var loadingProgressDialog: ProgressDialog? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val nonNullActivity = checkNotNull(activity) (nonNullActivity.application as WordPress).component()?.inject(this) - - site = nonNullActivity.intent?.getSerializableExtra(WordPress.SITE) as SiteModel - - domainProductDetails = arguments?.getParcelable(EXTRA_DOMAIN_PRODUCT_DETAILS) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -92,7 +85,11 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O viewModel = ViewModelProviders.of(this, viewModelFactory).get(DomainRegistrationDetailsViewModel::class.java) setupObservers() - viewModel.start(site!!, domainProductDetails!!) + + val domainProductDetails = arguments?.getParcelable(EXTRA_DOMAIN_PRODUCT_DETAILS) as DomainProductDetails + val site = activity!!.intent?.getSerializableExtra(WordPress.SITE) as SiteModel + + viewModel.start(site, domainProductDetails) // Country and State input could only be populated from the dialog country_input.inputType = 0 @@ -303,8 +300,8 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O }) viewModel.handleCompletedDomainRegistration.observe(this, - Observer { - (activity as DomainRegistrationActivity).onDomainRegistered(domainProductDetails!!.domainName) + Observer { domainName -> + (activity as DomainRegistrationActivity).onDomainRegistered(StringUtils.notNullStr(domainName)) }) viewModel.showTos.observe(this, diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt index 0b91212e4603..2d287c5ac513 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt @@ -94,8 +94,8 @@ class DomainRegistrationDetailsViewModel @Inject constructor( val domainContactDetails: LiveData get() = _domainContactDetails - private val _handleCompletedDomainRegistration = SingleLiveEvent() - val handleCompletedDomainRegistration: LiveData + private val _handleCompletedDomainRegistration = SingleLiveEvent() + val handleCompletedDomainRegistration: LiveData get() = _handleCompletedDomainRegistration private val _showTos = SingleLiveEvent() @@ -222,7 +222,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( _showErrorMessage.value = event.error.message } - _handleCompletedDomainRegistration.call() + _handleCompletedDomainRegistration.postValue(domainProductDetails.domainName) } fun onCountrySelectorClicked() { From 262d8c5013293766d952b7e8e08e7ee3a9ca67ff Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 29 May 2019 21:03:53 -0700 Subject: [PATCH 12/21] Removed generic type. --- .../android/ui/domains/DomainRegistrationDetailsFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index bd6b22344462..ad72f6e96de6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -203,7 +203,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O }) viewModel.domainRegistrationButtonEnabled.observe(this, - Observer { isEnabled -> + Observer { isEnabled -> register_domain_button.isEnabled = isEnabled == true }) From 2f25ffe9f1524b7d6d6e5876ca6f8d45bfb3ea85 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 29 May 2019 21:27:19 -0700 Subject: [PATCH 13/21] Updated way privacy protection radio button is handled. --- .../DomainRegistrationDetailsFragment.kt | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index ad72f6e96de6..0778240dc254 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -91,6 +91,14 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O viewModel.start(site, domainProductDetails) + domain_privacy_on_radio_button.setOnClickListener { + viewModel.togglePrivacyProtection(true) + } + + domain_privacy_off_radio_button.setOnClickListener { + viewModel.togglePrivacyProtection(false) + } + // Country and State input could only be populated from the dialog country_input.inputType = 0 country_input.setOnClickListener { @@ -207,18 +215,11 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O register_domain_button.isEnabled = isEnabled == true }) - viewModel.privacyProtectionState.observe(this, object : Observer { - override fun onChanged(privacyEnabled: Boolean?) { - if (privacyEnabled != null && privacyEnabled) { - domain_privacy_options_radiogroup.check(R.id.domain_privacy_on_radio_button) - } else { - domain_privacy_options_radiogroup.check(R.id.domain_privacy_off_radio_button) - } - - domain_privacy_options_radiogroup.setOnCheckedChangeListener { _, _ -> - viewModel.togglePrivacyProtection(domain_privacy_on_radio_button.isChecked) - } - viewModel.privacyProtectionState.removeObserver(this) + viewModel.privacyProtectionState.observe(this, Observer { privacyEnabled -> + if (privacyEnabled == true) { + domain_privacy_options_radiogroup.check(R.id.domain_privacy_on_radio_button) + } else { + domain_privacy_options_radiogroup.check(R.id.domain_privacy_off_radio_button) } }) From fc78ddbcdc9033aec79d177f6990caca07ffdff5 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 29 May 2019 23:53:05 -0700 Subject: [PATCH 14/21] Updated tests. --- .../DomainRegistrationDetailsViewModelTest.kt | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt index 8cd53e84f3e3..242239eafc50 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -1,6 +1,5 @@ package org.wordpress.android.viewmodel.domains -import android.arch.core.executor.testing.InstantTaskExecutorRule import android.arch.lifecycle.Observer import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.argWhere @@ -9,12 +8,10 @@ import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions import org.junit.Before -import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mock -import org.mockito.junit.MockitoJUnitRunner +import org.wordpress.android.BaseUnitTest import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.action.AccountAction import org.wordpress.android.fluxc.action.SiteAction @@ -51,9 +48,7 @@ import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType. import org.wordpress.android.test import org.wordpress.android.ui.domains.DomainProductDetails -@RunWith(MockitoJUnitRunner::class) -class DomainRegistrationDetailsViewModelTest { - @Rule @JvmField val rule = InstantTaskExecutorRule() +class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { @Mock private lateinit var store: TransactionsStore @Mock private lateinit var dispatcher: Dispatcher @Mock private lateinit var site: SiteModel @@ -69,7 +64,7 @@ class DomainRegistrationDetailsViewModelTest { @Mock private lateinit var tosLinkObserver: Observer @Mock private lateinit var privacyProtectionObserver: Observer @Mock private lateinit var domainRegistrationProgressIndicatorObserver: Observer - @Mock private lateinit var completedDomainRegistrationObserver: Observer + @Mock private lateinit var completedDomainRegistrationObserver: Observer @Mock private lateinit var stateInputVisibleObserver: Observer @Mock private lateinit var errorMessageObserver: Observer @@ -375,7 +370,7 @@ class DomainRegistrationDetailsViewModelTest { verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(false) Assertions.assertThat(viewModel.registrationProgressIndicatorVisible.value).isEqualTo(false) - verify(completedDomainRegistrationObserver, times(1)).onChanged(null) + verify(completedDomainRegistrationObserver, times(1)).onChanged(domainProductDetails.domainName) } @Test @@ -444,7 +439,7 @@ class DomainRegistrationDetailsViewModelTest { verify(errorMessageObserver, times(1)).onChanged(siteChangedError.message) - verify(completedDomainRegistrationObserver, times(1)).onChanged(null) + verify(completedDomainRegistrationObserver, times(1)).onChanged(domainProductDetails.domainName) } @Test From c6f503b61f5ca7861e693a61e91ed90fc230c93e Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Thu, 30 May 2019 00:03:38 -0700 Subject: [PATCH 15/21] Removed more types from observers. --- .../ui/domains/DomainRegistrationDetailsFragment.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index 0778240dc254..ffdc14a2d07e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -184,7 +184,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O private fun setupObservers() { viewModel.formProgressIndicatorVisible.observe(this, - Observer { isVisible -> + Observer { isVisible -> if (isVisible == true) { showFormProgressIndicator() } else { @@ -193,7 +193,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O }) viewModel.statesProgressIndicatorVisible.observe(this, - Observer { isVisible -> + Observer { isVisible -> if (isVisible == true) { showStateProgress() } else { @@ -202,7 +202,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O }) viewModel.registrationProgressIndicatorVisible.observe(this, - Observer { isVisible -> + Observer { isVisible -> if (isVisible == true) { showDomainRegistrationProgressDialog() } else { @@ -233,7 +233,7 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O }) viewModel.stateInputEnabled.observe(this, - Observer { stateInputVisible -> + Observer { stateInputVisible -> if (stateInputVisible != null && stateInputVisible) { enableStateInput() } else { From b3c40057e16b878d21f8db726bb1cc4f4f174def Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 4 Jun 2019 13:27:56 -0700 Subject: [PATCH 16/21] Checking if the viewmodel data matched form data instead of removing observer. --- .../ui/domains/DomainRegistrationDetailsFragment.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index ffdc14a2d07e..2e47f39817dc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -223,12 +223,10 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O } }) - viewModel.domainContactDetails.observe(this, object : Observer { - override fun onChanged(domainContactModel: DomainContactModel?) { + viewModel.domainContactDetails.observe(this, Observer { domainContactModel -> + val currentModel = contactFormToDomainContactModel() + if (currentModel != domainContactModel) { populateContactForm(domainContactModel!!) - // we need to remove observer to avoid loop when data is sent back to ViewModel - // after initial load we let EditText maintain it's content - viewModel.domainContactDetails.removeObserver(this) } }) From 3be7431ae956e1f58bacd93ea12525942760a890 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 4 Jun 2019 14:12:02 -0700 Subject: [PATCH 17/21] Calling ViewModel directly from dialog fragments instead of using listeners. --- .../android/modules/ApplicationModule.java | 8 ++++ .../DomainRegistrationDetailsFragment.kt | 41 +++++++++++-------- .../ui/domains/OnCountrySelectedListener.kt | 7 ---- .../ui/domains/OnStateSelectedListener.kt | 7 ---- 4 files changed, 33 insertions(+), 30 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/domains/OnCountrySelectedListener.kt delete mode 100644 WordPress/src/main/java/org/wordpress/android/ui/domains/OnStateSelectedListener.kt diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java index c1c4b510c2bd..c767b6166ca6 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java @@ -4,6 +4,8 @@ import android.arch.lifecycle.LiveData; import android.content.Context; +import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.CountryPickerDialogFragment; +import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.StatePickerDialogFragment; import org.wordpress.android.ui.news.LocalNewsService; import org.wordpress.android.ui.news.NewsService; import org.wordpress.android.ui.sitecreation.NewSiteCreationStepsProvider; @@ -48,6 +50,12 @@ public static NewsService provideLocalNewsService(Context context) { @ContributesAndroidInjector abstract StatsDetailFragment contributeStatsDetailFragment(); + @ContributesAndroidInjector + abstract CountryPickerDialogFragment contributeCountryPickerDialogFragment(); + + @ContributesAndroidInjector + abstract StatePickerDialogFragment contributeCStatePickerDialogFragment(); + @Provides public static WizardManager provideWizardManager(NewSiteCreationStepsProvider stepsProvider) { return new WizardManager<>(stepsProvider.getSteps()); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index 2e47f39817dc..32876e5a8004 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -5,6 +5,7 @@ import android.app.ProgressDialog import android.arch.lifecycle.Observer import android.arch.lifecycle.ViewModelProvider import android.arch.lifecycle.ViewModelProviders +import android.content.Context import android.os.Bundle import android.support.design.widget.TextInputEditText import android.support.design.widget.TextInputLayout @@ -22,6 +23,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.EditText +import dagger.android.support.AndroidSupportInjection import kotlinx.android.synthetic.main.domain_registration_details_fragment.* import org.apache.commons.lang3.StringEscapeUtils import org.wordpress.android.R @@ -48,7 +50,7 @@ import org.wordpress.android.util.WPUrlUtils import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel import javax.inject.Inject -class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, OnCountrySelectedListener { +class DomainRegistrationDetailsFragment : Fragment() { companion object { private const val PHONE_NUMBER_PREFIX = "+" private const val PHONE_NUMBER_CONNECTING_CHARACTER = "." @@ -83,7 +85,8 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel = ViewModelProviders.of(this, viewModelFactory).get(DomainRegistrationDetailsViewModel::class.java) + viewModel = ViewModelProviders.of(activity!!, viewModelFactory) + .get(DomainRegistrationDetailsViewModel::class.java) setupObservers() val domainProductDetails = arguments?.getParcelable(EXTRA_DOMAIN_PRODUCT_DETAILS) as DomainProductDetails @@ -403,14 +406,6 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O dialogFragment.show(fragmentManager, CountryPickerDialogFragment.TAG) } - override fun OnCountrySelected(country: SupportedDomainCountry) { - viewModel.onCountrySelected(country) - } - - override fun onStateSelected(state: SupportedStateResponse) { - viewModel.onStateSelected(state) - } - private fun showFormProgressIndicator() { form_progress_indicator.visibility = View.VISIBLE } @@ -461,6 +456,8 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O class StatePickerDialogFragment : DialogFragment() { private lateinit var states: ArrayList + @Inject lateinit var viewModelFactory: ViewModelProvider.Factory + private lateinit var viewModel: DomainRegistrationDetailsViewModel companion object { private const val EXTRA_STATES = "EXTRA_STATES" @@ -482,12 +479,12 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + viewModel = ViewModelProviders.of(activity!!, viewModelFactory) + .get(DomainRegistrationDetailsViewModel::class.java) val builder = AlertDialog.Builder(requireContext()) builder.setTitle(R.string.domain_registration_state_picker_dialog_title) builder.setItems(states.map { it.name }.toTypedArray()) { _, which -> - if (targetFragment != null && targetFragment is OnStateSelectedListener) { - (targetFragment as OnStateSelectedListener).onStateSelected(states[which]) - } + viewModel.onStateSelected(states[which]) } builder.setPositiveButton(R.string.dialog_button_cancel) { dialog, _ -> @@ -496,10 +493,17 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O return builder.create() } + + override fun onAttach(context: Context?) { + super.onAttach(context) + AndroidSupportInjection.inject(this) + } } class CountryPickerDialogFragment : DialogFragment() { private lateinit var countries: ArrayList + @Inject lateinit var viewModelFactory: ViewModelProvider.Factory + private lateinit var viewModel: DomainRegistrationDetailsViewModel companion object { private const val EXTRA_COUNTRIES = "EXTRA_COUNTRIES" @@ -521,12 +525,12 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + viewModel = ViewModelProviders.of(activity!!, viewModelFactory) + .get(DomainRegistrationDetailsViewModel::class.java) val builder = AlertDialog.Builder(requireContext()) builder.setTitle(R.string.domain_registration_country_picker_dialog_title) builder.setItems(countries.map { it.name }.toTypedArray()) { _, which -> - if (targetFragment != null && targetFragment is OnStateSelectedListener) { - (targetFragment as OnCountrySelectedListener).OnCountrySelected(countries[which]) - } + viewModel.onCountrySelected(countries[which]) } builder.setPositiveButton(R.string.dialog_button_cancel) { dialog, _ -> @@ -535,5 +539,10 @@ class DomainRegistrationDetailsFragment : Fragment(), OnStateSelectedListener, O return builder.create() } + + override fun onAttach(context: Context?) { + super.onAttach(context) + AndroidSupportInjection.inject(this) + } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/OnCountrySelectedListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/OnCountrySelectedListener.kt deleted file mode 100644 index 3681d0aeb6de..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/OnCountrySelectedListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.wordpress.android.ui.domains - -import org.wordpress.android.fluxc.network.rest.wpcom.transactions.SupportedDomainCountry - -interface OnCountrySelectedListener { - fun OnCountrySelected(country: SupportedDomainCountry) -} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/OnStateSelectedListener.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/OnStateSelectedListener.kt deleted file mode 100644 index a3ded426f6f8..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/OnStateSelectedListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.wordpress.android.ui.domains - -import org.wordpress.android.fluxc.network.rest.wpcom.site.SupportedStateResponse - -interface OnStateSelectedListener { - fun onStateSelected(state: SupportedStateResponse) -} From e6e8d9271d6df52708c28675cb796c41279439f0 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 4 Jun 2019 21:04:52 -0700 Subject: [PATCH 18/21] Switched to using UI state. --- .../DomainRegistrationDetailsFragment.kt | 96 ++++++--------- .../DomainRegistrationDetailsViewModel.kt | 115 +++++++++--------- 2 files changed, 98 insertions(+), 113 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index 32876e5a8004..b097bc894d88 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -186,46 +186,47 @@ class DomainRegistrationDetailsFragment : Fragment() { } private fun setupObservers() { - viewModel.formProgressIndicatorVisible.observe(this, - Observer { isVisible -> - if (isVisible == true) { - showFormProgressIndicator() - } else { - hideFormProgressIndicator() + viewModel.uiState.observe(this, + Observer { uiState -> + uiState?.let { + if (uiState.isFormProgressIndicatorVisible) { + showFormProgressIndicator() + } else { + hideFormProgressIndicator() + } + + if (uiState.isStateProgressIndicatorVisible) { + showStateProgress() + } else { + hideStateProgress() + } + + if (uiState.isRegistrationProgressIndicatorVisible) { + showDomainRegistrationProgressDialog() + } else { + hideDomainRegistrationProgressDialog() + } + + if (uiState.isPrivacyProtectionEnabled) { + domain_privacy_options_radiogroup.check(R.id.domain_privacy_on_radio_button) + } else { + domain_privacy_options_radiogroup.check(R.id.domain_privacy_off_radio_button) + } + + if (uiState.isStateInputEnabled) { + enableStateInput() + } else { + disableStateInput() + } + + register_domain_button.isEnabled = uiState.isDomainRegistrationButtonEnabled + + // Country and State fields treated as UI state, since we only use them for display purpose + country_input.setText(uiState.selectedCountry?.name) + state_input.setText(uiState.selectedState?.name) } }) - viewModel.statesProgressIndicatorVisible.observe(this, - Observer { isVisible -> - if (isVisible == true) { - showStateProgress() - } else { - hideStateProgress() - } - }) - - viewModel.registrationProgressIndicatorVisible.observe(this, - Observer { isVisible -> - if (isVisible == true) { - showDomainRegistrationProgressDialog() - } else { - hideDomainRegistrationProgressDialog() - } - }) - - viewModel.domainRegistrationButtonEnabled.observe(this, - Observer { isEnabled -> - register_domain_button.isEnabled = isEnabled == true - }) - - viewModel.privacyProtectionState.observe(this, Observer { privacyEnabled -> - if (privacyEnabled == true) { - domain_privacy_options_radiogroup.check(R.id.domain_privacy_on_radio_button) - } else { - domain_privacy_options_radiogroup.check(R.id.domain_privacy_off_radio_button) - } - }) - viewModel.domainContactDetails.observe(this, Observer { domainContactModel -> val currentModel = contactFormToDomainContactModel() if (currentModel != domainContactModel) { @@ -233,27 +234,6 @@ class DomainRegistrationDetailsFragment : Fragment() { } }) - viewModel.stateInputEnabled.observe(this, - Observer { stateInputVisible -> - if (stateInputVisible != null && stateInputVisible) { - enableStateInput() - } else { - disableStateInput() - } - }) - - viewModel.selectedCountry.observe(this, - Observer { country -> - if (country != null) { - country_input.setText(country.name) - } - }) - - viewModel.selectedState.observe(this, - Observer { state -> - state_input.setText(state?.name) - }) - viewModel.showCountryPickerDialog.observe(this, Observer { if (it != null && it.isNotEmpty()) { diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt index 2d287c5ac513..e3e3deda1085 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModel.kt @@ -2,7 +2,6 @@ package org.wordpress.android.viewmodel.domains import android.arch.lifecycle.LiveData import android.arch.lifecycle.MutableLiveData -import android.arch.lifecycle.Transformations import android.arch.lifecycle.ViewModel import android.text.TextUtils import org.greenrobot.eventbus.Subscribe @@ -44,15 +43,9 @@ class DomainRegistrationDetailsViewModel @Inject constructor( private var supportedCountries: List? = null private val _supportedStates = MutableLiveData>() - val stateInputEnabled: LiveData = Transformations.map(_supportedStates) { it?.isNotEmpty() ?: false } - - private val _selectedCountry = MutableLiveData() - val selectedCountry: LiveData - get() = _selectedCountry - - private val _selectedState = MutableLiveData() - val selectedState: LiveData - get() = _selectedState + private val _uiState = MutableLiveData() + val uiState: LiveData + get() = _uiState private val _showErrorMessage = SingleLiveEvent() val showErrorMessage: LiveData @@ -62,26 +55,6 @@ class DomainRegistrationDetailsViewModel @Inject constructor( val formError: LiveData get() = _formError - private val _formProgressIndicatorVisible = MutableLiveData() - val formProgressIndicatorVisible: LiveData - get() = _formProgressIndicatorVisible - - private val _statesProgressIndicatorVisible = MutableLiveData() - val statesProgressIndicatorVisible: LiveData - get() = _statesProgressIndicatorVisible - - private val _registrationProgressIndicatorVisible = MutableLiveData() - val registrationProgressIndicatorVisible: LiveData - get() = _registrationProgressIndicatorVisible - - private val _domainRegistrationButtonEnabled = MutableLiveData() - val domainRegistrationButtonEnabled: LiveData - get() = _domainRegistrationButtonEnabled - - private val _privacyProtectionState = MutableLiveData() - val privacyProtectionState: LiveData - get() = _privacyProtectionState - private val _showCountryPickerDialog = SingleLiveEvent>() val showCountryPickerDialog: LiveData> get() = _showCountryPickerDialog @@ -102,6 +75,17 @@ class DomainRegistrationDetailsViewModel @Inject constructor( val showTos: LiveData get() = _showTos + data class DomainRegistrationDetailsUiState( + val isFormProgressIndicatorVisible: Boolean = false, + val isStateProgressIndicatorVisible: Boolean = false, + val isRegistrationProgressIndicatorVisible: Boolean = false, + val isDomainRegistrationButtonEnabled: Boolean = false, + val isPrivacyProtectionEnabled: Boolean = true, + val selectedState: SupportedStateResponse? = null, + val selectedCountry: SupportedDomainCountry? = null, + val isStateInputEnabled: Boolean = false + ) + init { dispatcher.register(this) } @@ -117,21 +101,23 @@ class DomainRegistrationDetailsViewModel @Inject constructor( } this.site = site this.domainProductDetails = domainProductDetails + // default state + _uiState.value = DomainRegistrationDetailsUiState() + fetchSupportedCountries() - _privacyProtectionState.value = true isStarted = true } private fun fetchSupportedCountries() { - _formProgressIndicatorVisible.value = true + _uiState.value = _uiState.value?.copy(isFormProgressIndicatorVisible = true) dispatcher.dispatch(TransactionActionBuilder.generateNoPayloadAction(FETCH_SUPPORTED_COUNTRIES)) } @Subscribe(threadMode = ThreadMode.MAIN) fun onSupportedCountriesFetched(event: OnSupportedCountriesFetched) { if (event.isError) { - _formProgressIndicatorVisible.value = false + _uiState.value = _uiState.value?.copy(isFormProgressIndicatorVisible = false) _showErrorMessage.value = event.error.message AppLog.e(T.DOMAIN_REGISTRATION, "An error occurred while fetching supported countries") } else { @@ -142,7 +128,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( @Subscribe(threadMode = ThreadMode.MAIN) fun onDomainContactFetched(event: OnDomainContactFetched) { - _formProgressIndicatorVisible.value = false + _uiState.value = _uiState.value?.copy(isFormProgressIndicatorVisible = false) if (event.isError) { _showErrorMessage.value = event.error.message AppLog.e(T.DOMAIN_REGISTRATION, "An error occurred while fetching domain contact details") @@ -150,9 +136,14 @@ class DomainRegistrationDetailsViewModel @Inject constructor( _domainContactDetails.value = event.contactModel if (event.contactModel != null && !TextUtils.isEmpty(event.contactModel?.countryCode)) { - _selectedCountry.value = supportedCountries?.firstOrNull { it.code == event.contactModel?.countryCode } - _statesProgressIndicatorVisible.value = true - _domainRegistrationButtonEnabled.value = false + _uiState.value = + uiState.value?.copy( + selectedCountry = supportedCountries?.firstOrNull { + it.code == event.contactModel?.countryCode + }, + isStateProgressIndicatorVisible = true, + isDomainRegistrationButtonEnabled = false + ) dispatcher.dispatch( SiteActionBuilder.newFetchDomainSupportedStatesAction(event.contactModel?.countryCode) ) @@ -162,13 +153,21 @@ class DomainRegistrationDetailsViewModel @Inject constructor( @Subscribe(threadMode = ThreadMode.MAIN) fun onDomainSupportedStatesFetched(event: OnDomainSupportedStatesFetched) { - _domainRegistrationButtonEnabled.value = true - _statesProgressIndicatorVisible.value = false if (event.isError) { + _uiState.value = + uiState.value?.copy( + isStateProgressIndicatorVisible = false, + isDomainRegistrationButtonEnabled = true + ) _showErrorMessage.value = event.error.message AppLog.e(T.DOMAIN_REGISTRATION, "An error occurred while fetching supported countries") } else { - _selectedState.value = event.supportedStates?.firstOrNull { it.code == domainContactDetails.value?.state } + _uiState.value = uiState.value?.copy( + selectedState = event.supportedStates?.firstOrNull { it.code == domainContactDetails.value?.state }, + isStateProgressIndicatorVisible = false, + isDomainRegistrationButtonEnabled = true, + isStateInputEnabled = !event.supportedStates.isNullOrEmpty() + ) _supportedStates.value = event.supportedStates } } @@ -176,7 +175,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( @Subscribe(threadMode = ThreadMode.MAIN) fun onShoppingCartCreated(event: OnShoppingCartCreated) { if (event.isError) { - _registrationProgressIndicatorVisible.value = false + _uiState.value = uiState.value?.copy(isRegistrationProgressIndicatorVisible = false) AppLog.e( T.DOMAIN_REGISTRATION, "An error occurred while creating a shopping cart : " + event.error.message @@ -197,7 +196,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( @Subscribe(threadMode = ThreadMode.MAIN) fun onCartRedeemed(event: OnShoppingCartRedeemed) { if (event.isError) { - _registrationProgressIndicatorVisible.value = false + _uiState.value = uiState.value?.copy(isRegistrationProgressIndicatorVisible = false) _formError.value = event.error _showErrorMessage.value = event.error.message AppLog.e( @@ -213,7 +212,7 @@ class DomainRegistrationDetailsViewModel @Inject constructor( @Subscribe(threadMode = ThreadMode.MAIN) fun onSiteChanged(event: OnSiteChanged) { - _registrationProgressIndicatorVisible.value = false + _uiState.value = uiState.value?.copy(isRegistrationProgressIndicatorVisible = false) if (event.isError) { AppLog.e( T.DOMAIN_REGISTRATION, @@ -234,10 +233,10 @@ class DomainRegistrationDetailsViewModel @Inject constructor( } fun onRegisterDomainButtonClicked() { - _registrationProgressIndicatorVisible.value = true + _uiState.value = uiState.value?.copy(isRegistrationProgressIndicatorVisible = true) _domainContactDetails.value = _domainContactDetails.value?.copy( - countryCode = selectedCountry.value?.code, - state = selectedState.value?.code + countryCode = uiState.value?.selectedCountry?.code, + state = uiState.value?.selectedState?.code ) dispatcher.dispatch( TransactionActionBuilder.newCreateShoppingCartAction( @@ -245,25 +244,31 @@ class DomainRegistrationDetailsViewModel @Inject constructor( site, domainProductDetails.productId, domainProductDetails.domainName, - privacyProtectionState.value!! + uiState.value?.isPrivacyProtectionEnabled!! ) ) ) } fun onCountrySelected(country: SupportedDomainCountry) { - if (country != _selectedCountry.value) { - _selectedCountry.value = country + if (country != uiState.value?.selectedCountry) { + _supportedStates.value = null + _uiState.value = + uiState.value?.copy( + selectedCountry = country, + selectedState = null, + isStateProgressIndicatorVisible = true, + isDomainRegistrationButtonEnabled = false, + isStateInputEnabled = false + ) + _domainContactDetails.value = _domainContactDetails.value?.copy(countryCode = country.code, state = null) - _selectedState.value = null - _statesProgressIndicatorVisible.value = true - _domainRegistrationButtonEnabled.value = false dispatcher.dispatch(SiteActionBuilder.newFetchDomainSupportedStatesAction(country.code)) } } fun onStateSelected(state: SupportedStateResponse) { - _selectedState.value = state + _uiState.value = uiState.value?.copy(selectedState = state) } fun onTosLinkClicked() { @@ -271,12 +276,12 @@ class DomainRegistrationDetailsViewModel @Inject constructor( } fun onDomainContactDetailsChanged(domainContactModel: DomainContactModel) { - if (formProgressIndicatorVisible.value == false) { + if (uiState.value?.isFormProgressIndicatorVisible == false) { _domainContactDetails.value = domainContactModel } } fun togglePrivacyProtection(isEnabled: Boolean) { - _privacyProtectionState.value = isEnabled + _uiState.value = uiState.value?.copy(isPrivacyProtectionEnabled = isEnabled) } } From fa70c9a1da91694116378b9d959d2b864b10027b Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Tue, 4 Jun 2019 21:05:01 -0700 Subject: [PATCH 19/21] updated tests --- .../DomainRegistrationDetailsViewModelTest.kt | 288 +++++++++++------- 1 file changed, 174 insertions(+), 114 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt index 242239eafc50..fcfc7772dfa5 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -47,27 +47,22 @@ import org.wordpress.android.fluxc.store.TransactionsStore.RedeemShoppingCartPay import org.wordpress.android.fluxc.store.TransactionsStore.TransactionErrorType.PHONE import org.wordpress.android.test import org.wordpress.android.ui.domains.DomainProductDetails +import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel.DomainRegistrationDetailsUiState class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { @Mock private lateinit var store: TransactionsStore @Mock private lateinit var dispatcher: Dispatcher @Mock private lateinit var site: SiteModel - @Mock private lateinit var formProgressIndicatorObserver: Observer @Mock private lateinit var domainContactDetailsObserver: Observer - @Mock private lateinit var stateProgressIndicatorObserver: Observer - @Mock private lateinit var domainRegistrationButtonObserver: Observer - @Mock private lateinit var selectedStateObserver: Observer - @Mock private lateinit var selectedCountryObserver: Observer @Mock private lateinit var countryPickerDialogObserver: Observer> @Mock private lateinit var statePickerDialogObserver: Observer> @Mock private lateinit var tosLinkObserver: Observer - @Mock private lateinit var privacyProtectionObserver: Observer - @Mock private lateinit var domainRegistrationProgressIndicatorObserver: Observer @Mock private lateinit var completedDomainRegistrationObserver: Observer - @Mock private lateinit var stateInputVisibleObserver: Observer @Mock private lateinit var errorMessageObserver: Observer + private val uiStateResults = mutableListOf() + private lateinit var viewModel: DomainRegistrationDetailsViewModel private val primaryCountry = SupportedDomainCountry("US", "United States") @@ -135,19 +130,13 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { setupRedeemShoppingCartDispatcher(false) setupFetchSiteDispatcher(false) - viewModel.formProgressIndicatorVisible.observeForever(formProgressIndicatorObserver) + uiStateResults.clear() + viewModel.uiState.observeForever { if (it != null) uiStateResults.add(it) } viewModel.domainContactDetails.observeForever(domainContactDetailsObserver) - viewModel.statesProgressIndicatorVisible.observeForever(stateProgressIndicatorObserver) - viewModel.domainRegistrationButtonEnabled.observeForever(domainRegistrationButtonObserver) - viewModel.selectedState.observeForever(selectedStateObserver) - viewModel.selectedCountry.observeForever(selectedCountryObserver) viewModel.showCountryPickerDialog.observeForever(countryPickerDialogObserver) viewModel.showStatePickerDialog.observeForever(statePickerDialogObserver) viewModel.showTos.observeForever(tosLinkObserver) - viewModel.privacyProtectionState.observeForever(privacyProtectionObserver) - viewModel.registrationProgressIndicatorVisible.observeForever(domainRegistrationProgressIndicatorObserver) viewModel.handleCompletedDomainRegistration.observeForever(completedDomainRegistrationObserver) - viewModel.stateInputEnabled.observeForever(stateInputVisibleObserver) viewModel.showErrorMessage.observeForever(errorMessageObserver) } @@ -164,31 +153,70 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateFetchDomainContactAction(actionsDispatched[1]) validateFetchStatesAction(actionsDispatched[2], primaryCountry.code) - // form progress indicator was shown and dismissed - verify(formProgressIndicatorObserver, times(1)).onChanged(true) - verify(formProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) - - // states progress indicator was shown and dismissed - verify(stateProgressIndicatorObserver, times(1)).onChanged(true) - verify(stateProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.statesProgressIndicatorVisible.value).isEqualTo(false) - - // domain registration button was disabled and then enabled - verify(domainRegistrationButtonObserver, times(1)).onChanged(true) - verify(domainRegistrationButtonObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) - - verify(domainContactDetailsObserver, times(1)).onChanged(domainContactModel) - - verify(selectedStateObserver, times(1)).onChanged(primaryState) - Assertions.assertThat(viewModel.selectedState.value).isEqualTo(primaryState) - - verify(selectedCountryObserver, times(1)).onChanged(primaryCountry) - Assertions.assertThat(viewModel.selectedCountry.value).isEqualTo(primaryCountry) - - verify(stateInputVisibleObserver, times(1)).onChanged(true) - Assertions.assertThat(viewModel.stateInputEnabled.value).isEqualTo(true) + var preloadStep = 0 + + Assertions.assertThat(uiStateResults.size).isEqualTo(5) + + // initial state + Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].selectedState).isNull() + Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isNull() + + preloadStep++ + + // fetching countries and domain contact details + Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(true) + Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].selectedState).isNull() + Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isNull() + + preloadStep++ + + // hiding form progress after domain contact details fetched + Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].selectedState).isNull() + Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isNull() + + verify(domainContactDetailsObserver).onChanged(domainContactModel) + + preloadStep++ + + // fetching states using country code in domain contact details + Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(true) + Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].selectedState).isNull() + Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isEqualTo(primaryCountry) + + preloadStep++ + + // fetched states, ending preload + + Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[preloadStep].selectedState).isEqualTo(primaryState) + Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isEqualTo(primaryCountry) } @Test @@ -199,16 +227,23 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { // Verifying that correct actions with expected payloads were dispatched val captor = ArgumentCaptor.forClass(Action::class.java) - verify(dispatcher, times(1)).dispatch(captor.capture()) + verify(dispatcher).dispatch(captor.capture()) val actionsDispatched = captor.allValues validateFetchSupportedCountriesAction(actionsDispatched[0]) - verify(formProgressIndicatorObserver, times(1)).onChanged(true) - verify(formProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) + Assertions.assertThat(uiStateResults.size).isEqualTo(3) + + // error fetching countries + Assertions.assertThat(uiStateResults[2].isFormProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[2].isDomainRegistrationButtonEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[2].isStateProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[2].isPrivacyProtectionEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[2].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[2].selectedState).isNull() + Assertions.assertThat(uiStateResults[2].selectedCountry).isNull() - verify(errorMessageObserver, times(1)).onChanged(fetchSupportedCountriesError.message) + verify(errorMessageObserver).onChanged(fetchSupportedCountriesError.message) } @Test @@ -225,11 +260,19 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateFetchSupportedCountriesAction(actionsDispatched[0]) validateFetchDomainContactAction(actionsDispatched[1]) - verify(errorMessageObserver, times(1)).onChanged(domainContactInformationFetchError.message) + verify(errorMessageObserver).onChanged(domainContactInformationFetchError.message) + + Assertions.assertThat(uiStateResults.size).isEqualTo(3) - verify(formProgressIndicatorObserver, times(1)).onChanged(true) - verify(formProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) + // error fetching domain contact details + Assertions.assertThat(uiStateResults[2].isFormProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[2].isDomainRegistrationButtonEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[2].isStateProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[2].isPrivacyProtectionEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[2].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[2].isStateInputEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[2].selectedState).isNull() + Assertions.assertThat(uiStateResults[2].selectedCountry).isNull() verify(domainContactDetailsObserver, times(0)).onChanged(any()) Assertions.assertThat(viewModel.domainContactDetails.value).isNull() @@ -250,20 +293,18 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateFetchDomainContactAction(actionsDispatched[1]) validateFetchStatesAction(actionsDispatched[2], primaryCountry.code) - verify(errorMessageObserver, times(1)).onChanged(domainSupportedStatesFetchError.message) + verify(errorMessageObserver).onChanged(domainSupportedStatesFetchError.message) - verify(formProgressIndicatorObserver, times(1)).onChanged(true) - verify(formProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.formProgressIndicatorVisible.value).isEqualTo(false) + Assertions.assertThat(uiStateResults.size).isEqualTo(5) - verify(stateProgressIndicatorObserver, times(1)).onChanged(true) - verify(stateProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.statesProgressIndicatorVisible.value).isEqualTo(false) - - // domain registration button was disabled and then enabled - verify(domainRegistrationButtonObserver, times(1)).onChanged(true) - verify(domainRegistrationButtonObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) + Assertions.assertThat(uiStateResults[4].isFormProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[4].isDomainRegistrationButtonEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[4].isStateProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[4].isPrivacyProtectionEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[4].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[4].isStateInputEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[4].selectedState).isNull() + Assertions.assertThat(uiStateResults[4].selectedCountry).isEqualTo(primaryCountry) } @Test @@ -272,7 +313,7 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.onCountrySelectorClicked() - verify(countryPickerDialogObserver, times(1)).onChanged(countries) + verify(countryPickerDialogObserver).onChanged(countries) } @Test @@ -281,12 +322,13 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.onStateSelectorClicked() - verify(statePickerDialogObserver, times(1)).onChanged(states) + verify(statePickerDialogObserver).onChanged(states) } @Test fun onCountrySelected() = test { viewModel.start(site, domainProductDetails) + clearPreLoadUiStateResult() viewModel.onCountrySelected(secondaryCountry) @@ -299,58 +341,62 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { Assertions.assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo("AU") Assertions.assertThat(viewModel.domainContactDetails.value?.state).isNull() - verify(selectedStateObserver, times(2)).onChanged(null) - Assertions.assertThat(viewModel.selectedState.value).isNull() - - verify(selectedCountryObserver, times(1)).onChanged(secondaryCountry) - - // states progress indicator was shown and dismissed - verify(stateProgressIndicatorObserver, times(2)).onChanged(true) - verify(stateProgressIndicatorObserver, times(2)).onChanged(false) - Assertions.assertThat(viewModel.statesProgressIndicatorVisible.value).isEqualTo(false) - - // domain registration button was disabled and then enabled - verify(domainRegistrationButtonObserver, times(2)).onChanged(true) - verify(domainRegistrationButtonObserver, times(2)).onChanged(false) - Assertions.assertThat(viewModel.domainRegistrationButtonEnabled.value).isEqualTo(true) - - verify(stateInputVisibleObserver, times(2)).onChanged(true) - Assertions.assertThat(viewModel.stateInputEnabled.value).isEqualTo(true) + Assertions.assertThat(uiStateResults.size).isEqualTo(2) + + var loadingStep = 0 + + // county selected + Assertions.assertThat(uiStateResults[loadingStep].isFormProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[loadingStep].isDomainRegistrationButtonEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[loadingStep].isStateProgressIndicatorVisible).isEqualTo(true) + Assertions.assertThat(uiStateResults[loadingStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[loadingStep].isStateInputEnabled).isEqualTo(false) + Assertions.assertThat(uiStateResults[loadingStep].selectedState).isNull() + Assertions.assertThat(uiStateResults[loadingStep].selectedCountry).isEqualTo(secondaryCountry) + + loadingStep++ + + // states fetched + Assertions.assertThat(uiStateResults[loadingStep].isFormProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[loadingStep].isDomainRegistrationButtonEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[loadingStep].isStateProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[loadingStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) + Assertions.assertThat(uiStateResults[loadingStep].isStateInputEnabled).isEqualTo(true) + Assertions.assertThat(uiStateResults[loadingStep].selectedState).isNull() + Assertions.assertThat(uiStateResults[loadingStep].selectedCountry).isEqualTo(secondaryCountry) } @Test fun onSameCountrySelected() = test { viewModel.start(site, domainProductDetails) + clearPreLoadUiStateResult() - Assertions.assertThat(viewModel.selectedCountry.value).isEqualTo(primaryCountry) + Assertions.assertThat(viewModel.uiState.value?.selectedCountry).isEqualTo(primaryCountry) viewModel.onCountrySelected(primaryCountry) val captor = ArgumentCaptor.forClass(Action::class.java) verify(dispatcher, times(3)).dispatch(captor.capture()) - Assertions.assertThat(viewModel.selectedCountry.value).isEqualTo(primaryCountry) - - verify(selectedStateObserver, times(1)).onChanged(primaryState) - Assertions.assertThat(viewModel.selectedState.value).isEqualTo(primaryState) - - verify(selectedCountryObserver, times(1)).onChanged(primaryCountry) - - verify(stateInputVisibleObserver, times(1)).onChanged(true) + Assertions.assertThat(viewModel.uiState.value?.selectedCountry).isEqualTo(primaryCountry) + Assertions.assertThat(uiStateResults.size).isEqualTo(0) } @Test fun onStateSelected() = test { viewModel.start(site, domainProductDetails) + clearPreLoadUiStateResult() viewModel.onStateSelected(primaryState) + Assertions.assertThat(uiStateResults.size).isEqualTo(1) - verify(selectedStateObserver, times(2)).onChanged(primaryState) - Assertions.assertThat(viewModel.selectedState.value).isEqualTo(primaryState) + Assertions.assertThat(uiStateResults[0].selectedState).isEqualTo(primaryState) + Assertions.assertThat(viewModel.uiState.value?.selectedState).isEqualTo(primaryState) } @Test fun onRegisterDomainButtonClicked() = test { viewModel.start(site, domainProductDetails) + clearPreLoadUiStateResult() viewModel.onRegisterDomainButtonClicked() @@ -366,11 +412,12 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateRedeemCartAction(actionsDispatched[4]) validateFetchSiteAction(actionsDispatched[5]) - verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(true) - verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.registrationProgressIndicatorVisible.value).isEqualTo(false) + Assertions.assertThat(uiStateResults.size).isEqualTo(2) + + Assertions.assertThat(uiStateResults[0].isRegistrationProgressIndicatorVisible).isEqualTo(true) + Assertions.assertThat(uiStateResults[1].isRegistrationProgressIndicatorVisible).isEqualTo(false) - verify(completedDomainRegistrationObserver, times(1)).onChanged(domainProductDetails.domainName) + verify(completedDomainRegistrationObserver).onChanged(domainProductDetails.domainName) } @Test @@ -378,6 +425,7 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { setupCreateShoppingCartDispatcher(true) viewModel.start(site, domainProductDetails) + clearPreLoadUiStateResult() viewModel.onRegisterDomainButtonClicked() @@ -387,11 +435,12 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { val actionsDispatched = captor.allValues validateCreateCartAction(actionsDispatched[3]) - verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(true) - verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.registrationProgressIndicatorVisible.value).isEqualTo(false) + Assertions.assertThat(uiStateResults.size).isEqualTo(2) - verify(errorMessageObserver, times(1)).onChanged(shoppingCartCreateError.message) + Assertions.assertThat(uiStateResults[0].isRegistrationProgressIndicatorVisible).isEqualTo(true) + Assertions.assertThat(uiStateResults[1].isRegistrationProgressIndicatorVisible).isEqualTo(false) + + verify(errorMessageObserver).onChanged(shoppingCartCreateError.message) } @Test @@ -399,6 +448,7 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { setupRedeemShoppingCartDispatcher(true) viewModel.start(site, domainProductDetails) + clearPreLoadUiStateResult() viewModel.onRegisterDomainButtonClicked() @@ -409,11 +459,12 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateCreateCartAction(actionsDispatched[3]) validateRedeemCartAction(actionsDispatched[4]) - verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(true) - verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.registrationProgressIndicatorVisible.value).isEqualTo(false) + Assertions.assertThat(uiStateResults.size).isEqualTo(2) + + Assertions.assertThat(uiStateResults[0].isRegistrationProgressIndicatorVisible).isEqualTo(true) + Assertions.assertThat(uiStateResults[1].isRegistrationProgressIndicatorVisible).isEqualTo(false) - verify(errorMessageObserver, times(1)).onChanged(shoppingCartRedeemError.message) + verify(errorMessageObserver).onChanged(shoppingCartRedeemError.message) } @Test @@ -421,6 +472,7 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { setupFetchSiteDispatcher(true) viewModel.start(site, domainProductDetails) + clearPreLoadUiStateResult() viewModel.onRegisterDomainButtonClicked() @@ -433,13 +485,14 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateRedeemCartAction(actionsDispatched[4]) validateFetchSiteAction(actionsDispatched[5]) - verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(true) - verify(domainRegistrationProgressIndicatorObserver, times(1)).onChanged(false) - Assertions.assertThat(viewModel.registrationProgressIndicatorVisible.value).isEqualTo(false) + Assertions.assertThat(uiStateResults.size).isEqualTo(2) + + Assertions.assertThat(uiStateResults[0].isRegistrationProgressIndicatorVisible).isEqualTo(true) + Assertions.assertThat(uiStateResults[1].isRegistrationProgressIndicatorVisible).isEqualTo(false) - verify(errorMessageObserver, times(1)).onChanged(siteChangedError.message) + verify(errorMessageObserver).onChanged(siteChangedError.message) - verify(completedDomainRegistrationObserver, times(1)).onChanged(domainProductDetails.domainName) + verify(completedDomainRegistrationObserver).onChanged(domainProductDetails.domainName) } @Test @@ -448,7 +501,7 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.onTosLinkClicked() - verify(tosLinkObserver, times(1)).onChanged(null) + verify(tosLinkObserver).onChanged(null) } @Test @@ -458,21 +511,24 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { val updatedDomainContactDetails = domainContactModel.copy(firstName = "Peter") viewModel.onDomainContactDetailsChanged(updatedDomainContactDetails) - verify(domainContactDetailsObserver, times(1)).onChanged(updatedDomainContactDetails) + verify(domainContactDetailsObserver).onChanged(updatedDomainContactDetails) Assertions.assertThat(viewModel.domainContactDetails.value).isEqualTo(updatedDomainContactDetails) } @Test fun togglePrivacyProtection() = test { viewModel.start(site, domainProductDetails) + clearPreLoadUiStateResult() - Assertions.assertThat(viewModel.privacyProtectionState.value).isTrue() + Assertions.assertThat(viewModel.uiState.value?.isPrivacyProtectionEnabled).isTrue() viewModel.togglePrivacyProtection(true) - verify(privacyProtectionObserver, times(2)).onChanged(true) + Assertions.assertThat(uiStateResults[0].isPrivacyProtectionEnabled).isEqualTo(true) viewModel.togglePrivacyProtection(false) - verify(privacyProtectionObserver, times(1)).onChanged(false) + Assertions.assertThat(uiStateResults[1].isPrivacyProtectionEnabled).isEqualTo(false) + + Assertions.assertThat(uiStateResults.size).isEqualTo(2) } private fun setupFetchSupportedCountriesDispatcher(isError: Boolean) { @@ -591,4 +647,8 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { val fetchSitePayload = action.payload as SiteModel Assertions.assertThat(fetchSitePayload).isEqualTo(site) } + + private fun clearPreLoadUiStateResult() { + uiStateResults.clear() + } } From 9c545bce22aff4b6b2ac4b79ff88d5022a584559 Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 5 Jun 2019 14:13:14 -0700 Subject: [PATCH 20/21] Simplified progress indication toggle methods. --- .../DomainRegistrationDetailsFragment.kt | 61 +++++++------------ 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt index 2fc6d3687ad9..10d7a9bc9d5a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainRegistrationDetailsFragment.kt @@ -189,17 +189,9 @@ class DomainRegistrationDetailsFragment : Fragment() { viewModel.uiState.observe(this, Observer { uiState -> uiState?.let { - if (uiState.isFormProgressIndicatorVisible) { - showFormProgressIndicator() - } else { - hideFormProgressIndicator() - } - - if (uiState.isStateProgressIndicatorVisible) { - showStateProgress() - } else { - hideStateProgress() - } + toggleFormProgressIndictor(uiState.isFormProgressIndicatorVisible) + toggleStateProgressIndicator(uiState.isStateProgressIndicatorVisible) + toggleStateInputEnabledState(uiState.isStateInputEnabled) if (uiState.isRegistrationProgressIndicatorVisible) { showDomainRegistrationProgressDialog() @@ -213,12 +205,6 @@ class DomainRegistrationDetailsFragment : Fragment() { domain_privacy_options_radiogroup.check(R.id.domain_privacy_off_radio_button) } - if (uiState.isStateInputEnabled) { - enableStateInput() - } else { - disableStateInput() - } - register_domain_button.isEnabled = uiState.isDomainRegistrationButtonEnabled // Country and State fields treated as UI state, since we only use them for display purpose @@ -386,32 +372,31 @@ class DomainRegistrationDetailsFragment : Fragment() { dialogFragment.show(fragmentManager, CountryPickerDialogFragment.TAG) } - private fun showFormProgressIndicator() { - form_progress_indicator.visibility = View.VISIBLE - } - - private fun hideFormProgressIndicator() { - form_progress_indicator.visibility = View.GONE - } - - private fun showStateProgress() { - states_loading_progress_indicator.visibility = View.VISIBLE - state_input_container.isEnabled = false + private fun toggleFormProgressIndictor(visible: Boolean) { + if (visible) { + form_progress_indicator.visibility = View.VISIBLE + } else { + form_progress_indicator.visibility = View.GONE + } } - private fun hideStateProgress() { - states_loading_progress_indicator.visibility = View.GONE - state_input_container.isEnabled = true - } + private fun toggleStateProgressIndicator(visible: Boolean) { + if (visible) { + states_loading_progress_indicator.visibility = View.VISIBLE + } else { + states_loading_progress_indicator.visibility = View.GONE + } - private fun enableStateInput() { - state_input_container.isEnabled = true - state_input_container.hint = getString(R.string.domain_contact_information_state_hint) + state_input_container.isEnabled = !visible } - private fun disableStateInput() { - state_input_container.isEnabled = false - state_input_container.hint = getString(R.string.domain_contact_information_state_not_available_hint) + private fun toggleStateInputEnabledState(enabled: Boolean) { + state_input_container.isEnabled = enabled + if (enabled) { + state_input_container.hint = getString(R.string.domain_contact_information_state_hint) + } else { + state_input_container.hint = getString(R.string.domain_contact_information_state_not_available_hint) + } } private fun showDomainRegistrationProgressDialog() { From 5e29939f0d87417909cf4f03aec5b76f2298923a Mon Sep 17 00:00:00 2001 From: Klymentiy haykov Date: Wed, 5 Jun 2019 14:13:48 -0700 Subject: [PATCH 21/21] Simplifying test using static import for Assertions and variables for UI states for better readability. --- .../DomainRegistrationDetailsViewModelTest.kt | 323 +++++++++--------- 1 file changed, 169 insertions(+), 154 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt index 6a1b08c6fc72..711502c7d5a8 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/domains/DomainRegistrationDetailsViewModelTest.kt @@ -7,6 +7,7 @@ import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test import org.mockito.ArgumentCaptor @@ -153,70 +154,66 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateFetchDomainContactAction(actionsDispatched[1]) validateFetchStatesAction(actionsDispatched[2], primaryCountry.code) - var preloadStep = 0 - Assertions.assertThat(uiStateResults.size).isEqualTo(5) - // initial state - Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].selectedState).isNull() - Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isNull() - - preloadStep++ - - // fetching countries and domain contact details - Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].selectedState).isNull() - Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isNull() - - preloadStep++ + val initialState = uiStateResults[0] + + assertThat(initialState.isFormProgressIndicatorVisible).isEqualTo(false) + assertThat(initialState.isDomainRegistrationButtonEnabled).isEqualTo(false) + assertThat(initialState.isStateProgressIndicatorVisible).isEqualTo(false) + assertThat(initialState.isPrivacyProtectionEnabled).isEqualTo(true) + assertThat(initialState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(initialState.isStateInputEnabled).isEqualTo(false) + assertThat(initialState.selectedState).isNull() + assertThat(initialState.selectedCountry).isNull() + + val fetchingCountriesAndDomainContactState = uiStateResults[1] + + assertThat(fetchingCountriesAndDomainContactState.isFormProgressIndicatorVisible).isEqualTo(true) + assertThat(fetchingCountriesAndDomainContactState.isDomainRegistrationButtonEnabled).isEqualTo(false) + assertThat(fetchingCountriesAndDomainContactState.isStateProgressIndicatorVisible).isEqualTo(false) + assertThat(fetchingCountriesAndDomainContactState.isPrivacyProtectionEnabled).isEqualTo(true) + assertThat(fetchingCountriesAndDomainContactState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(fetchingCountriesAndDomainContactState.isStateInputEnabled).isEqualTo(false) + assertThat(fetchingCountriesAndDomainContactState.selectedState).isNull() + assertThat(fetchingCountriesAndDomainContactState.selectedCountry).isNull() // hiding form progress after domain contact details fetched - Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].selectedState).isNull() - Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isNull() + val domainContactDetailsFetchedState = uiStateResults[2] + + assertThat(domainContactDetailsFetchedState.isFormProgressIndicatorVisible).isEqualTo(false) + assertThat(domainContactDetailsFetchedState.isDomainRegistrationButtonEnabled).isEqualTo(false) + assertThat(domainContactDetailsFetchedState.isStateProgressIndicatorVisible).isEqualTo(false) + assertThat(domainContactDetailsFetchedState.isPrivacyProtectionEnabled).isEqualTo(true) + assertThat(domainContactDetailsFetchedState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(domainContactDetailsFetchedState.isStateInputEnabled).isEqualTo(false) + assertThat(domainContactDetailsFetchedState.selectedState).isNull() + assertThat(domainContactDetailsFetchedState.selectedCountry).isNull() verify(domainContactDetailsObserver).onChanged(domainContactModel) - preloadStep++ - - // fetching states using country code in domain contact details - Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].selectedState).isNull() - Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isEqualTo(primaryCountry) - - preloadStep++ - - // fetched states, ending preload - - Assertions.assertThat(uiStateResults[preloadStep].isFormProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isDomainRegistrationButtonEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[preloadStep].isStateProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isPrivacyProtectionEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[preloadStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[preloadStep].isStateInputEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[preloadStep].selectedState).isEqualTo(primaryState) - Assertions.assertThat(uiStateResults[preloadStep].selectedCountry).isEqualTo(primaryCountry) + val fetchingStatesState = uiStateResults[3] + + assertThat(fetchingStatesState.isFormProgressIndicatorVisible).isEqualTo(false) + assertThat(fetchingStatesState.isDomainRegistrationButtonEnabled).isEqualTo(false) + assertThat(fetchingStatesState.isStateProgressIndicatorVisible).isEqualTo(true) + assertThat(fetchingStatesState.isPrivacyProtectionEnabled).isEqualTo(true) + assertThat(fetchingStatesState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(fetchingStatesState.isStateInputEnabled).isEqualTo(false) + assertThat(fetchingStatesState.selectedState).isNull() + assertThat(fetchingStatesState.selectedCountry).isEqualTo(primaryCountry) + + // ending preload + val fetchedStatesState = uiStateResults[4] + + assertThat(fetchedStatesState.isFormProgressIndicatorVisible).isEqualTo(false) + assertThat(fetchedStatesState.isDomainRegistrationButtonEnabled).isEqualTo(true) + assertThat(fetchedStatesState.isStateProgressIndicatorVisible).isEqualTo(false) + assertThat(fetchedStatesState.isPrivacyProtectionEnabled).isEqualTo(true) + assertThat(fetchedStatesState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(fetchedStatesState.isStateInputEnabled).isEqualTo(true) + assertThat(fetchedStatesState.selectedState).isEqualTo(primaryState) + assertThat(fetchedStatesState.selectedCountry).isEqualTo(primaryCountry) } @Test @@ -232,16 +229,17 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { val actionsDispatched = captor.allValues validateFetchSupportedCountriesAction(actionsDispatched[0]) - Assertions.assertThat(uiStateResults.size).isEqualTo(3) + assertThat(uiStateResults.size).isEqualTo(3) + + val errorFetchingCountriesState = uiStateResults[2] - // error fetching countries - Assertions.assertThat(uiStateResults[2].isFormProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[2].isDomainRegistrationButtonEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[2].isStateProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[2].isPrivacyProtectionEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[2].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[2].selectedState).isNull() - Assertions.assertThat(uiStateResults[2].selectedCountry).isNull() + assertThat(errorFetchingCountriesState.isFormProgressIndicatorVisible).isEqualTo(false) + assertThat(errorFetchingCountriesState.isDomainRegistrationButtonEnabled).isEqualTo(false) + assertThat(errorFetchingCountriesState.isStateProgressIndicatorVisible).isEqualTo(false) + assertThat(errorFetchingCountriesState.isPrivacyProtectionEnabled).isEqualTo(true) + assertThat(errorFetchingCountriesState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(errorFetchingCountriesState.selectedState).isNull() + assertThat(errorFetchingCountriesState.selectedCountry).isNull() verify(errorMessageObserver).onChanged(fetchSupportedCountriesError.message) } @@ -262,20 +260,21 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { verify(errorMessageObserver).onChanged(domainContactInformationFetchError.message) - Assertions.assertThat(uiStateResults.size).isEqualTo(3) + assertThat(uiStateResults.size).isEqualTo(3) + + val errorFetchingDomainContactDetailsState = uiStateResults[2] - // error fetching domain contact details - Assertions.assertThat(uiStateResults[2].isFormProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[2].isDomainRegistrationButtonEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[2].isStateProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[2].isPrivacyProtectionEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[2].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[2].isStateInputEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[2].selectedState).isNull() - Assertions.assertThat(uiStateResults[2].selectedCountry).isNull() + assertThat(errorFetchingDomainContactDetailsState.isFormProgressIndicatorVisible).isEqualTo(false) + assertThat(errorFetchingDomainContactDetailsState.isDomainRegistrationButtonEnabled).isEqualTo(false) + assertThat(errorFetchingDomainContactDetailsState.isStateProgressIndicatorVisible).isEqualTo(false) + assertThat(errorFetchingDomainContactDetailsState.isPrivacyProtectionEnabled).isEqualTo(true) + assertThat(errorFetchingDomainContactDetailsState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(errorFetchingDomainContactDetailsState.isStateInputEnabled).isEqualTo(false) + assertThat(errorFetchingDomainContactDetailsState.selectedState).isNull() + assertThat(errorFetchingDomainContactDetailsState.selectedCountry).isNull() verify(domainContactDetailsObserver, times(0)).onChanged(any()) - Assertions.assertThat(viewModel.domainContactDetails.value).isNull() + assertThat(viewModel.domainContactDetails.value).isNull() } @Test @@ -295,16 +294,18 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { verify(errorMessageObserver).onChanged(domainSupportedStatesFetchError.message) - Assertions.assertThat(uiStateResults.size).isEqualTo(5) + assertThat(uiStateResults.size).isEqualTo(5) + + val errorFetchingStatesState = uiStateResults[4] - Assertions.assertThat(uiStateResults[4].isFormProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[4].isDomainRegistrationButtonEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[4].isStateProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[4].isPrivacyProtectionEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[4].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[4].isStateInputEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[4].selectedState).isNull() - Assertions.assertThat(uiStateResults[4].selectedCountry).isEqualTo(primaryCountry) + assertThat(errorFetchingStatesState.isFormProgressIndicatorVisible).isEqualTo(false) + assertThat(errorFetchingStatesState.isDomainRegistrationButtonEnabled).isEqualTo(true) + assertThat(errorFetchingStatesState.isStateProgressIndicatorVisible).isEqualTo(false) + assertThat(errorFetchingStatesState.isPrivacyProtectionEnabled).isEqualTo(true) + assertThat(errorFetchingStatesState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(errorFetchingStatesState.isStateInputEnabled).isEqualTo(false) + assertThat(errorFetchingStatesState.selectedState).isNull() + assertThat(errorFetchingStatesState.selectedCountry).isEqualTo(primaryCountry) } @Test @@ -338,32 +339,30 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { val actionsDispatched = captor.allValues validateFetchStatesAction(actionsDispatched[3], secondaryCountry.code) - Assertions.assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo("AU") - Assertions.assertThat(viewModel.domainContactDetails.value?.state).isNull() + assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo("AU") + assertThat(viewModel.domainContactDetails.value?.state).isNull() - Assertions.assertThat(uiStateResults.size).isEqualTo(2) + assertThat(uiStateResults.size).isEqualTo(2) - var loadingStep = 0 + val countrySelectedState = uiStateResults[0] - // county selected - Assertions.assertThat(uiStateResults[loadingStep].isFormProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[loadingStep].isDomainRegistrationButtonEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[loadingStep].isStateProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[loadingStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[loadingStep].isStateInputEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults[loadingStep].selectedState).isNull() - Assertions.assertThat(uiStateResults[loadingStep].selectedCountry).isEqualTo(secondaryCountry) + assertThat(countrySelectedState.isFormProgressIndicatorVisible).isEqualTo(false) + assertThat(countrySelectedState.isDomainRegistrationButtonEnabled).isEqualTo(false) + assertThat(countrySelectedState.isStateProgressIndicatorVisible).isEqualTo(true) + assertThat(countrySelectedState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(countrySelectedState.isStateInputEnabled).isEqualTo(false) + assertThat(countrySelectedState.selectedState).isNull() + assertThat(countrySelectedState.selectedCountry).isEqualTo(secondaryCountry) - loadingStep++ + val statesFetchedState = uiStateResults[1] - // states fetched - Assertions.assertThat(uiStateResults[loadingStep].isFormProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[loadingStep].isDomainRegistrationButtonEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[loadingStep].isStateProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[loadingStep].isRegistrationProgressIndicatorVisible).isEqualTo(false) - Assertions.assertThat(uiStateResults[loadingStep].isStateInputEnabled).isEqualTo(true) - Assertions.assertThat(uiStateResults[loadingStep].selectedState).isNull() - Assertions.assertThat(uiStateResults[loadingStep].selectedCountry).isEqualTo(secondaryCountry) + assertThat(statesFetchedState.isFormProgressIndicatorVisible).isEqualTo(false) + assertThat(statesFetchedState.isDomainRegistrationButtonEnabled).isEqualTo(true) + assertThat(statesFetchedState.isStateProgressIndicatorVisible).isEqualTo(false) + assertThat(statesFetchedState.isRegistrationProgressIndicatorVisible).isEqualTo(false) + assertThat(statesFetchedState.isStateInputEnabled).isEqualTo(true) + assertThat(statesFetchedState.selectedState).isNull() + assertThat(statesFetchedState.selectedCountry).isEqualTo(secondaryCountry) } @Test @@ -371,14 +370,14 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.start(site, domainProductDetails) clearPreLoadUiStateResult() - Assertions.assertThat(viewModel.uiState.value?.selectedCountry).isEqualTo(primaryCountry) + assertThat(viewModel.uiState.value?.selectedCountry).isEqualTo(primaryCountry) viewModel.onCountrySelected(primaryCountry) val captor = ArgumentCaptor.forClass(Action::class.java) verify(dispatcher, times(3)).dispatch(captor.capture()) - Assertions.assertThat(viewModel.uiState.value?.selectedCountry).isEqualTo(primaryCountry) - Assertions.assertThat(uiStateResults.size).isEqualTo(0) + assertThat(viewModel.uiState.value?.selectedCountry).isEqualTo(primaryCountry) + assertThat(uiStateResults.size).isEqualTo(0) } @Test @@ -387,10 +386,12 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { clearPreLoadUiStateResult() viewModel.onStateSelected(primaryState) - Assertions.assertThat(uiStateResults.size).isEqualTo(1) + assertThat(uiStateResults.size).isEqualTo(1) - Assertions.assertThat(uiStateResults[0].selectedState).isEqualTo(primaryState) - Assertions.assertThat(viewModel.uiState.value?.selectedState).isEqualTo(primaryState) + val stateSelectedState = uiStateResults[0] + + assertThat(stateSelectedState.selectedState).isEqualTo(primaryState) + assertThat(viewModel.uiState.value?.selectedState).isEqualTo(primaryState) } @Test @@ -400,8 +401,8 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.onRegisterDomainButtonClicked() - Assertions.assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo(primaryCountry.code) - Assertions.assertThat(viewModel.domainContactDetails.value?.state).isEqualTo(primaryState.code) + assertThat(viewModel.domainContactDetails.value?.countryCode).isEqualTo(primaryCountry.code) + assertThat(viewModel.domainContactDetails.value?.state).isEqualTo(primaryState.code) val captor = ArgumentCaptor.forClass(Action::class.java) verify(dispatcher, times(6)).dispatch(captor.capture()) @@ -412,10 +413,13 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateRedeemCartAction(actionsDispatched[4]) validateFetchSiteAction(actionsDispatched[5]) - Assertions.assertThat(uiStateResults.size).isEqualTo(2) + assertThat(uiStateResults.size).isEqualTo(2) + + val domainRegisteringState = uiStateResults[0] + assertThat(domainRegisteringState.isRegistrationProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[0].isRegistrationProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[1].isRegistrationProgressIndicatorVisible).isEqualTo(false) + val domainRegisteredState = uiStateResults[1] + assertThat(domainRegisteredState.isRegistrationProgressIndicatorVisible).isEqualTo(false) verify(completedDomainRegistrationObserver).onChanged(domainProductDetails.domainName) } @@ -435,10 +439,13 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { val actionsDispatched = captor.allValues validateCreateCartAction(actionsDispatched[3]) - Assertions.assertThat(uiStateResults.size).isEqualTo(2) + assertThat(uiStateResults.size).isEqualTo(2) - Assertions.assertThat(uiStateResults[0].isRegistrationProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[1].isRegistrationProgressIndicatorVisible).isEqualTo(false) + val domainRegisteringState = uiStateResults[0] + assertThat(domainRegisteringState.isRegistrationProgressIndicatorVisible).isEqualTo(true) + + val errorCreatingCartState = uiStateResults[1] + assertThat(errorCreatingCartState.isRegistrationProgressIndicatorVisible).isEqualTo(false) verify(errorMessageObserver).onChanged(shoppingCartCreateError.message) } @@ -459,10 +466,13 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateCreateCartAction(actionsDispatched[3]) validateRedeemCartAction(actionsDispatched[4]) - Assertions.assertThat(uiStateResults.size).isEqualTo(2) + assertThat(uiStateResults.size).isEqualTo(2) + + val domainRegisteringState = uiStateResults[0] + assertThat(domainRegisteringState.isRegistrationProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[0].isRegistrationProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[1].isRegistrationProgressIndicatorVisible).isEqualTo(false) + val errorRedeemingCartState = uiStateResults[1] + assertThat(errorRedeemingCartState.isRegistrationProgressIndicatorVisible).isEqualTo(false) verify(errorMessageObserver).onChanged(shoppingCartRedeemError.message) } @@ -485,10 +495,13 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { validateRedeemCartAction(actionsDispatched[4]) validateFetchSiteAction(actionsDispatched[5]) - Assertions.assertThat(uiStateResults.size).isEqualTo(2) + assertThat(uiStateResults.size).isEqualTo(2) + + val domainRegisteringState = uiStateResults[0] + assertThat(domainRegisteringState.isRegistrationProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[0].isRegistrationProgressIndicatorVisible).isEqualTo(true) - Assertions.assertThat(uiStateResults[1].isRegistrationProgressIndicatorVisible).isEqualTo(false) + val errorFetchingSiteState = uiStateResults[1] + assertThat(errorFetchingSiteState.isRegistrationProgressIndicatorVisible).isEqualTo(false) verify(errorMessageObserver).onChanged(siteChangedError.message) @@ -512,7 +525,7 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.onDomainContactDetailsChanged(updatedDomainContactDetails) verify(domainContactDetailsObserver).onChanged(updatedDomainContactDetails) - Assertions.assertThat(viewModel.domainContactDetails.value).isEqualTo(updatedDomainContactDetails) + assertThat(viewModel.domainContactDetails.value).isEqualTo(updatedDomainContactDetails) } @Test @@ -520,15 +533,17 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { viewModel.start(site, domainProductDetails) clearPreLoadUiStateResult() - Assertions.assertThat(viewModel.uiState.value?.isPrivacyProtectionEnabled).isTrue() + assertThat(viewModel.uiState.value?.isPrivacyProtectionEnabled).isTrue() viewModel.togglePrivacyProtection(true) - Assertions.assertThat(uiStateResults[0].isPrivacyProtectionEnabled).isEqualTo(true) + val privacyProtectionOnState = uiStateResults[0] + assertThat(privacyProtectionOnState.isPrivacyProtectionEnabled).isEqualTo(true) viewModel.togglePrivacyProtection(false) - Assertions.assertThat(uiStateResults[1].isPrivacyProtectionEnabled).isEqualTo(false) + val privacyProtectionOffState = uiStateResults[1] + assertThat(privacyProtectionOffState.isPrivacyProtectionEnabled).isEqualTo(false) - Assertions.assertThat(uiStateResults.size).isEqualTo(2) + assertThat(uiStateResults.size).isEqualTo(2) } private fun setupFetchSupportedCountriesDispatcher(isError: Boolean) { @@ -603,49 +618,49 @@ class DomainRegistrationDetailsViewModelTest : BaseUnitTest() { } private fun validateFetchSupportedCountriesAction(action: Action<*>) { - Assertions.assertThat(action.type).isEqualTo(FETCH_SUPPORTED_COUNTRIES) - Assertions.assertThat(action.payload).isNull() + assertThat(action.type).isEqualTo(FETCH_SUPPORTED_COUNTRIES) + assertThat(action.payload).isNull() } private fun validateFetchDomainContactAction(action: Action<*>) { - Assertions.assertThat(action.type).isEqualTo(AccountAction.FETCH_DOMAIN_CONTACT) - Assertions.assertThat(action.payload).isNull() + assertThat(action.type).isEqualTo(AccountAction.FETCH_DOMAIN_CONTACT) + assertThat(action.payload).isNull() } private fun validateFetchStatesAction(action: Action<*>, targetCountryCode: String) { - Assertions.assertThat(action.type).isEqualTo(SiteAction.FETCH_DOMAIN_SUPPORTED_STATES) - Assertions.assertThat(action.payload).isEqualTo(targetCountryCode) + assertThat(action.type).isEqualTo(SiteAction.FETCH_DOMAIN_SUPPORTED_STATES) + assertThat(action.payload).isEqualTo(targetCountryCode) } private fun validateCreateCartAction(action: Action<*>) { - Assertions.assertThat(action.type).isEqualTo(TransactionAction.CREATE_SHOPPING_CART) - Assertions.assertThat(action.payload).isNotNull - Assertions.assertThat(action.payload).isInstanceOf(CreateShoppingCartPayload::class.java) + assertThat(action.type).isEqualTo(TransactionAction.CREATE_SHOPPING_CART) + assertThat(action.payload).isNotNull + assertThat(action.payload).isInstanceOf(CreateShoppingCartPayload::class.java) val createShoppingCartPayload = action.payload as CreateShoppingCartPayload - Assertions.assertThat(createShoppingCartPayload.site).isEqualTo(site) - Assertions.assertThat(createShoppingCartPayload.domainName).isEqualTo(testDomainName) - Assertions.assertThat(createShoppingCartPayload.productId).isEqualTo(productId) - Assertions.assertThat(createShoppingCartPayload.isPrivacyEnabled).isEqualTo(true) + assertThat(createShoppingCartPayload.site).isEqualTo(site) + assertThat(createShoppingCartPayload.domainName).isEqualTo(testDomainName) + assertThat(createShoppingCartPayload.productId).isEqualTo(productId) + assertThat(createShoppingCartPayload.isPrivacyEnabled).isEqualTo(true) } private fun validateRedeemCartAction(action: Action<*>) { - Assertions.assertThat(action.type).isEqualTo(TransactionAction.REDEEM_CART_WITH_CREDITS) - Assertions.assertThat(action.payload).isNotNull - Assertions.assertThat(action.payload).isInstanceOf(RedeemShoppingCartPayload::class.java) + assertThat(action.type).isEqualTo(TransactionAction.REDEEM_CART_WITH_CREDITS) + assertThat(action.payload).isNotNull + assertThat(action.payload).isInstanceOf(RedeemShoppingCartPayload::class.java) val redeemShoppingCartPayload = action.payload as RedeemShoppingCartPayload - Assertions.assertThat(redeemShoppingCartPayload.cartDetails).isEqualTo(createShoppingCartResponse) - Assertions.assertThat(redeemShoppingCartPayload.domainContactModel).isEqualTo(domainContactModel) + assertThat(redeemShoppingCartPayload.cartDetails).isEqualTo(createShoppingCartResponse) + assertThat(redeemShoppingCartPayload.domainContactModel).isEqualTo(domainContactModel) } private fun validateFetchSiteAction(action: Action<*>) { - Assertions.assertThat(action.type).isEqualTo(SiteAction.FETCH_SITE) - Assertions.assertThat(action.payload).isNotNull - Assertions.assertThat(action.payload).isInstanceOf(SiteModel::class.java) + assertThat(action.type).isEqualTo(SiteAction.FETCH_SITE) + assertThat(action.payload).isNotNull + assertThat(action.payload).isInstanceOf(SiteModel::class.java) val fetchSitePayload = action.payload as SiteModel - Assertions.assertThat(fetchSitePayload).isEqualTo(site) + assertThat(fetchSitePayload).isEqualTo(site) } private fun clearPreLoadUiStateResult() {