PM-19645: Remove new device feature flags (#4950)

This commit is contained in:
David Perez
2025-04-02 12:59:48 +00:00
committed by GitHub
parent a476436bff
commit e5ddeb44fd
14 changed files with 34 additions and 300 deletions
@@ -253,8 +253,6 @@ class AuthRepositoryTest {
}
private val featureFlagManager: FeatureFlagManager = mockk(relaxed = true) {
every { getFeatureFlag(FlagKey.NewDeviceTemporaryDismiss) } returns true
every { getFeatureFlag(FlagKey.NewDevicePermanentDismiss) } returns true
every { getFeatureFlag(FlagKey.OnboardingFlow) } returns false
every { getFeatureFlag(FlagKey.IgnoreEnvironmentCheck) } returns false
}
@@ -1580,7 +1578,6 @@ class AuthRepositoryTest {
coVerify { identityService.preLogin(email = EMAIL) }
}
@Suppress("MaxLineLength")
@Test
fun `prelogin fails should return CertificateError when SSLHandshakeException is thrown`() =
runTest {
@@ -1753,7 +1750,6 @@ class AuthRepositoryTest {
}
@Test
@Suppress("MaxLineLength")
fun `login should return Error result when get token succeeds but unlock vault fails`() =
runTest {
val successResponse = GET_TOKEN_RESPONSE_SUCCESS
@@ -5389,7 +5385,6 @@ class AuthRepositoryTest {
)
}
@Suppress("MaxLineLength")
@Test
fun `getVerifiedOrganizationDomainSsoDetails Success should return Success`() = runTest {
val email = "test@gmail.com"
@@ -5408,6 +5403,7 @@ class AuthRepositoryTest {
assertEquals(
VerifiedOrganizationDomainSsoDetailsResult.Success(
verifiedOrganizationDomainSsoDetails = listOf(
@Suppress("MaxLineLength")
VerifiedOrganizationDomainSsoDetailsResponse.VerifiedOrganizationDomainSsoDetail(
organizationIdentifier = "Test Identifier",
organizationName = "Bitwarden",
@@ -6483,7 +6479,6 @@ class AuthRepositoryTest {
assertNull(fakeAuthDiskSource.getOnboardingStatus(USER_ID_1))
}
@Suppress("MaxLineLength")
@Test
fun `on successful login does not set onboarding status if feature flag is off`() =
runTest {
@@ -6675,28 +6670,6 @@ class AuthRepositoryTest {
assertTrue(shouldShowNewDeviceNotice)
}
@Test
@Suppress("MaxLineLength")
fun `checkUserNeedsNewDeviceTwoFactorNotice NewDeviceTemporaryDismiss and NewDevicePermanentDismiss flags are off returns false`() =
runTest {
every {
featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss)
} returns false
every {
featureFlagManager.getFeatureFlag(FlagKey.NewDeviceTemporaryDismiss)
} returns false
every {
policyManager.getActivePolicies(type = PolicyTypeJson.REQUIRE_SSO)
} returns listOf()
fakeEnvironmentRepository.environment = Environment.Us
fakeAuthDiskSource.userState = SINGLE_USER_STATE_1
val shouldShowNewDeviceNotice = repository.checkUserNeedsNewDeviceTwoFactorNotice()
assertFalse(shouldShowNewDeviceNotice)
}
@Test
@Suppress("MaxLineLength")
fun `checkUserNeedsNewDeviceTwoFactorNotice IgnoreEnvironmentCheck flag enabled should not check for a cloud environment and return true`() =
@@ -6719,7 +6692,6 @@ class AuthRepositoryTest {
}
@Test
@Suppress("MaxLineLength")
fun `checkUserNeedsNewDeviceTwoFactorNotice if environment is selfhosted return false`() =
runTest {
every {
@@ -6890,7 +6862,7 @@ class AuthRepositoryTest {
@Test
@Suppress("MaxLineLength")
fun `checkUserNeedsNewDeviceTwoFactorNotice with NewDeviceNoticeDisplayStatus CAN_ACCESS_EMAIL return permanent flag value`() =
fun `checkUserNeedsNewDeviceTwoFactorNotice with NewDeviceNoticeDisplayStatus CAN_ACCESS_EMAIL return true`() =
runTest {
every {
policyManager.getActivePolicies(type = PolicyTypeJson.REQUIRE_SSO)
@@ -6907,12 +6879,6 @@ class AuthRepositoryTest {
)
assertTrue(repository.checkUserNeedsNewDeviceTwoFactorNotice())
every {
featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss)
} returns false
assertFalse(repository.checkUserNeedsNewDeviceTwoFactorNotice())
}
@Test
@@ -49,14 +49,6 @@ class FlagKeyTest {
FlagKey.CipherKeyEncryption.keyName,
"cipher-key-encryption",
)
assertEquals(
FlagKey.NewDeviceTemporaryDismiss.keyName,
"new-device-temporary-dismiss",
)
assertEquals(
FlagKey.NewDevicePermanentDismiss.keyName,
"new-device-permanent-dismiss",
)
assertEquals(
FlagKey.SingleTapPasskeyCreation.keyName,
"single-tap-passkey-creation",
@@ -104,8 +96,6 @@ class FlagKeyTest {
FlagKey.CredentialExchangeProtocolImport,
FlagKey.CredentialExchangeProtocolExport,
FlagKey.AppReviewPrompt,
FlagKey.NewDeviceTemporaryDismiss,
FlagKey.NewDevicePermanentDismiss,
FlagKey.SingleTapPasskeyCreation,
FlagKey.SingleTapPasskeyAuthentication,
FlagKey.AnonAddySelfHostAlias,
@@ -134,8 +124,6 @@ class FlagKeyTest {
FlagKey.CredentialExchangeProtocolExport,
FlagKey.AppReviewPrompt,
FlagKey.CipherKeyEncryption,
FlagKey.NewDeviceTemporaryDismiss,
FlagKey.NewDevicePermanentDismiss,
FlagKey.SingleTapPasskeyCreation,
FlagKey.SingleTapPasskeyAuthentication,
FlagKey.MutualTls,
@@ -5,8 +5,6 @@ import app.cash.turbine.test
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeDisplayStatus
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeState
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
import io.mockk.every
@@ -28,11 +26,6 @@ class NewDeviceNoticeEmailAccessViewModelTest : BaseViewModelTest() {
every { checkUserNeedsNewDeviceTwoFactorNotice() } returns true
}
private val featureFlagManager = mockk<FeatureFlagManager>(relaxed = true) {
every { getFeatureFlag(FlagKey.NewDevicePermanentDismiss) } returns true
every { getFeatureFlag(FlagKey.NewDeviceTemporaryDismiss) } returns true
}
private val vaultRepository = mockk<VaultRepository>(relaxed = true)
@Test
@@ -97,33 +90,6 @@ class NewDeviceNoticeEmailAccessViewModelTest : BaseViewModelTest() {
}
}
@Test
@Suppress("MaxLineLength")
fun `ContinueClick should emit NavigateBackToVault if isEmailAccessEnabled and NewDevicePermanentDismiss flag is off`() =
runTest {
every {
featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss)
} returns false
val viewModel = createViewModel()
viewModel.trySendAction(NewDeviceNoticeEmailAccessAction.EmailAccessToggle(true))
viewModel.eventFlow.test {
viewModel.trySendAction(NewDeviceNoticeEmailAccessAction.ContinueClick)
assertEquals(
NewDeviceNoticeEmailAccessEvent.NavigateBackToVault,
awaitItem(),
)
verify(exactly = 1) {
authRepository.setNewDeviceNoticeState(
NewDeviceNoticeState(
displayStatus = NewDeviceNoticeDisplayStatus.CAN_ACCESS_EMAIL,
lastSeenDate = null,
),
)
}
}
}
@Test
fun `ContinueClick should emit NavigateToTwoFactorOptions if isEmailAccessEnabled is false`() =
runTest {
@@ -138,14 +104,13 @@ class NewDeviceNoticeEmailAccessViewModelTest : BaseViewModelTest() {
}
@Test
fun `LearnMoreClick should emit NavigateToLearnMore`() =
runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(NewDeviceNoticeEmailAccessAction.LearnMoreClick)
assertEquals(NewDeviceNoticeEmailAccessEvent.NavigateToLearnMore, awaitItem())
}
fun `LearnMoreClick should emit NavigateToLearnMore`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(NewDeviceNoticeEmailAccessAction.LearnMoreClick)
assertEquals(NewDeviceNoticeEmailAccessEvent.NavigateToLearnMore, awaitItem())
}
}
private fun createViewModel(
savedStateHandle: SavedStateHandle = SavedStateHandle().also {
@@ -153,7 +118,6 @@ class NewDeviceNoticeEmailAccessViewModelTest : BaseViewModelTest() {
},
): NewDeviceNoticeEmailAccessViewModel = NewDeviceNoticeEmailAccessViewModel(
authRepository = authRepository,
featureFlagManager = featureFlagManager,
vaultRepository = vaultRepository,
savedStateHandle = savedStateHandle,
)
@@ -94,19 +94,6 @@ class NewDeviceNoticeTwoFactorScreenTest : BaseComposeTest() {
}
}
@Test
fun `Remind me later click should send RemindMeLaterClick action`() {
composeTestRule
.onNodeWithText("Remind me later")
.performScrollTo()
.performClick()
verify(exactly = 1) {
viewModel.trySendAction(
NewDeviceNoticeTwoFactorAction.RemindMeLaterClick,
)
}
}
@Test
fun `on NavigateToTurnOnTwoFactor should call launchUri on IntentManager`() {
mutableEventFlow.tryEmit(
@@ -144,22 +131,6 @@ class NewDeviceNoticeTwoFactorScreenTest : BaseComposeTest() {
}
@Test
fun `remind me later button visibility should update according to state`() {
composeTestRule
.onNodeWithText("Remind me later")
.performScrollTo()
.assertIsDisplayed()
mutableStateFlow.update {
it.copy(shouldShowRemindMeLater = false)
}
composeTestRule
.onNodeWithText("Remind me later")
.assertDoesNotExist()
}
@Test
@Suppress("MaxLineLength")
fun `turn on two factor dialog should be shown or hidden according to the state`() {
composeTestRule.onNode(isDialog()).assertDoesNotExist()
@@ -175,9 +146,10 @@ class NewDeviceNoticeTwoFactorScreenTest : BaseComposeTest() {
.onNodeWithText("Continue to web app", substring = true, ignoreCase = true)
.assert(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
@Suppress("MaxLineLength")
composeTestRule
.onNodeWithText(
"Make your account more secure by setting up two-step login in the Bitwarden web app.",
text = "Make your account more secure by setting up two-step login in the Bitwarden web app.",
substring = true,
ignoreCase = true,
)
@@ -251,6 +223,5 @@ class NewDeviceNoticeTwoFactorScreenTest : BaseComposeTest() {
private val DEFAULT_STATE =
NewDeviceNoticeTwoFactorState(
shouldShowRemindMeLater = true,
dialogState = null,
)
@@ -1,11 +1,7 @@
package com.x8bit.bitwarden.ui.auth.feature.newdevicenotice
import app.cash.turbine.test
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeDisplayStatus
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeState
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
@@ -18,10 +14,6 @@ import io.mockk.verify
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.time.Clock
import java.time.Instant
import java.time.ZoneOffset
import java.time.ZonedDateTime
class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
private val environmentRepository = FakeEnvironmentRepository()
@@ -29,35 +21,18 @@ class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
every { checkUserNeedsNewDeviceTwoFactorNotice() } returns true
}
private val featureFlagManager = mockk<FeatureFlagManager>(relaxed = true) {
every { getFeatureFlag(FlagKey.NewDevicePermanentDismiss) } returns false
every { getFeatureFlag(FlagKey.NewDeviceTemporaryDismiss) } returns true
}
private val settingsRepository = mockk<SettingsRepository>(relaxed = true)
private val vaultRepository = mockk<VaultRepository>(relaxed = true)
@Test
fun `initial state should be correct with NewDevicePermanentDismiss flag false`() = runTest {
fun `initial state should be correct`() = runTest {
val viewModel = createViewModel()
viewModel.stateFlow.test {
assertEquals(DEFAULT_STATE, awaitItem())
}
}
@Test
fun `initial state should be correct with NewDevicePermanentDismiss flag true`() = runTest {
every { featureFlagManager.getFeatureFlag(FlagKey.NewDevicePermanentDismiss) } returns true
val viewModel = createViewModel()
viewModel.stateFlow.test {
assertEquals(
DEFAULT_STATE.copy(shouldShowRemindMeLater = false),
awaitItem(),
)
}
}
@Test
fun `Init should not send events if user needs new device notice`() = runTest {
every { authRepository.checkUserNeedsNewDeviceTwoFactorNotice() } returns true
@@ -126,26 +101,6 @@ class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
}
}
@Test
fun `RemindMeLaterClick should emit NavigateBackToVault`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(NewDeviceNoticeTwoFactorAction.RemindMeLaterClick)
assertEquals(
NewDeviceNoticeTwoFactorEvent.NavigateBackToVault,
awaitItem(),
)
verify(exactly = 1) {
authRepository.setNewDeviceNoticeState(
NewDeviceNoticeState(
displayStatus = NewDeviceNoticeDisplayStatus.HAS_SEEN,
lastSeenDate = ZonedDateTime.now(FIXED_CLOCK),
),
)
}
}
}
@Test
fun `NavigateBackClick should send NavigateBack event`() = runTest {
val viewModel = createViewModel()
@@ -207,7 +162,6 @@ class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
}
@Test
@Suppress("MaxLineLength")
fun `ContinueDialogClick should return if dialog state is null`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
@@ -223,20 +177,12 @@ class NewDeviceNoticeTwoFactorViewModelTest : BaseViewModelTest() {
NewDeviceNoticeTwoFactorViewModel(
authRepository = authRepository,
environmentRepository = environmentRepository,
featureFlagManager = featureFlagManager,
settingsRepository = settingsRepository,
vaultRepository = vaultRepository,
clock = FIXED_CLOCK,
)
}
private val DEFAULT_STATE =
NewDeviceNoticeTwoFactorState(
shouldShowRemindMeLater = true,
dialogState = null,
)
private val FIXED_CLOCK: Clock = Clock.fixed(
Instant.parse("2023-10-27T12:00:00Z"),
ZoneOffset.UTC,
)
@@ -129,8 +129,6 @@ private val DEFAULT_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf
FlagKey.CredentialExchangeProtocolImport to true,
FlagKey.CredentialExchangeProtocolExport to true,
FlagKey.AppReviewPrompt to true,
FlagKey.NewDeviceTemporaryDismiss to true,
FlagKey.NewDevicePermanentDismiss to true,
FlagKey.IgnoreEnvironmentCheck to true,
FlagKey.MutualTls to true,
FlagKey.SingleTapPasskeyCreation to true,
@@ -152,8 +150,6 @@ private val UPDATED_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf
FlagKey.CredentialExchangeProtocolImport to false,
FlagKey.CredentialExchangeProtocolExport to false,
FlagKey.AppReviewPrompt to false,
FlagKey.NewDeviceTemporaryDismiss to false,
FlagKey.NewDevicePermanentDismiss to false,
FlagKey.IgnoreEnvironmentCheck to false,
FlagKey.MutualTls to false,
FlagKey.SingleTapPasskeyCreation to false,