PIN : add test for SetupPinPresenter
This commit is contained in:
parent
f6b9a8be9a
commit
f283594fbd
7 changed files with 123 additions and 13 deletions
|
|
@ -250,8 +250,6 @@ koverMerged {
|
||||||
excludes += "io.element.android.appnav.loggedin.LoggedInPresenter$*"
|
excludes += "io.element.android.appnav.loggedin.LoggedInPresenter$*"
|
||||||
// Some options can't be tested at the moment
|
// Some options can't be tested at the moment
|
||||||
excludes += "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*"
|
excludes += "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*"
|
||||||
// Temporary until we have actually something to test.
|
|
||||||
excludes += "io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter$*"
|
|
||||||
}
|
}
|
||||||
bound {
|
bound {
|
||||||
minValue = 85
|
minValue = 85
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ dependencies {
|
||||||
testImplementation(projects.tests.testutils)
|
testImplementation(projects.tests.testutils)
|
||||||
testImplementation(projects.libraries.cryptography.test)
|
testImplementation(projects.libraries.cryptography.test)
|
||||||
testImplementation(projects.libraries.cryptography.impl)
|
testImplementation(projects.libraries.cryptography.impl)
|
||||||
|
testImplementation(projects.libraries.featureflag.test)
|
||||||
|
|
||||||
|
|
||||||
ksp(libs.showkase.processor)
|
ksp(libs.showkase.processor)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,6 @@ import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel
|
||||||
|
|
||||||
sealed interface PinUnlockEvents {
|
sealed interface PinUnlockEvents {
|
||||||
data class OnPinKeypadPressed(val pinKeypadModel: PinKeypadModel) : PinUnlockEvents
|
data class OnPinKeypadPressed(val pinKeypadModel: PinKeypadModel) : PinUnlockEvents
|
||||||
data object Unlock : PinUnlockEvents
|
|
||||||
data object OnForgetPin : PinUnlockEvents
|
data object OnForgetPin : PinUnlockEvents
|
||||||
|
data object ClearSignOutPrompt : PinUnlockEvents
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ class PinUnlockPresenter @Inject constructor(
|
||||||
|
|
||||||
fun handleEvents(event: PinUnlockEvents) {
|
fun handleEvents(event: PinUnlockEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
PinUnlockEvents.Unlock -> coroutineScope.launch { pinStateService.unlock() }
|
|
||||||
is PinUnlockEvents.OnPinKeypadPressed -> {
|
is PinUnlockEvents.OnPinKeypadPressed -> {
|
||||||
pinEntry = pinEntry.process(event.pinKeypadModel)
|
pinEntry = pinEntry.process(event.pinKeypadModel)
|
||||||
if (pinEntry.isComplete()) {
|
if (pinEntry.isComplete()) {
|
||||||
|
|
@ -61,6 +60,7 @@ class PinUnlockPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PinUnlockEvents.OnForgetPin -> showSignOutPrompt = true
|
PinUnlockEvents.OnForgetPin -> showSignOutPrompt = true
|
||||||
|
PinUnlockEvents.ClearSignOutPrompt -> showSignOutPrompt = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PinUnlockState(
|
return PinUnlockState(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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
|
||||||
|
*
|
||||||
|
* http://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.lockscreen.impl.pin.model
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
|
||||||
|
fun PinEntry.assertText(text: String) {
|
||||||
|
assertThat(toText()).isEqualTo(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PinEntry.assertEmpty() {
|
||||||
|
val isEmpty = digits.all { it is PinDigit.Empty }
|
||||||
|
assertThat(isEmpty).isTrue()
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,8 @@ import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.lockscreen.impl.pin.model.PinDigit
|
import io.element.android.features.lockscreen.impl.pin.model.PinDigit
|
||||||
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
|
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
|
||||||
|
import io.element.android.features.lockscreen.impl.pin.model.assertEmpty
|
||||||
|
import io.element.android.features.lockscreen.impl.pin.model.assertText
|
||||||
import io.element.android.features.lockscreen.impl.setup.validation.PinValidator
|
import io.element.android.features.lockscreen.impl.setup.validation.PinValidator
|
||||||
import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure
|
import io.element.android.features.lockscreen.impl.setup.validation.SetupPinFailure
|
||||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||||
|
|
@ -99,15 +101,6 @@ class SetupPinPresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PinEntry.assertText(text: String) {
|
|
||||||
assertThat(toText()).isEqualTo(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PinEntry.assertEmpty() {
|
|
||||||
val isEmpty = digits.all { it is PinDigit.Empty }
|
|
||||||
assertThat(isEmpty).isTrue()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createSetupPinPresenter(): SetupPinPresenter {
|
private fun createSetupPinPresenter(): SetupPinPresenter {
|
||||||
return SetupPinPresenter(PinValidator(), aBuildMeta())
|
return SetupPinPresenter(PinValidator(), aBuildMeta())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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
|
||||||
|
*
|
||||||
|
* http://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.lockscreen.impl.unlock
|
||||||
|
|
||||||
|
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.features.lockscreen.impl.pin.model.assertEmpty
|
||||||
|
import io.element.android.features.lockscreen.impl.pin.model.assertText
|
||||||
|
import io.element.android.features.lockscreen.impl.state.DefaultLockScreenStateService
|
||||||
|
import io.element.android.features.lockscreen.impl.unlock.numpad.PinKeypadModel
|
||||||
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
|
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||||
|
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class PinUnlockPresenterTest {
|
||||||
|
|
||||||
|
private val halfCompletePin = "12"
|
||||||
|
private val completePin = "1235"
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - complete flow`() = runTest {
|
||||||
|
val presenter = createPinUnlockPresenter(this)
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
awaitItem().also { state ->
|
||||||
|
state.pinEntry.assertEmpty()
|
||||||
|
assertThat(state.showWrongPinTitle).isFalse()
|
||||||
|
assertThat(state.showSignOutPrompt).isFalse()
|
||||||
|
assertThat(state.remainingAttempts).isEqualTo(3)
|
||||||
|
state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('1')))
|
||||||
|
state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('2')))
|
||||||
|
}
|
||||||
|
awaitLastSequentialItem().also { state ->
|
||||||
|
state.pinEntry.assertText(halfCompletePin)
|
||||||
|
state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('3')))
|
||||||
|
state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Back))
|
||||||
|
state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Empty))
|
||||||
|
}
|
||||||
|
awaitLastSequentialItem().also { state ->
|
||||||
|
state.pinEntry.assertText(halfCompletePin)
|
||||||
|
state.eventSink(PinUnlockEvents.OnForgetPin)
|
||||||
|
}
|
||||||
|
awaitLastSequentialItem().also { state ->
|
||||||
|
assertThat(state.showSignOutPrompt).isEqualTo(true)
|
||||||
|
assertThat(state.isSignOutPromptCancellable).isEqualTo(true)
|
||||||
|
state.eventSink(PinUnlockEvents.ClearSignOutPrompt)
|
||||||
|
}
|
||||||
|
awaitLastSequentialItem().also { state ->
|
||||||
|
assertThat(state.showSignOutPrompt).isEqualTo(false)
|
||||||
|
state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('3')))
|
||||||
|
state.eventSink(PinUnlockEvents.OnPinKeypadPressed(PinKeypadModel.Number('5')))
|
||||||
|
}
|
||||||
|
awaitLastSequentialItem().also { state ->
|
||||||
|
state.pinEntry.assertText(completePin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun createPinUnlockPresenter(scope: CoroutineScope): PinUnlockPresenter {
|
||||||
|
val featureFlagService = FakeFeatureFlagService().apply {
|
||||||
|
setFeatureEnabled(FeatureFlags.PinUnlock, true)
|
||||||
|
}
|
||||||
|
val lockScreenStateService = DefaultLockScreenStateService(featureFlagService)
|
||||||
|
return PinUnlockPresenter(
|
||||||
|
lockScreenStateService,
|
||||||
|
scope,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue