Jorge Martín
1 month ago
22 changed files with 562 additions and 76 deletions
@ -0,0 +1,119 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.securebackup.impl.reset |
||||||
|
|
||||||
|
import app.cash.turbine.test |
||||||
|
import com.google.common.truth.Truth.assertThat |
||||||
|
import io.element.android.libraries.architecture.AsyncData |
||||||
|
import io.element.android.libraries.matrix.api.encryption.IdentityResetHandle |
||||||
|
import io.element.android.libraries.matrix.test.FakeMatrixClient |
||||||
|
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService |
||||||
|
import io.element.android.libraries.matrix.test.encryption.FakeIdentityPasswordResetHandle |
||||||
|
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService |
||||||
|
import io.element.android.tests.testutils.lambda.lambdaRecorder |
||||||
|
import kotlinx.coroutines.CoroutineScope |
||||||
|
import kotlinx.coroutines.test.TestScope |
||||||
|
import kotlinx.coroutines.test.runTest |
||||||
|
import org.junit.Test |
||||||
|
|
||||||
|
class ResetIdentityFlowManagerTests { |
||||||
|
@Test |
||||||
|
fun `getResetHandle - emits a reset handle`() = runTest { |
||||||
|
val startResetLambda = lambdaRecorder<Result<IdentityResetHandle?>> { Result.success(FakeIdentityPasswordResetHandle()) } |
||||||
|
val encryptionService = FakeEncryptionService(startIdentityResetLambda = startResetLambda) |
||||||
|
val flowManager = createFlowManager(encryptionService = encryptionService) |
||||||
|
|
||||||
|
flowManager.getResetHandle().test { |
||||||
|
assertThat(awaitItem().isLoading()).isTrue() |
||||||
|
assertThat(awaitItem().isSuccess()).isTrue() |
||||||
|
startResetLambda.assertions().isCalledOnce() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `getResetHandle - om successful handle retrieval returns that same handle`() = runTest { |
||||||
|
val startResetLambda = lambdaRecorder<Result<IdentityResetHandle?>> { Result.success(FakeIdentityPasswordResetHandle()) } |
||||||
|
val encryptionService = FakeEncryptionService(startIdentityResetLambda = startResetLambda) |
||||||
|
val flowManager = createFlowManager(encryptionService = encryptionService) |
||||||
|
|
||||||
|
var result: AsyncData.Success<IdentityResetHandle>? = null |
||||||
|
flowManager.getResetHandle().test { |
||||||
|
assertThat(awaitItem().isLoading()).isTrue() |
||||||
|
result = awaitItem() as? AsyncData.Success<IdentityResetHandle> |
||||||
|
assertThat(result).isNotNull() |
||||||
|
} |
||||||
|
|
||||||
|
flowManager.getResetHandle().test { |
||||||
|
assertThat(awaitItem()).isSameInstanceAs(result) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `getResetHandle - will fail if it receives a null reset handle`() = runTest { |
||||||
|
val startResetLambda = lambdaRecorder<Result<IdentityResetHandle?>> { Result.success(null) } |
||||||
|
val encryptionService = FakeEncryptionService(startIdentityResetLambda = startResetLambda) |
||||||
|
val flowManager = createFlowManager(encryptionService = encryptionService) |
||||||
|
|
||||||
|
flowManager.getResetHandle().test { |
||||||
|
assertThat(awaitItem().isLoading()).isTrue() |
||||||
|
assertThat(awaitItem().isFailure()).isTrue() |
||||||
|
startResetLambda.assertions().isCalledOnce() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `getResetHandle - fails gracefully when receiving an exception from the encryption service`() = runTest { |
||||||
|
val startResetLambda = lambdaRecorder<Result<IdentityResetHandle?>> { Result.failure(IllegalStateException("Failure")) } |
||||||
|
val encryptionService = FakeEncryptionService(startIdentityResetLambda = startResetLambda) |
||||||
|
val flowManager = createFlowManager(encryptionService = encryptionService) |
||||||
|
|
||||||
|
flowManager.getResetHandle().test { |
||||||
|
assertThat(awaitItem().isLoading()).isTrue() |
||||||
|
assertThat(awaitItem().isFailure()).isTrue() |
||||||
|
startResetLambda.assertions().isCalledOnce() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `cancel - resets the state and calls cancel on the reset handle`() = runTest { |
||||||
|
val cancelLambda = lambdaRecorder<Unit> { } |
||||||
|
val resetHandle = FakeIdentityPasswordResetHandle(cancelLambda = cancelLambda) |
||||||
|
val startResetLambda = lambdaRecorder<Result<IdentityResetHandle?>> { Result.success(resetHandle) } |
||||||
|
val encryptionService = FakeEncryptionService(startIdentityResetLambda = startResetLambda) |
||||||
|
val flowManager = createFlowManager(encryptionService = encryptionService) |
||||||
|
|
||||||
|
flowManager.getResetHandle().test { |
||||||
|
assertThat(awaitItem().isLoading()).isTrue() |
||||||
|
assertThat(awaitItem().isSuccess()).isTrue() |
||||||
|
|
||||||
|
flowManager.cancel() |
||||||
|
cancelLambda.assertions().isCalledOnce() |
||||||
|
assertThat(awaitItem().isUninitialized()).isTrue() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun TestScope.createFlowManager( |
||||||
|
encryptionService: FakeEncryptionService = FakeEncryptionService(), |
||||||
|
client: FakeMatrixClient = FakeMatrixClient(encryptionService = encryptionService), |
||||||
|
sessionCoroutineScope: CoroutineScope = this, |
||||||
|
sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(), |
||||||
|
) = ResetIdentityFlowManager( |
||||||
|
matrixClient = client, |
||||||
|
sessionCoroutineScope = sessionCoroutineScope, |
||||||
|
sessionVerificationService = sessionVerificationService, |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,96 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.securebackup.impl.reset.password |
||||||
|
|
||||||
|
import app.cash.molecule.RecompositionMode |
||||||
|
import app.cash.molecule.moleculeFlow |
||||||
|
import app.cash.turbine.test |
||||||
|
import com.google.common.truth.Truth.assertThat |
||||||
|
import io.element.android.libraries.matrix.test.encryption.FakeIdentityPasswordResetHandle |
||||||
|
import io.element.android.tests.testutils.lambda.lambdaRecorder |
||||||
|
import io.element.android.tests.testutils.testCoroutineDispatchers |
||||||
|
import kotlinx.coroutines.test.TestScope |
||||||
|
import kotlinx.coroutines.test.runTest |
||||||
|
import org.junit.Test |
||||||
|
|
||||||
|
class ResetIdentityPasswordPresenterTest { |
||||||
|
@Test |
||||||
|
fun `present - initial state`() = runTest { |
||||||
|
val presenter = createPresenter() |
||||||
|
moleculeFlow(RecompositionMode.Immediate) { |
||||||
|
presenter.present() |
||||||
|
}.test { |
||||||
|
val initialState = awaitItem() |
||||||
|
assertThat(initialState.resetAction.isUninitialized()).isTrue() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `present - Reset event succeeds`() = runTest { |
||||||
|
val resetLambda = lambdaRecorder<String, Result<Unit>> { _ -> Result.success(Unit) } |
||||||
|
val resetHandle = FakeIdentityPasswordResetHandle(resetPasswordLambda = resetLambda) |
||||||
|
val presenter = createPresenter(identityResetHandle = resetHandle) |
||||||
|
moleculeFlow(RecompositionMode.Immediate) { |
||||||
|
presenter.present() |
||||||
|
}.test { |
||||||
|
val initialState = awaitItem() |
||||||
|
initialState.eventSink(ResetIdentityPasswordEvent.Reset("password")) |
||||||
|
assertThat(awaitItem().resetAction.isLoading()).isTrue() |
||||||
|
assertThat(awaitItem().resetAction.isSuccess()).isTrue() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `present - Reset event can fail gracefully`() = runTest { |
||||||
|
val resetLambda = lambdaRecorder<String, Result<Unit>> { _ -> Result.failure(IllegalStateException("Failed")) } |
||||||
|
val resetHandle = FakeIdentityPasswordResetHandle(resetPasswordLambda = resetLambda) |
||||||
|
val presenter = createPresenter(identityResetHandle = resetHandle) |
||||||
|
moleculeFlow(RecompositionMode.Immediate) { |
||||||
|
presenter.present() |
||||||
|
}.test { |
||||||
|
val initialState = awaitItem() |
||||||
|
initialState.eventSink(ResetIdentityPasswordEvent.Reset("password")) |
||||||
|
assertThat(awaitItem().resetAction.isLoading()).isTrue() |
||||||
|
assertThat(awaitItem().resetAction.isFailure()).isTrue() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `present - DismissError event resets the state`() = runTest { |
||||||
|
val resetLambda = lambdaRecorder<String, Result<Unit>> { _ -> Result.failure(IllegalStateException("Failed")) } |
||||||
|
val resetHandle = FakeIdentityPasswordResetHandle(resetPasswordLambda = resetLambda) |
||||||
|
val presenter = createPresenter(identityResetHandle = resetHandle) |
||||||
|
moleculeFlow(RecompositionMode.Immediate) { |
||||||
|
presenter.present() |
||||||
|
}.test { |
||||||
|
val initialState = awaitItem() |
||||||
|
initialState.eventSink(ResetIdentityPasswordEvent.Reset("password")) |
||||||
|
assertThat(awaitItem().resetAction.isLoading()).isTrue() |
||||||
|
assertThat(awaitItem().resetAction.isFailure()).isTrue() |
||||||
|
|
||||||
|
initialState.eventSink(ResetIdentityPasswordEvent.DismissError) |
||||||
|
assertThat(awaitItem().resetAction.isUninitialized()).isTrue() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun TestScope.createPresenter( |
||||||
|
identityResetHandle: FakeIdentityPasswordResetHandle = FakeIdentityPasswordResetHandle(), |
||||||
|
) = ResetIdentityPasswordPresenter( |
||||||
|
identityPasswordResetHandle = identityResetHandle, |
||||||
|
dispatchers = testCoroutineDispatchers(), |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.securebackup.impl.reset.password |
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity |
||||||
|
import androidx.compose.ui.test.junit4.AndroidComposeTestRule |
||||||
|
import androidx.compose.ui.test.junit4.createAndroidComposeRule |
||||||
|
import androidx.compose.ui.test.onNodeWithText |
||||||
|
import androidx.compose.ui.test.performTextInput |
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4 |
||||||
|
import io.element.android.libraries.architecture.AsyncAction |
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings |
||||||
|
import io.element.android.tests.testutils.EnsureNeverCalled |
||||||
|
import io.element.android.tests.testutils.EventsRecorder |
||||||
|
import io.element.android.tests.testutils.clickOn |
||||||
|
import io.element.android.tests.testutils.ensureCalledOnce |
||||||
|
import io.element.android.tests.testutils.pressBack |
||||||
|
import io.element.android.tests.testutils.pressBackKey |
||||||
|
import org.junit.Rule |
||||||
|
import org.junit.Test |
||||||
|
import org.junit.rules.TestRule |
||||||
|
import org.junit.runner.RunWith |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class) |
||||||
|
class ResetIdentityPasswordViewTest { |
||||||
|
@get:Rule |
||||||
|
val rule = createAndroidComposeRule<ComponentActivity>() |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `pressing the back HW button invokes the expected callback`() { |
||||||
|
ensureCalledOnce { |
||||||
|
rule.setResetPasswordView( |
||||||
|
ResetIdentityPasswordState(resetAction = AsyncAction.Uninitialized, eventSink = {}), |
||||||
|
onBack = it, |
||||||
|
) |
||||||
|
rule.pressBackKey() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `clicking on the back navigation button invokes the expected callback`() { |
||||||
|
ensureCalledOnce { |
||||||
|
rule.setResetPasswordView( |
||||||
|
ResetIdentityPasswordState(resetAction = AsyncAction.Uninitialized, eventSink = {}), |
||||||
|
onBack = it, |
||||||
|
) |
||||||
|
rule.pressBack() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `clicking 'Reset identity' confirms the reset`() { |
||||||
|
val eventsRecorder = EventsRecorder<ResetIdentityPasswordEvent>() |
||||||
|
rule.setResetPasswordView( |
||||||
|
ResetIdentityPasswordState(resetAction = AsyncAction.Uninitialized, eventSink = eventsRecorder), |
||||||
|
) |
||||||
|
rule.onNodeWithText("Password").performTextInput("A password") |
||||||
|
|
||||||
|
rule.clickOn(CommonStrings.action_reset_identity) |
||||||
|
|
||||||
|
eventsRecorder.assertSingle(ResetIdentityPasswordEvent.Reset("A password")) |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `clicking OK dismisses the error dialog`() { |
||||||
|
val eventsRecorder = EventsRecorder<ResetIdentityPasswordEvent>() |
||||||
|
rule.setResetPasswordView( |
||||||
|
ResetIdentityPasswordState(resetAction = AsyncAction.Failure(IllegalStateException("A failure")), eventSink = eventsRecorder), |
||||||
|
) |
||||||
|
rule.clickOn(CommonStrings.action_ok) |
||||||
|
|
||||||
|
eventsRecorder.assertSingle(ResetIdentityPasswordEvent.DismissError) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setResetPasswordView( |
||||||
|
state: ResetIdentityPasswordState, |
||||||
|
onBack: () -> Unit = EnsureNeverCalled(), |
||||||
|
) { |
||||||
|
setContent { |
||||||
|
ResetIdentityPasswordView(state = state, onBack = onBack) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.securebackup.impl.reset.root |
||||||
|
|
||||||
|
import app.cash.molecule.RecompositionMode |
||||||
|
import app.cash.molecule.moleculeFlow |
||||||
|
import app.cash.turbine.test |
||||||
|
import com.google.common.truth.Truth.assertThat |
||||||
|
import kotlinx.coroutines.test.runTest |
||||||
|
import org.junit.Test |
||||||
|
|
||||||
|
class ResetIdentityRootPresenterTests { |
||||||
|
@Test |
||||||
|
fun `present - initial state`() = runTest { |
||||||
|
val presenter = ResetIdentityRootPresenter() |
||||||
|
moleculeFlow(RecompositionMode.Immediate) { |
||||||
|
presenter.present() |
||||||
|
}.test { |
||||||
|
val initialState = awaitItem() |
||||||
|
assertThat(initialState.displayConfirmationDialog).isFalse() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `present - Continue event displays the confirmation dialog`() = runTest { |
||||||
|
val presenter = ResetIdentityRootPresenter() |
||||||
|
moleculeFlow(RecompositionMode.Immediate) { |
||||||
|
presenter.present() |
||||||
|
}.test { |
||||||
|
val initialState = awaitItem() |
||||||
|
initialState.eventSink(ResetIdentityRootEvent.Continue) |
||||||
|
|
||||||
|
assertThat(awaitItem().displayConfirmationDialog).isTrue() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `present - DismissDialog event hides the confirmation dialog`() = runTest { |
||||||
|
val presenter = ResetIdentityRootPresenter() |
||||||
|
moleculeFlow(RecompositionMode.Immediate) { |
||||||
|
presenter.present() |
||||||
|
}.test { |
||||||
|
val initialState = awaitItem() |
||||||
|
initialState.eventSink(ResetIdentityRootEvent.Continue) |
||||||
|
assertThat(awaitItem().displayConfirmationDialog).isTrue() |
||||||
|
|
||||||
|
initialState.eventSink(ResetIdentityRootEvent.DismissDialog) |
||||||
|
assertThat(awaitItem().displayConfirmationDialog).isFalse() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2024 New Vector Ltd |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package io.element.android.features.securebackup.impl.reset.root |
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity |
||||||
|
import androidx.compose.ui.test.junit4.AndroidComposeTestRule |
||||||
|
import androidx.compose.ui.test.junit4.createAndroidComposeRule |
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4 |
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings |
||||||
|
import io.element.android.tests.testutils.EnsureNeverCalled |
||||||
|
import io.element.android.tests.testutils.EventsRecorder |
||||||
|
import io.element.android.tests.testutils.clickOn |
||||||
|
import io.element.android.tests.testutils.ensureCalledOnce |
||||||
|
import io.element.android.tests.testutils.pressBack |
||||||
|
import io.element.android.tests.testutils.pressBackKey |
||||||
|
import org.junit.Rule |
||||||
|
import org.junit.Test |
||||||
|
import org.junit.rules.TestRule |
||||||
|
import org.junit.runner.RunWith |
||||||
|
import org.robolectric.annotation.Config |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class) |
||||||
|
class ResetIdentityRootViewTests { |
||||||
|
@get:Rule |
||||||
|
val rule = createAndroidComposeRule<ComponentActivity>() |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `pressing the back HW button invokes the expected callback`() { |
||||||
|
ensureCalledOnce { |
||||||
|
rule.setResetRootView( |
||||||
|
ResetIdentityRootState(displayConfirmationDialog = false, eventSink = {}), |
||||||
|
onBack = it, |
||||||
|
) |
||||||
|
rule.pressBackKey() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `clicking on the back navigation button invokes the expected callback`() { |
||||||
|
ensureCalledOnce { |
||||||
|
rule.setResetRootView( |
||||||
|
ResetIdentityRootState(displayConfirmationDialog = false, eventSink = {}), |
||||||
|
onBack = it, |
||||||
|
) |
||||||
|
rule.pressBack() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@Config(qualifiers = "h720dp") |
||||||
|
fun `clicking Continue displays the confirmation dialog`() { |
||||||
|
val eventsRecorder = EventsRecorder<ResetIdentityRootEvent>() |
||||||
|
rule.setResetRootView( |
||||||
|
ResetIdentityRootState(displayConfirmationDialog = false, eventSink = eventsRecorder), |
||||||
|
) |
||||||
|
|
||||||
|
rule.clickOn(CommonStrings.action_continue) |
||||||
|
|
||||||
|
eventsRecorder.assertSingle(ResetIdentityRootEvent.Continue) |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `clicking 'Yes, reset now' confirms the reset`() { |
||||||
|
ensureCalledOnce { |
||||||
|
rule.setResetRootView( |
||||||
|
ResetIdentityRootState(displayConfirmationDialog = true, eventSink = {}), |
||||||
|
onContinue = it, |
||||||
|
) |
||||||
|
rule.clickOn(CommonStrings.screen_reset_encryption_confirmation_alert_action) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun `clicking Cancel dismisses the dialog`() { |
||||||
|
val eventsRecorder = EventsRecorder<ResetIdentityRootEvent>() |
||||||
|
rule.setResetRootView( |
||||||
|
ResetIdentityRootState(displayConfirmationDialog = true, eventSink = eventsRecorder), |
||||||
|
) |
||||||
|
|
||||||
|
rule.clickOn(CommonStrings.action_cancel) |
||||||
|
eventsRecorder.assertSingle(ResetIdentityRootEvent.DismissDialog) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setResetRootView( |
||||||
|
state: ResetIdentityRootState, |
||||||
|
onBack: () -> Unit = EnsureNeverCalled(), |
||||||
|
onContinue: () -> Unit = EnsureNeverCalled(), |
||||||
|
) { |
||||||
|
setContent { |
||||||
|
ResetIdentityRootView(state = state, onContinue = onContinue, onBack = onBack) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue