|
|
@ -22,6 +22,7 @@ import app.cash.turbine.test |
|
|
|
import com.google.common.truth.Truth |
|
|
|
import com.google.common.truth.Truth |
|
|
|
import io.element.android.features.location.api.Location |
|
|
|
import io.element.android.features.location.api.Location |
|
|
|
import io.element.android.features.location.impl.common.actions.FakeLocationActions |
|
|
|
import io.element.android.features.location.impl.common.actions.FakeLocationActions |
|
|
|
|
|
|
|
import io.element.android.features.location.impl.common.permissions.PermissionsEvents |
|
|
|
import io.element.android.features.location.impl.common.permissions.PermissionsPresenter |
|
|
|
import io.element.android.features.location.impl.common.permissions.PermissionsPresenter |
|
|
|
import io.element.android.features.location.impl.common.permissions.PermissionsPresenterFake |
|
|
|
import io.element.android.features.location.impl.common.permissions.PermissionsPresenterFake |
|
|
|
import io.element.android.features.location.impl.common.permissions.PermissionsState |
|
|
|
import io.element.android.features.location.impl.common.permissions.PermissionsState |
|
|
@ -48,6 +49,33 @@ class ShowLocationPresenterTest { |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
fun `emits initial state with no location permission`() = runTest { |
|
|
|
fun `emits initial state with no location permission`() = runTest { |
|
|
|
|
|
|
|
permissionsPresenterFake.givenState( |
|
|
|
|
|
|
|
PermissionsState( |
|
|
|
|
|
|
|
permissions = PermissionsState.Permissions.NoneGranted, |
|
|
|
|
|
|
|
shouldShowRationale = false, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
moleculeFlow(RecompositionMode.Immediate) { |
|
|
|
|
|
|
|
presenter.present() |
|
|
|
|
|
|
|
}.test { |
|
|
|
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
|
|
|
Truth.assertThat(initialState.location).isEqualTo(location) |
|
|
|
|
|
|
|
Truth.assertThat(initialState.description).isEqualTo(A_DESCRIPTION) |
|
|
|
|
|
|
|
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(false) |
|
|
|
|
|
|
|
Truth.assertThat(initialState.isTrackMyLocation).isEqualTo(false) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
fun `emits initial state location permission denied once`() = runTest { |
|
|
|
|
|
|
|
permissionsPresenterFake.givenState( |
|
|
|
|
|
|
|
PermissionsState( |
|
|
|
|
|
|
|
permissions = PermissionsState.Permissions.NoneGranted, |
|
|
|
|
|
|
|
shouldShowRationale = true, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
moleculeFlow(RecompositionMode.Immediate) { |
|
|
|
moleculeFlow(RecompositionMode.Immediate) { |
|
|
|
presenter.present() |
|
|
|
presenter.present() |
|
|
|
}.test { |
|
|
|
}.test { |
|
|
@ -120,9 +148,144 @@ class ShowLocationPresenterTest { |
|
|
|
|
|
|
|
|
|
|
|
Truth.assertThat(trackMyLocationState.hasLocationPermission).isEqualTo(true) |
|
|
|
Truth.assertThat(trackMyLocationState.hasLocationPermission).isEqualTo(true) |
|
|
|
Truth.assertThat(trackMyLocationState.isTrackMyLocation).isEqualTo(true) |
|
|
|
Truth.assertThat(trackMyLocationState.isTrackMyLocation).isEqualTo(true) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Swipe the map to switch mode |
|
|
|
|
|
|
|
initialState.eventSink(ShowLocationEvents.TrackMyLocation(false)) |
|
|
|
|
|
|
|
val trackLocationDisabledState = awaitItem() |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationDisabledState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None) |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationDisabledState.isTrackMyLocation).isEqualTo(false) |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationDisabledState.hasLocationPermission).isEqualTo(true) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
fun `rationale dialog dismiss`() = runTest { |
|
|
|
|
|
|
|
permissionsPresenterFake.givenState( |
|
|
|
|
|
|
|
PermissionsState( |
|
|
|
|
|
|
|
permissions = PermissionsState.Permissions.NoneGranted, |
|
|
|
|
|
|
|
shouldShowRationale = true, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
moleculeFlow(RecompositionMode.Immediate) { |
|
|
|
|
|
|
|
presenter.present() |
|
|
|
|
|
|
|
}.test { |
|
|
|
|
|
|
|
// Skip initial state |
|
|
|
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Click on the button to switch mode |
|
|
|
|
|
|
|
initialState.eventSink(ShowLocationEvents.TrackMyLocation(true)) |
|
|
|
|
|
|
|
val trackLocationState = awaitItem() |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationState.permissionDialog).isEqualTo(ShowLocationState.Dialog.PermissionRationale) |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationState.isTrackMyLocation).isEqualTo(false) |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationState.hasLocationPermission).isEqualTo(false) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Dismiss the dialog |
|
|
|
|
|
|
|
initialState.eventSink(ShowLocationEvents.DismissDialog) |
|
|
|
|
|
|
|
val dialogDismissedState = awaitItem() |
|
|
|
|
|
|
|
Truth.assertThat(dialogDismissedState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None) |
|
|
|
|
|
|
|
Truth.assertThat(dialogDismissedState.isTrackMyLocation).isEqualTo(false) |
|
|
|
|
|
|
|
Truth.assertThat(dialogDismissedState.hasLocationPermission).isEqualTo(false) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
fun `rationale dialog continue`() = runTest { |
|
|
|
|
|
|
|
permissionsPresenterFake.givenState( |
|
|
|
|
|
|
|
PermissionsState( |
|
|
|
|
|
|
|
permissions = PermissionsState.Permissions.NoneGranted, |
|
|
|
|
|
|
|
shouldShowRationale = true, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
moleculeFlow(RecompositionMode.Immediate) { |
|
|
|
|
|
|
|
presenter.present() |
|
|
|
|
|
|
|
}.test { |
|
|
|
|
|
|
|
// Skip initial state |
|
|
|
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Click on the button to switch mode |
|
|
|
|
|
|
|
initialState.eventSink(ShowLocationEvents.TrackMyLocation(true)) |
|
|
|
|
|
|
|
val trackLocationState = awaitItem() |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationState.permissionDialog).isEqualTo(ShowLocationState.Dialog.PermissionRationale) |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationState.isTrackMyLocation).isEqualTo(false) |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationState.hasLocationPermission).isEqualTo(false) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Continue the dialog sends permission request to the permissions presenter |
|
|
|
|
|
|
|
trackLocationState.eventSink(ShowLocationEvents.RequestPermissions) |
|
|
|
|
|
|
|
Truth.assertThat(permissionsPresenterFake.events.last()).isEqualTo(PermissionsEvents.RequestPermissions) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
fun `permission denied dialog dismiss`() = runTest { |
|
|
|
|
|
|
|
permissionsPresenterFake.givenState( |
|
|
|
|
|
|
|
PermissionsState( |
|
|
|
|
|
|
|
permissions = PermissionsState.Permissions.NoneGranted, |
|
|
|
|
|
|
|
shouldShowRationale = false, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
moleculeFlow(RecompositionMode.Immediate) { |
|
|
|
|
|
|
|
presenter.present() |
|
|
|
|
|
|
|
}.test { |
|
|
|
|
|
|
|
// Skip initial state |
|
|
|
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Click on the button to switch mode |
|
|
|
|
|
|
|
initialState.eventSink(ShowLocationEvents.TrackMyLocation(true)) |
|
|
|
|
|
|
|
val trackLocationState = awaitItem() |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationState.permissionDialog).isEqualTo(ShowLocationState.Dialog.PermissionDenied) |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationState.isTrackMyLocation).isEqualTo(false) |
|
|
|
|
|
|
|
Truth.assertThat(trackLocationState.hasLocationPermission).isEqualTo(false) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Dismiss the dialog |
|
|
|
|
|
|
|
initialState.eventSink(ShowLocationEvents.DismissDialog) |
|
|
|
|
|
|
|
val dialogDismissedState = awaitItem() |
|
|
|
|
|
|
|
Truth.assertThat(dialogDismissedState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None) |
|
|
|
|
|
|
|
Truth.assertThat(dialogDismissedState.isTrackMyLocation).isEqualTo(false) |
|
|
|
|
|
|
|
Truth.assertThat(dialogDismissedState.hasLocationPermission).isEqualTo(false) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
fun `open settings activity`() = runTest { |
|
|
|
|
|
|
|
permissionsPresenterFake.givenState( |
|
|
|
|
|
|
|
PermissionsState( |
|
|
|
|
|
|
|
permissions = PermissionsState.Permissions.NoneGranted, |
|
|
|
|
|
|
|
shouldShowRationale = false, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
moleculeFlow(RecompositionMode.Immediate) { |
|
|
|
|
|
|
|
presenter.present() |
|
|
|
|
|
|
|
}.test { |
|
|
|
|
|
|
|
// Skip initial state |
|
|
|
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
initialState.eventSink(ShowLocationEvents.TrackMyLocation(true)) |
|
|
|
|
|
|
|
val dialogShownState = awaitItem() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Open settings |
|
|
|
|
|
|
|
dialogShownState.eventSink(ShowLocationEvents.OpenAppSettings) |
|
|
|
|
|
|
|
val settingsOpenedState = awaitItem() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Truth.assertThat(settingsOpenedState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None) |
|
|
|
|
|
|
|
Truth.assertThat(fakeLocationActions.openSettingsInvocationsCount).isEqualTo(1) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
fun `application name is in state`() = runTest { |
|
|
|
|
|
|
|
moleculeFlow(RecompositionMode.Immediate) { |
|
|
|
|
|
|
|
presenter.present() |
|
|
|
|
|
|
|
}.test { |
|
|
|
|
|
|
|
val initialState = awaitItem() |
|
|
|
|
|
|
|
Truth.assertThat(initialState.appName).isEqualTo("app name") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
companion object { |
|
|
|
companion object { |
|
|
|
private const val A_DESCRIPTION = "My happy place" |
|
|
|
private const val A_DESCRIPTION = "My happy place" |
|
|
|
} |
|
|
|
} |
|
|
|