mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
Remove the send password (#579)
This commit is contained in:
parent
7a6088a23d
commit
3f7fe90c5c
15 changed files with 375 additions and 13 deletions
|
@ -35,4 +35,10 @@ interface SendsApi {
|
|||
*/
|
||||
@DELETE("sends/{sendId}")
|
||||
suspend fun deleteSend(@Path("sendId") sendId: String): Result<Unit>
|
||||
|
||||
/**
|
||||
* Deletes a send.
|
||||
*/
|
||||
@PUT("sends/{sendId}/remove-password")
|
||||
suspend fun removeSendPassword(@Path("sendId") sendId: String): Result<SyncResponseJson.Send>
|
||||
}
|
||||
|
|
|
@ -24,9 +24,16 @@ interface SendsService {
|
|||
): Result<UpdateSendResponseJson>
|
||||
|
||||
/**
|
||||
* Attempt to delete a cipher.
|
||||
* Attempt to delete a send.
|
||||
*/
|
||||
suspend fun deleteSend(
|
||||
sendId: String,
|
||||
): Result<Unit>
|
||||
|
||||
/**
|
||||
* Attempt to remove password protection from a send.
|
||||
*/
|
||||
suspend fun removeSendPassword(
|
||||
sendId: String,
|
||||
): Result<UpdateSendResponseJson>
|
||||
}
|
||||
|
|
|
@ -40,4 +40,18 @@ class SendsServiceImpl(
|
|||
|
||||
override suspend fun deleteSend(sendId: String): Result<Unit> =
|
||||
sendsApi.deleteSend(sendId = sendId)
|
||||
|
||||
override suspend fun removeSendPassword(sendId: String): Result<UpdateSendResponseJson> =
|
||||
sendsApi
|
||||
.removeSendPassword(sendId = sendId)
|
||||
.map { UpdateSendResponseJson.Success(send = it) }
|
||||
.recoverCatching { throwable ->
|
||||
throwable
|
||||
.toBitwardenError()
|
||||
.parseErrorBodyOrNull<UpdateSendResponseJson.Invalid>(
|
||||
code = 400,
|
||||
json = json,
|
||||
)
|
||||
?: throw throwable
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
|||
import com.x8bit.bitwarden.data.vault.manager.VaultLockManager
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.RemovePasswordSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.SendData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.TotpCodeResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
|
@ -151,4 +152,9 @@ interface VaultRepository : VaultLockManager {
|
|||
sendId: String,
|
||||
sendView: SendView,
|
||||
): UpdateSendResult
|
||||
|
||||
/**
|
||||
* Attempt to remove the password from a send.
|
||||
*/
|
||||
suspend fun removePasswordSend(sendId: String): RemovePasswordSendResult
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
|||
import com.x8bit.bitwarden.data.vault.manager.VaultLockManager
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.RemovePasswordSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.SendData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.TotpCodeResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
|
@ -443,6 +444,34 @@ class VaultRepositoryImpl(
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun removePasswordSend(sendId: String): RemovePasswordSendResult {
|
||||
val userId = requireNotNull(activeUserId)
|
||||
return sendsService
|
||||
.removeSendPassword(sendId = sendId)
|
||||
.fold(
|
||||
onSuccess = { response ->
|
||||
when (response) {
|
||||
is UpdateSendResponseJson.Invalid -> {
|
||||
RemovePasswordSendResult.Error(errorMessage = response.message)
|
||||
}
|
||||
|
||||
is UpdateSendResponseJson.Success -> {
|
||||
vaultDiskSource.saveSend(userId = userId, send = response.send)
|
||||
vaultSdkSource
|
||||
.decryptSend(
|
||||
userId = userId,
|
||||
send = response.send.toEncryptedSdkSend(),
|
||||
)
|
||||
.getOrNull()
|
||||
?.let { RemovePasswordSendResult.Success(sendView = it) }
|
||||
?: RemovePasswordSendResult.Error(errorMessage = null)
|
||||
}
|
||||
}
|
||||
},
|
||||
onFailure = { RemovePasswordSendResult.Error(errorMessage = null) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun storeProfileData(
|
||||
syncResponse: SyncResponseJson,
|
||||
) {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.x8bit.bitwarden.data.vault.repository.model
|
||||
|
||||
import com.bitwarden.core.SendView
|
||||
|
||||
/**
|
||||
* Models result of removing the password protection from a send.
|
||||
*/
|
||||
sealed class RemovePasswordSendResult {
|
||||
|
||||
/**
|
||||
* Send has had the password protection successfully removed and contains the decrypted
|
||||
* [SendView].
|
||||
*/
|
||||
data class Success(val sendView: SendView) : RemovePasswordSendResult()
|
||||
|
||||
/**
|
||||
* Generic error while removing the password protection from a send. The optional
|
||||
* [errorMessage] may be displayed directly in the UI when present.
|
||||
*/
|
||||
data class Error(val errorMessage: String?) : RemovePasswordSendResult()
|
||||
}
|
|
@ -32,7 +32,7 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
|||
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.handlers.AddSendHandlers
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
/**
|
||||
* Displays new send UX.
|
||||
|
@ -92,7 +92,7 @@ fun AddSendScreen(
|
|||
)
|
||||
if (!state.isAddMode) {
|
||||
BitwardenOverflowActionItem(
|
||||
menuItemDataList = persistentListOf(
|
||||
menuItemDataList = listOfNotNull(
|
||||
OverflowMenuItemData(
|
||||
text = stringResource(id = R.string.remove_password),
|
||||
onClick = remember(viewModel) {
|
||||
|
@ -102,7 +102,8 @@ fun AddSendScreen(
|
|||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
.takeIf { state.hasPassword },
|
||||
OverflowMenuItemData(
|
||||
text = stringResource(id = R.string.copy_link),
|
||||
onClick = remember(viewModel) {
|
||||
|
@ -121,7 +122,8 @@ fun AddSendScreen(
|
|||
{ viewModel.trySendAction(AddSendAction.DeleteClick) }
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
.toPersistentList(),
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.x8bit.bitwarden.data.platform.repository.util.baseWebSendUrl
|
|||
import com.x8bit.bitwarden.data.platform.repository.util.takeUntilLoaded
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.RemovePasswordSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateSendResult
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
|
@ -70,6 +71,7 @@ class AddSendViewModel @Inject constructor(
|
|||
.plusWeeks(1),
|
||||
expirationDate = null,
|
||||
sendUrl = null,
|
||||
hasPassword = false,
|
||||
),
|
||||
selectedType = AddSendState.ViewState.Content.SendType.Text(
|
||||
input = "",
|
||||
|
@ -139,6 +141,10 @@ class AddSendViewModel @Inject constructor(
|
|||
private fun handleInternalAction(action: AddSendAction.Internal): Unit = when (action) {
|
||||
is AddSendAction.Internal.CreateSendResultReceive -> handleCreateSendResultReceive(action)
|
||||
is AddSendAction.Internal.UpdateSendResultReceive -> handleUpdateSendResultReceive(action)
|
||||
is AddSendAction.Internal.RemovePasswordResultReceive -> handleRemovePasswordResultReceive(
|
||||
action,
|
||||
)
|
||||
|
||||
is AddSendAction.Internal.UserStateReceive -> handleUserStateReceive(action)
|
||||
is AddSendAction.Internal.SendDataReceive -> handleSendDataReceive(action)
|
||||
}
|
||||
|
@ -200,6 +206,32 @@ class AddSendViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleRemovePasswordResultReceive(
|
||||
action: AddSendAction.Internal.RemovePasswordResultReceive,
|
||||
) {
|
||||
when (val result = action.result) {
|
||||
is RemovePasswordSendResult.Error -> {
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
dialogState = AddSendState.DialogState.Error(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = result
|
||||
.errorMessage
|
||||
?.asText()
|
||||
?: R.string.generic_error_message.asText(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is RemovePasswordSendResult.Success -> {
|
||||
updateCommonContent { it.copy(hasPassword = false) }
|
||||
mutableStateFlow.update { it.copy(dialogState = null) }
|
||||
sendEvent(AddSendEvent.ShowToast(message = R.string.send_password_removed.asText()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUserStateReceive(action: AddSendAction.Internal.UserStateReceive) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(isPremiumUser = action.userState?.activeAccount?.isPremium == true)
|
||||
|
@ -288,8 +320,22 @@ class AddSendViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleRemovePasswordClick() {
|
||||
// TODO Add remove password support (BIT-1435)
|
||||
sendEvent(AddSendEvent.ShowToast("Not yet implemented".asText()))
|
||||
when (val addSendType = state.addSendType) {
|
||||
AddSendType.AddItem -> Unit
|
||||
is AddSendType.EditItem -> {
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
dialogState = AddSendState.DialogState.Loading(
|
||||
message = R.string.removing_send_password.asText(),
|
||||
),
|
||||
)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
val result = vaultRepo.removePasswordSend(addSendType.sendItemId)
|
||||
sendAction(AddSendAction.Internal.RemovePasswordResultReceive(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleShareLinkClick() {
|
||||
|
@ -516,6 +562,12 @@ data class AddSendState(
|
|||
*/
|
||||
val isAddMode: Boolean get() = addSendType is AddSendType.AddItem
|
||||
|
||||
/**
|
||||
* Helper to determine if the currently displayed send has a password already set.
|
||||
*/
|
||||
val hasPassword: Boolean
|
||||
get() = (viewState as? ViewState.Content)?.common?.hasPassword == true
|
||||
|
||||
/**
|
||||
* Represents the specific view states for the [AddSendScreen].
|
||||
*/
|
||||
|
@ -566,6 +618,7 @@ data class AddSendState(
|
|||
val deletionDate: ZonedDateTime,
|
||||
val expirationDate: ZonedDateTime?,
|
||||
val sendUrl: String?,
|
||||
val hasPassword: Boolean,
|
||||
) : Parcelable {
|
||||
val dateFormatPattern: String get() = "M/d/yyyy"
|
||||
|
||||
|
@ -767,6 +820,11 @@ sealed class AddSendAction {
|
|||
*/
|
||||
data class UpdateSendResultReceive(val result: UpdateSendResult) : Internal()
|
||||
|
||||
/**
|
||||
* Indicates a result for removing the password from a send has been received.
|
||||
*/
|
||||
data class RemovePasswordResultReceive(val result: RemovePasswordSendResult) : Internal()
|
||||
|
||||
/**
|
||||
* Indicates that the send item data has been received.
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@ fun SendView.toViewState(
|
|||
deletionDate = ZonedDateTime.ofInstant(this.deletionDate, clock.zone),
|
||||
expirationDate = this.expirationDate?.let { ZonedDateTime.ofInstant(it, clock.zone) },
|
||||
sendUrl = this.toSendUrl(baseWebSendUrl),
|
||||
hasPassword = this.hasPassword,
|
||||
),
|
||||
selectedType = when (type) {
|
||||
SendType.TEXT -> {
|
||||
|
|
|
@ -70,6 +70,32 @@ class SendsServiceTest : BaseServiceTest() {
|
|||
val result = sendsService.deleteSend(sendId = "send-id-1")
|
||||
assertEquals(Unit, result.getOrThrow())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeSendPassword with success response should return a Success with the correct send`() =
|
||||
runTest {
|
||||
server.enqueue(MockResponse().setBody(CREATE_UPDATE_SEND_SUCCESS_JSON))
|
||||
val result = sendsService.removeSendPassword(sendId = "send-id-1")
|
||||
assertEquals(
|
||||
UpdateSendResponseJson.Success(send = createMockSend(number = 1)),
|
||||
result.getOrThrow(),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `removeSendPassword with an invalid response should return an Invalid with the correct data`() =
|
||||
runTest {
|
||||
server.enqueue(MockResponse().setResponseCode(400).setBody(UPDATE_SEND_INVALID_JSON))
|
||||
val result = sendsService.removeSendPassword(sendId = "send-id-1")
|
||||
assertEquals(
|
||||
UpdateSendResponseJson.Invalid(
|
||||
message = "You do not have permission to edit this.",
|
||||
validationErrors = null,
|
||||
),
|
||||
result.getOrThrow(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private const val CREATE_UPDATE_SEND_SUCCESS_JSON = """
|
||||
|
|
|
@ -49,6 +49,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSendView
|
|||
import com.x8bit.bitwarden.data.vault.manager.VaultLockManager
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.RemovePasswordSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.SendData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateSendResult
|
||||
|
@ -1591,6 +1592,65 @@ class VaultRepositoryTest {
|
|||
assertEquals(UpdateSendResult.Success(mockSendViewResult), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `removePasswordSend with sendsService removeSendPassword Error should return RemovePasswordSendResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val sendId = "sendId1234"
|
||||
val mockSendView = createMockSendView(number = 1)
|
||||
coEvery {
|
||||
sendsService.removeSendPassword(sendId = sendId)
|
||||
} returns Throwable("Fail").asFailure()
|
||||
|
||||
val result = vaultRepository.removePasswordSend(sendId = sendId)
|
||||
|
||||
assertEquals(RemovePasswordSendResult.Error(errorMessage = null), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `removePasswordSend with sendsService removeSendPassword Success and vaultSdkSource decryptSend Failure should return RemovePasswordSendResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = "mockId-1"
|
||||
val sendId = "sendId1234"
|
||||
val mockSend = createMockSend(number = 1)
|
||||
coEvery {
|
||||
sendsService.removeSendPassword(sendId = sendId)
|
||||
} returns UpdateSendResponseJson.Success(send = mockSend).asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.decryptSend(userId = userId, send = createMockSdkSend(number = 1))
|
||||
} returns Throwable("Fail").asFailure()
|
||||
coEvery { vaultDiskSource.saveSend(userId = userId, send = mockSend) } just runs
|
||||
|
||||
val result = vaultRepository.removePasswordSend(sendId = sendId)
|
||||
|
||||
assertEquals(RemovePasswordSendResult.Error(errorMessage = null), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `removePasswordSend with sendsService removeSendPassword Success should return RemovePasswordSendResult success`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = "mockId-1"
|
||||
val sendId = "sendId1234"
|
||||
val mockSendView = createMockSendView(number = 1)
|
||||
val mockSend = createMockSend(number = 1)
|
||||
coEvery {
|
||||
sendsService.removeSendPassword(sendId = sendId)
|
||||
} returns UpdateSendResponseJson.Success(send = mockSend).asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.decryptSend(userId = userId, send = createMockSdkSend(number = 1))
|
||||
} returns mockSendView.asSuccess()
|
||||
coEvery { vaultDiskSource.saveSend(userId = userId, send = mockSend) } just runs
|
||||
|
||||
val result = vaultRepository.removePasswordSend(sendId = sendId)
|
||||
|
||||
assertEquals(RemovePasswordSendResult.Success(mockSendView), result)
|
||||
}
|
||||
|
||||
//region Helper functions
|
||||
|
||||
/**
|
||||
|
|
|
@ -124,6 +124,24 @@ class AddSendScreenTest : BaseComposeTest() {
|
|||
.isDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `overflow remove password button should be hidden when hasPassword is false`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
addSendType = AddSendType.EditItem(sendItemId = "sendId"),
|
||||
viewState = DEFAULT_VIEW_STATE.copy(
|
||||
common = DEFAULT_COMMON_STATE.copy(hasPassword = false),
|
||||
),
|
||||
)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("More")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Remove password")
|
||||
.assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on overflow remove password button click should send RemovePasswordClick`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
|
@ -790,6 +808,7 @@ class AddSendScreenTest : BaseComposeTest() {
|
|||
deletionDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
|
||||
expirationDate = null,
|
||||
sendUrl = null,
|
||||
hasPassword = true,
|
||||
)
|
||||
|
||||
private val DEFAULT_SELECTED_TYPE_STATE = AddSendState.ViewState.Content.SendType.Text(
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
|||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSendView
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.RemovePasswordSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateSendResult
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
|
@ -292,15 +293,124 @@ class AddSendViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `RemovePasswordClick should send ShowToast`() = runTest {
|
||||
fun `in add item state, RemovePasswordClick should do nothing`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AddSendAction.RemovePasswordClick)
|
||||
expectNoEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `in edit item state, RemovePasswordClick vaultRepository removePasswordSend Error without message should show default error dialog`() =
|
||||
runTest {
|
||||
val sendId = "mockId-1"
|
||||
coEvery {
|
||||
vaultRepository.removePasswordSend(sendId)
|
||||
} returns RemovePasswordSendResult.Error(errorMessage = null)
|
||||
val initialState = DEFAULT_STATE.copy(
|
||||
addSendType = AddSendType.EditItem(sendItemId = sendId),
|
||||
)
|
||||
val mockSendView = createMockSendView(number = 1)
|
||||
every {
|
||||
mockSendView.toViewState(clock, DEFAULT_ENVIRONMENT_URL)
|
||||
} returns DEFAULT_VIEW_STATE
|
||||
mutableSendDataStateFlow.value = DataState.Loaded(mockSendView)
|
||||
val viewModel = createViewModel(
|
||||
state = DEFAULT_STATE.copy(addSendType = AddSendType.EditItem("sendId")),
|
||||
addSendType = AddSendType.EditItem("sendId"),
|
||||
state = initialState,
|
||||
addSendType = AddSendType.EditItem(sendItemId = sendId),
|
||||
)
|
||||
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(initialState, awaitItem())
|
||||
viewModel.trySendAction(AddSendAction.RemovePasswordClick)
|
||||
assertEquals(
|
||||
initialState.copy(
|
||||
dialogState = AddSendState.DialogState.Loading(
|
||||
message = R.string.removing_send_password.asText(),
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
initialState.copy(
|
||||
dialogState = AddSendState.DialogState.Error(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = R.string.generic_error_message.asText(),
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `in edit item state, RemovePasswordClick vaultRepository removePasswordSend Error with message should show error dialog with message`() =
|
||||
runTest {
|
||||
val sendId = "mockId-1"
|
||||
val errorMessage = "Fail"
|
||||
coEvery {
|
||||
vaultRepository.removePasswordSend(sendId)
|
||||
} returns RemovePasswordSendResult.Error(errorMessage = errorMessage)
|
||||
val mockSendView = createMockSendView(number = 1)
|
||||
every {
|
||||
mockSendView.toViewState(clock, DEFAULT_ENVIRONMENT_URL)
|
||||
} returns DEFAULT_VIEW_STATE
|
||||
mutableSendDataStateFlow.value = DataState.Loaded(mockSendView)
|
||||
val initialState = DEFAULT_STATE.copy(
|
||||
addSendType = AddSendType.EditItem(sendItemId = sendId),
|
||||
)
|
||||
val viewModel = createViewModel(
|
||||
state = initialState,
|
||||
addSendType = AddSendType.EditItem(sendItemId = sendId),
|
||||
)
|
||||
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(initialState, awaitItem())
|
||||
viewModel.trySendAction(AddSendAction.RemovePasswordClick)
|
||||
assertEquals(
|
||||
initialState.copy(
|
||||
dialogState = AddSendState.DialogState.Loading(
|
||||
message = R.string.removing_send_password.asText(),
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
initialState.copy(
|
||||
dialogState = AddSendState.DialogState.Error(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = errorMessage.asText(),
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `in edit item state, RemovePasswordClick vaultRepository removePasswordSend Success should show toast`() =
|
||||
runTest {
|
||||
val sendId = "mockId-1"
|
||||
val mockSendView = createMockSendView(number = 1)
|
||||
coEvery {
|
||||
vaultRepository.removePasswordSend(sendId)
|
||||
} returns RemovePasswordSendResult.Success(mockSendView)
|
||||
val viewModel = createViewModel(
|
||||
state = DEFAULT_STATE.copy(addSendType = AddSendType.EditItem(sendItemId = sendId)),
|
||||
addSendType = AddSendType.EditItem(sendItemId = sendId),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AddSendAction.RemovePasswordClick)
|
||||
assertEquals(AddSendEvent.ShowToast("Not yet implemented".asText()), awaitItem())
|
||||
assertEquals(
|
||||
AddSendEvent.ShowToast(R.string.send_password_removed.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -605,6 +715,7 @@ class AddSendViewModelTest : BaseViewModelTest() {
|
|||
deletionDate = ZonedDateTime.parse("2023-11-03T00:00Z"),
|
||||
expirationDate = null,
|
||||
sendUrl = null,
|
||||
hasPassword = false,
|
||||
)
|
||||
|
||||
private val DEFAULT_SELECTED_TYPE_STATE = AddSendState.ViewState.Content.SendType.Text(
|
||||
|
|
|
@ -70,6 +70,7 @@ private val DEFAULT_COMMON_STATE = AddSendState.ViewState.Content.Common(
|
|||
deletionDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
|
||||
expirationDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
|
||||
sendUrl = null,
|
||||
hasPassword = false,
|
||||
)
|
||||
|
||||
private val DEFAULT_SELECTED_TYPE_STATE = AddSendState.ViewState.Content.SendType.Text(
|
||||
|
|
|
@ -60,6 +60,7 @@ private val DEFAULT_COMMON: AddSendState.ViewState.Content.Common =
|
|||
ZoneOffset.UTC,
|
||||
),
|
||||
sendUrl = "www.test.com/mockAccessId-1/mockKey-1",
|
||||
hasPassword = true,
|
||||
)
|
||||
|
||||
private val DEFAULT_TEXT_TYPE: AddSendState.ViewState.Content.SendType.Text =
|
||||
|
|
Loading…
Reference in a new issue