diff --git a/WordPress/src/main/java/org/wordpress/android/models/InvitePeopleUtils.kt b/WordPress/src/main/java/org/wordpress/android/models/InvitePeopleUtils.kt index af1a5dd2a42c..8132c9c8d361 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/InvitePeopleUtils.kt +++ b/WordPress/src/main/java/org/wordpress/android/models/InvitePeopleUtils.kt @@ -1,24 +1,25 @@ package org.wordpress.android.models -import android.content.Context import dagger.Reusable -import org.wordpress.android.fluxc.model.RoleModel import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.models.wrappers.RoleUtilsWrapper +import org.wordpress.android.models.wrappers.SimpleDateFormatWrapper import org.wordpress.android.ui.people.InviteLinksApiCallsProvider.InviteLinksItem import org.wordpress.android.ui.people.InviteLinksUiItem import org.wordpress.android.util.AppLog import org.wordpress.android.util.AppLog.T import org.wordpress.android.util.DateTimeUtilsWrapper import org.wordpress.android.viewmodel.ContextProvider -import java.text.SimpleDateFormat import javax.inject.Inject @Reusable class InvitePeopleUtils @Inject constructor( private val siteStore: SiteStore, private val contextProvider: ContextProvider, - private val dateTimeUtilsWrapper: DateTimeUtilsWrapper + private val dateTimeUtilsWrapper: DateTimeUtilsWrapper, + private val roleUtilsWrapper: RoleUtilsWrapper, + private val simpleDateFormatWrapper: SimpleDateFormatWrapper ) { fun getInviteLinkDataFromRoleDisplayName( inviteLinksData: MutableList, @@ -39,7 +40,7 @@ class InvitePeopleUtils @Inject constructor( siteModel: SiteModel, roleName: String ): String { - val roles = getInviteRoles(siteStore, siteModel, contextProvider.getContext()) + val roles = roleUtilsWrapper.getInviteRoles(siteStore, siteModel, contextProvider.getContext()) return roles.firstOrNull { roleModel -> roleModel.name.equals(roleName, ignoreCase = true) @@ -50,8 +51,8 @@ class InvitePeopleUtils @Inject constructor( inviteLinksData: MutableList, siteModel: SiteModel ): List { - val formatter = SimpleDateFormat.getDateInstance() - val roles = getInviteRoles(siteStore, siteModel, contextProvider.getContext()) + val formatter = simpleDateFormatWrapper.getDateInstance() + val roles = roleUtilsWrapper.getInviteRoles(siteStore, siteModel, contextProvider.getContext()) AppLog.d(T.PEOPLE, "getMappedLinksUiItems > ${siteModel.siteId}") AppLog.d( @@ -93,10 +94,4 @@ class InvitePeopleUtils @Inject constructor( linksItem.roleDisplayName } } - - private fun getInviteRoles( - siteStore: SiteStore, - siteModel: SiteModel, - context: Context - ): List = RoleUtils.getInviteRoles(siteStore, siteModel, context) } diff --git a/WordPress/src/main/java/org/wordpress/android/models/wrappers/RoleUtilsWrapper.kt b/WordPress/src/main/java/org/wordpress/android/models/wrappers/RoleUtilsWrapper.kt new file mode 100644 index 000000000000..0d1badbc562f --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/models/wrappers/RoleUtilsWrapper.kt @@ -0,0 +1,18 @@ +package org.wordpress.android.models.wrappers + +import android.content.Context +import dagger.Reusable +import org.wordpress.android.fluxc.model.RoleModel +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.models.RoleUtils +import javax.inject.Inject + +@Reusable +class RoleUtilsWrapper @Inject constructor() { + fun getInviteRoles( + siteStore: SiteStore, + siteModel: SiteModel, + context: Context + ): List = RoleUtils.getInviteRoles(siteStore, siteModel, context) +} diff --git a/WordPress/src/main/java/org/wordpress/android/models/wrappers/SimpleDateFormatWrapper.kt b/WordPress/src/main/java/org/wordpress/android/models/wrappers/SimpleDateFormatWrapper.kt new file mode 100644 index 000000000000..5a3e9e9aec35 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/models/wrappers/SimpleDateFormatWrapper.kt @@ -0,0 +1,11 @@ +package org.wordpress.android.models.wrappers + +import dagger.Reusable +import java.text.DateFormat +import java.text.SimpleDateFormat +import javax.inject.Inject + +@Reusable +class SimpleDateFormatWrapper @Inject constructor() { + fun getDateInstance(): DateFormat = SimpleDateFormat.getDateInstance() +} diff --git a/WordPress/src/test/java/org/wordpress/android/ui/people/InviteLinksHandlerTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/people/InviteLinksHandlerTest.kt new file mode 100644 index 000000000000..cf5e68dc77f4 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/people/InviteLinksHandlerTest.kt @@ -0,0 +1,135 @@ +package org.wordpress.android.ui.people + +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.flow.flow +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.wordpress.android.BaseUnitTest +import org.wordpress.android.TEST_DISPATCHER +import org.wordpress.android.test +import org.wordpress.android.ui.pages.SnackbarMessageHolder +import org.wordpress.android.ui.people.InviteLinksUseCase.InviteLinksState +import org.wordpress.android.ui.people.InviteLinksUseCase.InviteLinksState.InviteLinksData +import org.wordpress.android.ui.people.InviteLinksUseCase.InviteLinksState.InviteLinksError +import org.wordpress.android.ui.people.InviteLinksUseCase.UseCaseScenarioContext.GENERATING_LINKS +import org.wordpress.android.ui.people.InviteLinksUseCase.UseCaseScenarioContext.INITIALIZING +import org.wordpress.android.ui.people.InviteLinksUseCase.UseCaseScenarioContext.MANAGING_AVAILABLE_LINKS +import org.wordpress.android.ui.utils.UiString.UiStringText + +@InternalCoroutinesApi +class InviteLinksHandlerTest : BaseUnitTest() { + @Mock lateinit var inviteLinksUseCase: InviteLinksUseCase + + private lateinit var inviteLinksHandler: InviteLinksHandler + private var uiState: InviteLinksState? = null + private var holder: SnackbarMessageHolder? = null + private val blogId = 100L + + @Before + fun setUp() { + inviteLinksHandler = InviteLinksHandler( + inviteLinksUseCase, + TEST_DISPATCHER + ) + setupObservers() + } + + @Test + fun `manageState populates snackbar on Failure`() = test { + val errorMessage = UiStringText("error message") + + val state = InviteLinksError( + scenarioContext = INITIALIZING, + error = errorMessage + ) + + whenever( + inviteLinksUseCase.getInviteLinksStatus(blogId, INITIALIZING) + ).thenReturn(flow { emit(state) }) + + inviteLinksHandler.handleInviteLinksStatusRequest(blogId, INITIALIZING) + + requireNotNull(uiState).let { + assertThat(it).isEqualTo(state) + } + + requireNotNull(holder).let { + assertThat(it.message).isEqualTo(errorMessage) + } + } + + @Test + fun `handleInviteLinksStatusRequest collects expected state`() = test { + val state = InviteLinksData( + scenarioContext = INITIALIZING, + links = listOf(mock(), mock()) + ) + + whenever( + inviteLinksUseCase.getInviteLinksStatus(blogId, INITIALIZING) + ).thenReturn(flow { emit(state) }) + + inviteLinksHandler.handleInviteLinksStatusRequest(blogId, INITIALIZING) + + requireNotNull(uiState).let { + assertThat(it).isEqualTo(state) + } + + assertThat(holder).isNull() + } + + @Test + fun `handleGenerateLinks collects expected state`() = test { + val state = InviteLinksData( + scenarioContext = GENERATING_LINKS, + links = listOf(mock(), mock()) + ) + + whenever(inviteLinksUseCase.generateLinks(blogId)).thenReturn(flow { emit(state) }) + + inviteLinksHandler.handleGenerateLinks(blogId) + + requireNotNull(uiState).let { + assertThat(it).isEqualTo(state) + } + + assertThat(holder).isNull() + } + + @Test + fun `handleDisableLinks collects expected state`() = test { + val state = InviteLinksData( + scenarioContext = MANAGING_AVAILABLE_LINKS, + links = listOf() + ) + + whenever(inviteLinksUseCase.disableLinks(blogId)).thenReturn(flow { emit(state) }) + + inviteLinksHandler.handleDisableLinks(blogId) + + requireNotNull(uiState).let { + assertThat(it).isEqualTo(state) + } + + assertThat(holder).isNull() + } + + private fun setupObservers() { + uiState = null + + inviteLinksHandler.inviteLinksState.observeForever { + uiState = it + } + + holder = null + inviteLinksHandler.snackbarEvents.observeForever { event -> + event.applyIfNotHandled { + holder = this + } + } + } +} diff --git a/WordPress/src/test/java/org/wordpress/android/ui/people/InvitePeopleUtilsTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/people/InvitePeopleUtilsTest.kt new file mode 100644 index 000000000000..89ac78fa2808 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/people/InvitePeopleUtilsTest.kt @@ -0,0 +1,124 @@ +package org.wordpress.android.ui.people + +import android.content.Context +import com.nhaarman.mockitokotlin2.eq +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.ArgumentMatchers.anyLong +import org.mockito.Mock +import org.wordpress.android.BaseUnitTest +import org.wordpress.android.fluxc.model.RoleModel +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.models.InvitePeopleUtils +import org.wordpress.android.models.wrappers.RoleUtilsWrapper +import org.wordpress.android.models.wrappers.SimpleDateFormatWrapper +import org.wordpress.android.ui.people.InviteLinksApiCallsProvider.InviteLinksItem +import org.wordpress.android.util.DateTimeUtilsWrapper +import org.wordpress.android.viewmodel.ContextProvider +import java.text.DateFormat +import java.util.Date + +class InvitePeopleUtilsTest : BaseUnitTest() { + @Mock lateinit var siteStore: SiteStore + @Mock lateinit var siteModel: SiteModel + @Mock lateinit var contextProvider: ContextProvider + @Mock lateinit var dateTimeUtilsWrapper: DateTimeUtilsWrapper + @Mock lateinit var roleUtilsWrapper: RoleUtilsWrapper + @Mock lateinit var context: Context + @Mock lateinit var simpleDateFormatWrapper: SimpleDateFormatWrapper + @Mock lateinit var dateFormat: DateFormat + + private lateinit var invitePeopleUtils: InvitePeopleUtils + + private val roles = listOf( + RoleModel().apply { + name = "administrator" + displayName = "Administrator" + }, + RoleModel().apply { + name = "contributor" + displayName = "Contributor" + } + ) + + private val linkItems = mutableListOf( + InviteLinksItem( + role = "administrator", + expiry = 0, + link = "https://wordpress.com/linkdata" + ), + InviteLinksItem( + role = "follower", + expiry = 0, + link = "https://wordpress.com/linkdata" + ) + ) + + @Before + fun setUp() { + val date: Date = mock() + whenever(contextProvider.getContext()).thenReturn(context) + whenever(roleUtilsWrapper.getInviteRoles(siteStore, siteModel, context)).thenReturn(roles) + whenever(dateTimeUtilsWrapper.dateFromTimestamp(anyLong())).thenReturn(date) + whenever(dateFormat.format(eq(date))).thenReturn("") + whenever(simpleDateFormatWrapper.getDateInstance()).thenReturn(dateFormat) + + invitePeopleUtils = InvitePeopleUtils( + siteStore, + contextProvider, + dateTimeUtilsWrapper, + roleUtilsWrapper, + simpleDateFormatWrapper + ) + } + + @Test + fun `link data found by available display name`() { + val item = invitePeopleUtils.getInviteLinkDataFromRoleDisplayName(linkItems, siteModel, "Administrator") + + requireNotNull(item).let { + assertThat(it.role).isEqualTo("administrator") + } + } + + @Test + fun `link data not found by missing display name`() { + val item = invitePeopleUtils.getInviteLinkDataFromRoleDisplayName(linkItems, siteModel, "Follower") + + assertThat(item).isNull() + } + + @Test + fun `display name found for available role`() { + val displayName = invitePeopleUtils.getDisplayNameForRole(siteModel, "administrator") + + assertThat(displayName).isEqualTo("Administrator") + } + + @Test + fun `display name not found for missing role`() { + val displayName = invitePeopleUtils.getDisplayNameForRole(siteModel, "follower") + + assertThat(displayName).isEmpty() + } + + @Test + fun `ui items list created as expected`() { + val uiItemsList = invitePeopleUtils.getMappedLinksUiItems(linkItems, siteModel) + + assertThat(uiItemsList.count()).isEqualTo(1) + assertThat(uiItemsList.get(0).roleName).isEqualTo("administrator") + } + + @Test + fun `role display names created as expected`() { + val displayNamesList = invitePeopleUtils.getInviteLinksRoleDisplayNames(linkItems, siteModel) + + assertThat(displayNamesList.count()).isEqualTo(1) + assertThat(displayNamesList.get(0)).isEqualTo("Administrator") + } +} diff --git a/WordPress/src/test/java/org/wordpress/android/ui/people/PeopleInviteViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/people/PeopleInviteViewModelTest.kt new file mode 100644 index 000000000000..4070f9154513 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/people/PeopleInviteViewModelTest.kt @@ -0,0 +1,225 @@ +package org.wordpress.android.ui.people + +import android.content.Context +import androidx.lifecycle.MutableLiveData +import com.nhaarman.mockitokotlin2.eq +import com.nhaarman.mockitokotlin2.times +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import kotlinx.coroutines.InternalCoroutinesApi +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyList +import org.mockito.ArgumentMatchers.anyLong +import org.mockito.Mock +import org.wordpress.android.BaseUnitTest +import org.wordpress.android.TEST_DISPATCHER +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.models.InvitePeopleUtils +import org.wordpress.android.test +import org.wordpress.android.ui.pages.SnackbarMessageHolder +import org.wordpress.android.ui.people.InviteLinksApiCallsProvider.InviteLinksItem +import org.wordpress.android.ui.people.InviteLinksUiStateType.HIDDEN +import org.wordpress.android.ui.people.InviteLinksUiStateType.LOADING +import org.wordpress.android.ui.people.InviteLinksUseCase.InviteLinksState +import org.wordpress.android.ui.people.InviteLinksUseCase.InviteLinksState.InviteLinksData +import org.wordpress.android.ui.people.InviteLinksUseCase.UseCaseScenarioContext.INITIALIZING +import org.wordpress.android.ui.utils.UiString.UiStringText +import org.wordpress.android.util.DateTimeUtilsWrapper +import org.wordpress.android.util.analytics.AnalyticsUtilsWrapper +import org.wordpress.android.viewmodel.ContextProvider +import org.wordpress.android.viewmodel.Event + +@InternalCoroutinesApi +class PeopleInviteViewModelTest : BaseUnitTest() { + @Mock lateinit var inviteLinksHandler: InviteLinksHandler + @Mock lateinit var dateTimeUtilsWrapper: DateTimeUtilsWrapper + @Mock lateinit var contextProvider: ContextProvider + @Mock lateinit var invitePeopleUtils: InvitePeopleUtils + @Mock lateinit var analyticsUtilsWrapper: AnalyticsUtilsWrapper + @Mock lateinit var siteModel: SiteModel + @Mock lateinit var context: Context + @Mock lateinit var inviteLinksItem: InviteLinksItem + + private lateinit var viewModel: PeopleInviteViewModel + private val blogId = 100L + + private val snackbarEvents = MutableLiveData>() + private val inviteLinksState = MutableLiveData() + + private var holder: SnackbarMessageHolder? = null + private var uiState: InviteLinksUiState? = null + private var sharedLink: InviteLinksItem? = null + private var rolesForSelectDialog: Array? = null + + @Before + fun setUp() { + whenever(inviteLinksHandler.snackbarEvents).thenReturn(snackbarEvents) + whenever(inviteLinksHandler.inviteLinksState).thenReturn(inviteLinksState) + whenever(siteModel.siteId).thenReturn(blogId) + whenever(siteModel.isWpForTeamsSite).thenReturn(true) + whenever(contextProvider.getContext()).thenReturn(context) + + viewModel = PeopleInviteViewModel( + inviteLinksHandler, + TEST_DISPATCHER, + dateTimeUtilsWrapper, + contextProvider, + invitePeopleUtils, + analyticsUtilsWrapper + ) + } + + @Test + fun `View Model has expected state when starting and site is WP for teams site`() = test { + setupObvserversAndStart() + + requireNotNull(uiState).let { + assertThat(it).isEqualTo(getInviteLinksUiState()) + } + + verify( + inviteLinksHandler, times(1) + ).handleInviteLinksStatusRequest(anyLong(), eq(INITIALIZING)) + } + + @Test + fun `View Model has expected state when starting and site is NOT WP for teams site`() = test { + whenever(siteModel.isWpForTeamsSite).thenReturn(false) + + setupObvserversAndStart() + + requireNotNull(uiState).let { + assertThat(it).isEqualTo(getInviteLinksUiState(type = HIDDEN, isLinksSectionVisible = false)) + } + } + + @Test + fun `selecting links role opens role dialog`() { + val roles = listOf("administrator", "contributor") + + whenever(invitePeopleUtils.getInviteLinksRoleDisplayNames(anyList(), eq(siteModel))).thenReturn(roles) + + setupObvserversAndStart() + + viewModel.onLinksRoleClicked() + + requireNotNull(rolesForSelectDialog).let { + assertThat(it).isEqualTo(roles.toTypedArray()) + } + } + + @Test + fun `selecting links role gives error if role cannot be found`() { + val roles = listOf() + val message = "snackbar message" + + whenever(invitePeopleUtils.getInviteLinksRoleDisplayNames(anyList(), eq(siteModel))).thenReturn(roles) + whenever(context.getString(anyInt())).thenReturn(message) + + setupObvserversAndStart() + + viewModel.onLinksRoleClicked() + + assertThat(rolesForSelectDialog).isNull() + requireNotNull(holder).let { + assertThat(it.message).isEqualTo(UiStringText(message)) + } + } + + @Test + fun `expected link is shared when data is found`() { + val role = "viewer" + + whenever(inviteLinksItem.role).thenReturn(role) + whenever( + invitePeopleUtils.getInviteLinkDataFromRoleDisplayName(anyList(), eq(siteModel), eq(role)) + ).thenReturn(inviteLinksItem) + + setupObvserversAndStart() + + viewModel.onShareButtonClicked(role) + + requireNotNull(sharedLink).let { + assertThat(it).isEqualTo(inviteLinksItem) + } + } + + @Test + fun `snackbar is shown when link to shared data is not found`() { + val role = "viewer" + val message = "snackbar message" + + whenever(inviteLinksItem.role).thenReturn(role) + whenever( + invitePeopleUtils.getInviteLinkDataFromRoleDisplayName(anyList(), eq(siteModel), eq(role)) + ).thenReturn(null) + whenever(context.getString(anyInt(), eq(role))).thenReturn(message) + + setupObvserversAndStart() + inviteLinksState.value = InviteLinksData(INITIALIZING, listOf(inviteLinksItem)) + + viewModel.onShareButtonClicked(role) + + assertThat(sharedLink).isNull() + requireNotNull(holder).let { + assertThat(it.message).isEqualTo(UiStringText(message)) + } + } + + private fun setupObvserversAndStart() { + viewModel.inviteLinksUiState.observeForever { + uiState = it + } + + viewModel.shareLink.observeForever { + it.applyIfNotHandled { + sharedLink = this + } + } + + viewModel.snackbarEvents.observeForever { + it.applyIfNotHandled { + holder = this + } + } + + viewModel.showSelectLinksRoleDialog.observeForever { + it.applyIfNotHandled { + rolesForSelectDialog = this + } + } + + viewModel.start(siteModel) + } + + companion object { + fun getInviteLinksUiState( + type: InviteLinksUiStateType = LOADING, + isLinksSectionVisible: Boolean = true, + loadAndRetryUiState: LoadAndRetryUiState = LoadAndRetryUiState.LOADING, + isShimmerSectionVisible: Boolean = false, + isRoleSelectionAllowed: Boolean = false, + links: List = listOf(), + inviteLinksSelectedRole: InviteLinksUiItem = InviteLinksUiItem.getEmptyItem(), + enableManageLinksActions: Boolean = false, + startShimmer: Boolean = isShimmerSectionVisible && type == LOADING, + isActionButtonsEnabled: Boolean = !startShimmer + ): InviteLinksUiState { + return InviteLinksUiState( + type = type, + isLinksSectionVisible = isLinksSectionVisible, + loadAndRetryUiState = loadAndRetryUiState, + isShimmerSectionVisible = isShimmerSectionVisible, + isRoleSelectionAllowed = isRoleSelectionAllowed, + links = links, + inviteLinksSelectedRole = inviteLinksSelectedRole, + enableManageLinksActions = enableManageLinksActions, + startShimmer = startShimmer, + isActionButtonsEnabled = isActionButtonsEnabled + ) + } + } +} diff --git a/WordPress/src/test/java/org/wordpress/android/ui/people/usecases/InviteLinksUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/people/usecases/InviteLinksUseCaseTest.kt new file mode 100644 index 000000000000..7d518a9c1833 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/people/usecases/InviteLinksUseCaseTest.kt @@ -0,0 +1,191 @@ +package org.wordpress.android.ui.people.usecases + +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import kotlinx.coroutines.flow.toList +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.ArgumentMatchers.anyLong +import org.mockito.Mock +import org.wordpress.android.BaseUnitTest +import org.wordpress.android.R.string +import org.wordpress.android.fluxc.store.AccountStore +import org.wordpress.android.fluxc.store.SiteStore +import org.wordpress.android.test +import org.wordpress.android.ui.people.InviteLinksApiCallsProvider +import org.wordpress.android.ui.people.InviteLinksApiCallsProvider.InviteLinksCallResult.Failure +import org.wordpress.android.ui.people.InviteLinksApiCallsProvider.InviteLinksCallResult.Success +import org.wordpress.android.ui.people.InviteLinksApiCallsProvider.InviteLinksItem +import org.wordpress.android.ui.people.InviteLinksUseCase +import org.wordpress.android.ui.people.InviteLinksUseCase.InviteLinksState.InviteLinksData +import org.wordpress.android.ui.people.InviteLinksUseCase.InviteLinksState.InviteLinksError +import org.wordpress.android.ui.people.InviteLinksUseCase.InviteLinksState.InviteLinksLoading +import org.wordpress.android.ui.people.InviteLinksUseCase.InviteLinksState.UserNotAuthenticated +import org.wordpress.android.ui.people.InviteLinksUseCase.UseCaseScenarioContext.GENERATING_LINKS +import org.wordpress.android.ui.people.InviteLinksUseCase.UseCaseScenarioContext.INITIALIZING +import org.wordpress.android.ui.people.InviteLinksUseCase.UseCaseScenarioContext.MANAGING_AVAILABLE_LINKS +import org.wordpress.android.ui.utils.UiString.UiStringRes +import org.wordpress.android.ui.utils.UiString.UiStringText +import org.wordpress.android.util.NetworkUtilsWrapper +import org.wordpress.android.util.analytics.AnalyticsUtilsWrapper + +class InviteLinksUseCaseTest : BaseUnitTest() { + @Mock lateinit var networkUtilsWrapper: NetworkUtilsWrapper + @Mock lateinit var inviteLinksApiCallsProvider: InviteLinksApiCallsProvider + @Mock lateinit var accountStore: AccountStore + @Mock lateinit var analyticsUtilsWrapper: AnalyticsUtilsWrapper + @Mock lateinit var siteStore: SiteStore + + private lateinit var inviteLinksUseCase: InviteLinksUseCase + private val blogId = 100L + + @Before + fun setUp() { + whenever(accountStore.hasAccessToken()).thenReturn(true) + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true) + + inviteLinksUseCase = InviteLinksUseCase( + networkUtilsWrapper, + inviteLinksApiCallsProvider, + accountStore, + analyticsUtilsWrapper, + siteStore + ) + } + + @Test + fun `makeChecksAndApplyStrategy emits expected state when user not logged in`() = test { + whenever(accountStore.hasAccessToken()).thenReturn(false) + + val flow = inviteLinksUseCase.getInviteLinksStatus(blogId, INITIALIZING) + + assertThat(flow.toList()).isEqualTo(listOf(UserNotAuthenticated)) + } + + @Test + fun `makeChecksAndApplyStrategy emits expected states when no network`() = test { + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(false) + + val flow = inviteLinksUseCase.getInviteLinksStatus(blogId, INITIALIZING) + + assertThat(flow.toList()).isEqualTo( + listOf( + InviteLinksLoading(INITIALIZING), + InviteLinksError(INITIALIZING, UiStringRes(string.error_network_connection)) + ) + ) + } + + @Test + fun `getInviteLinksStatus emits expected states on Success`() = test { + val inviteLinks = listOf(mock(), mock()) + + whenever(inviteLinksApiCallsProvider.getInviteLinksStatus(anyLong())).thenReturn(Success(inviteLinks)) + + val flow = inviteLinksUseCase.getInviteLinksStatus(blogId, INITIALIZING) + + assertThat(flow.toList()).isEqualTo( + listOf( + InviteLinksLoading(INITIALIZING), + InviteLinksData(INITIALIZING, inviteLinks) + ) + ) + } + + @Test + fun `getInviteLinksStatus emits expected states on Failure`() = test { + val error = "error message" + + whenever(inviteLinksApiCallsProvider.getInviteLinksStatus(anyLong())).thenReturn(Failure(error)) + + val flow = inviteLinksUseCase.getInviteLinksStatus(blogId, INITIALIZING) + + assertThat(flow.toList()).isEqualTo( + listOf( + InviteLinksLoading(INITIALIZING), + InviteLinksError(INITIALIZING, UiStringText(error)) + ) + ) + } + + @Test + fun `generateInvitesStrategy emits expected states when getInviteLinksStatus succeeds`() = test { + val inviteLinks = listOf(mock(), mock()) + + whenever(inviteLinksApiCallsProvider.generateLinks(anyLong())).thenReturn(Success(listOf())) + whenever(inviteLinksApiCallsProvider.getInviteLinksStatus(anyLong())).thenReturn(Success(inviteLinks)) + + val flow = inviteLinksUseCase.generateLinks(blogId) + + assertThat(flow.toList()).isEqualTo( + listOf( + InviteLinksLoading(GENERATING_LINKS), + InviteLinksData(GENERATING_LINKS, inviteLinks) + ) + ) + } + + @Test + fun `generateInvitesStrategy emits expected states when getInviteLinksStatus fails`() = test { + val error = "error message" + + whenever(inviteLinksApiCallsProvider.generateLinks(anyLong())).thenReturn(Success(listOf())) + whenever(inviteLinksApiCallsProvider.getInviteLinksStatus(anyLong())).thenReturn(Failure(error)) + + val flow = inviteLinksUseCase.generateLinks(blogId) + + assertThat(flow.toList()).isEqualTo( + listOf( + InviteLinksLoading(GENERATING_LINKS), + InviteLinksError(GENERATING_LINKS, UiStringText(error)) + ) + ) + } + + @Test + fun `generateInvitesStrategy emits expected states when generateLinks fails`() = test { + val error = "error message" + + whenever(inviteLinksApiCallsProvider.generateLinks(anyLong())).thenReturn(Success(listOf())) + whenever(inviteLinksApiCallsProvider.getInviteLinksStatus(anyLong())).thenReturn(Failure(error)) + + val flow = inviteLinksUseCase.generateLinks(blogId) + + assertThat(flow.toList()).isEqualTo( + listOf(InviteLinksLoading(GENERATING_LINKS), + InviteLinksError(GENERATING_LINKS, UiStringText(error)) + ) + ) + } + + @Test + fun `disableInvitesStrategy emits expected states on Success`() = test { + whenever(inviteLinksApiCallsProvider.disableLinks(anyLong())).thenReturn(Success(listOf())) + + val flow = inviteLinksUseCase.disableLinks(blogId) + + assertThat(flow.toList()).isEqualTo( + listOf( + InviteLinksLoading(MANAGING_AVAILABLE_LINKS), + InviteLinksData(MANAGING_AVAILABLE_LINKS, listOf()) + ) + ) + } + + @Test + fun `disableInvitesStrategy emits expected states on Failure`() = test { + val error = "error message" + + whenever(inviteLinksApiCallsProvider.disableLinks(anyLong())).thenReturn(Failure(error)) + + val flow = inviteLinksUseCase.disableLinks(blogId) + + assertThat(flow.toList()).isEqualTo( + listOf( + InviteLinksLoading(MANAGING_AVAILABLE_LINKS), + InviteLinksError(MANAGING_AVAILABLE_LINKS, UiStringText(error)) + ) + ) + } +}