PM-19243 send result errors propagated to UI (#4872)

This commit is contained in:
Dave Severns
2025-03-14 22:01:42 +00:00
committed by GitHub
parent 9ea85917b1
commit db287ddce5
18 changed files with 146 additions and 64 deletions
@@ -21,6 +21,7 @@ import com.x8bit.bitwarden.data.auth.repository.util.toUpdatedUserStateJson
import com.x8bit.bitwarden.data.auth.repository.util.userSwitchingChangesFlow
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
import com.x8bit.bitwarden.data.platform.datasource.network.util.isNoConnectionError
import com.x8bit.bitwarden.data.platform.error.NoActiveUserException
import com.x8bit.bitwarden.data.platform.manager.DatabaseSchemeManager
import com.x8bit.bitwarden.data.platform.manager.PushManager
import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager
@@ -622,7 +623,8 @@ class VaultRepositoryImpl(
sendView: SendView,
fileUri: Uri?,
): CreateSendResult {
val userId = activeUserId ?: return CreateSendResult.Error(message = null)
val userId = activeUserId
?: return CreateSendResult.Error(message = null, error = NoActiveUserException())
return vaultSdkSource
.encryptSend(
userId = userId,
@@ -639,6 +641,7 @@ class VaultRepositoryImpl(
is CreateSendJsonResponse.Invalid -> {
return CreateSendResult.Error(
message = createSendResponse.firstValidationErrorMessage,
error = null,
)
}
@@ -656,7 +659,7 @@ class VaultRepositoryImpl(
)
}
.fold(
onFailure = { CreateSendResult.Error(message = null) },
onFailure = { CreateSendResult.Error(message = null, error = it) },
onSuccess = {
reviewPromptManager.registerCreateSendAction()
CreateSendResult.Success(it)
@@ -668,7 +671,11 @@ class VaultRepositoryImpl(
sendId: String,
sendView: SendView,
): UpdateSendResult {
val userId = activeUserId ?: return UpdateSendResult.Error(null)
val userId = activeUserId
?: return UpdateSendResult.Error(
errorMessage = null,
error = NoActiveUserException(),
)
return vaultSdkSource
.encryptSend(
userId = userId,
@@ -681,11 +688,11 @@ class VaultRepositoryImpl(
)
}
.fold(
onFailure = { UpdateSendResult.Error(errorMessage = null) },
onFailure = { UpdateSendResult.Error(errorMessage = null, error = it) },
onSuccess = { response ->
when (response) {
is UpdateSendResponseJson.Invalid -> {
UpdateSendResult.Error(errorMessage = response.message)
UpdateSendResult.Error(errorMessage = response.message, error = null)
}
is UpdateSendResponseJson.Success -> {
@@ -695,9 +702,12 @@ class VaultRepositoryImpl(
userId = userId,
send = response.send.toEncryptedSdkSend(),
)
.getOrNull()
?.let { UpdateSendResult.Success(sendView = it) }
?: UpdateSendResult.Error(errorMessage = null)
.fold(
onSuccess = { UpdateSendResult.Success(sendView = it) },
onFailure = {
UpdateSendResult.Error(errorMessage = null, error = it)
},
)
}
}
},
@@ -705,14 +715,21 @@ class VaultRepositoryImpl(
}
override suspend fun removePasswordSend(sendId: String): RemovePasswordSendResult {
val userId = activeUserId ?: return RemovePasswordSendResult.Error(null)
val userId = activeUserId
?: return RemovePasswordSendResult.Error(
errorMessage = null,
error = NoActiveUserException(),
)
return sendsService
.removeSendPassword(sendId = sendId)
.fold(
onSuccess = { response ->
when (response) {
is UpdateSendResponseJson.Invalid -> {
RemovePasswordSendResult.Error(errorMessage = response.message)
RemovePasswordSendResult.Error(
errorMessage = response.message,
error = null,
)
}
is UpdateSendResponseJson.Success -> {
@@ -722,24 +739,30 @@ class VaultRepositoryImpl(
userId = userId,
send = response.send.toEncryptedSdkSend(),
)
.getOrNull()
?.let { RemovePasswordSendResult.Success(sendView = it) }
?: RemovePasswordSendResult.Error(errorMessage = null)
.fold(
onSuccess = { RemovePasswordSendResult.Success(sendView = it) },
onFailure = {
RemovePasswordSendResult.Error(
errorMessage = null,
error = it,
)
},
)
}
}
},
onFailure = { RemovePasswordSendResult.Error(errorMessage = null) },
onFailure = { RemovePasswordSendResult.Error(errorMessage = null, error = it) },
)
}
override suspend fun deleteSend(sendId: String): DeleteSendResult {
val userId = activeUserId ?: return DeleteSendResult.Error
val userId = activeUserId ?: return DeleteSendResult.Error(error = NoActiveUserException())
return sendsService
.deleteSend(sendId)
.onSuccess { vaultDiskSource.deleteSend(userId, sendId) }
.fold(
onSuccess = { DeleteSendResult.Success },
onFailure = { DeleteSendResult.Error },
onFailure = { DeleteSendResult.Error(error = it) },
)
}
@@ -15,5 +15,5 @@ sealed class CreateSendResult {
/**
* Generic error while creating a send.
*/
data class Error(val message: String?) : CreateSendResult()
data class Error(val message: String?, val error: Throwable?) : CreateSendResult()
}
@@ -13,5 +13,5 @@ sealed class DeleteSendResult {
/**
* Generic error while deleting a send.
*/
data object Error : DeleteSendResult()
data class Error(val error: Throwable) : DeleteSendResult()
}
@@ -17,5 +17,5 @@ sealed class 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()
data class Error(val errorMessage: String?, val error: Throwable?) : RemovePasswordSendResult()
}
@@ -16,5 +16,5 @@ sealed class UpdateSendResult {
* Generic error while updating a send. The optional [errorMessage] may be displayed directly
* in the UI when present.
*/
data class Error(val errorMessage: String?) : UpdateSendResult()
data class Error(val errorMessage: String?, val error: Throwable?) : UpdateSendResult()
}
@@ -186,6 +186,7 @@ private fun SearchDialogs(
title = dialogState.title?.invoke(),
message = dialogState.message(),
onDismissRequest = onDismissRequest,
throwable = dialogState.throwable,
)
is SearchState.DialogState.Loading -> BitwardenLoadingDialog(
@@ -474,13 +474,14 @@ class SearchViewModel @Inject constructor(
private fun handleDeleteSendResultReceive(
action: SearchAction.Internal.DeleteSendResultReceive,
) {
when (action.result) {
DeleteSendResult.Error -> {
when (val result = action.result) {
is DeleteSendResult.Error -> {
mutableStateFlow.update {
it.copy(
dialogState = SearchState.DialogState.Error(
title = R.string.an_error_has_occurred.asText(),
message = R.string.generic_error_message.asText(),
throwable = result.error,
),
)
}
@@ -857,6 +858,7 @@ data class SearchState(
data class Error(
val title: Text?,
val message: Text,
val throwable: Throwable? = null,
) : DialogState()
/**
@@ -212,6 +212,7 @@ private fun SendDialogs(
title = dialogState.title?.invoke(),
message = dialogState.message(),
onDismissRequest = onDismissRequest,
throwable = dialogState.throwable,
)
is SendState.DialogState.Loading -> BitwardenLoadingDialog(
@@ -140,13 +140,14 @@ class SendViewModel @Inject constructor(
}
private fun handleDeleteSendResultReceive(action: SendAction.Internal.DeleteSendResultReceive) {
when (action.result) {
DeleteSendResult.Error -> {
when (val result = action.result) {
is DeleteSendResult.Error -> {
mutableStateFlow.update {
it.copy(
dialogState = SendState.DialogState.Error(
title = R.string.an_error_has_occurred.asText(),
message = R.string.generic_error_message.asText(),
throwable = result.error,
),
)
}
@@ -465,6 +466,7 @@ data class SendState(
data class Error(
val title: Text?,
val message: Text,
val throwable: Throwable? = null,
) : DialogState()
/**
@@ -255,6 +255,7 @@ private fun AddSendDialogs(
title = dialogState.title?.invoke(),
message = dialogState.message(),
onDismissRequest = onDismissRequest,
throwable = dialogState.throwable,
)
is AddSendState.DialogState.Loading -> BitwardenLoadingDialog(
@@ -192,6 +192,7 @@ class AddSendViewModel @Inject constructor(
title = R.string.an_error_has_occurred.asText(),
message = result.message?.asText()
?: R.string.generic_error_message.asText(),
throwable = result.error,
),
)
}
@@ -222,6 +223,7 @@ class AddSendViewModel @Inject constructor(
.errorMessage
?.asText()
?: R.string.generic_error_message.asText(),
throwable = result.error,
),
)
}
@@ -242,13 +244,14 @@ class AddSendViewModel @Inject constructor(
private fun handleDeleteSendResultReceive(
action: AddSendAction.Internal.DeleteSendResultReceive,
) {
when (action.result) {
when (val result = action.result) {
is DeleteSendResult.Error -> {
mutableStateFlow.update {
it.copy(
dialogState = AddSendState.DialogState.Error(
title = R.string.an_error_has_occurred.asText(),
message = R.string.generic_error_message.asText(),
throwable = result.error,
),
)
}
@@ -275,6 +278,7 @@ class AddSendViewModel @Inject constructor(
.errorMessage
?.asText()
?: R.string.generic_error_message.asText(),
result.error,
),
)
}
@@ -836,6 +840,7 @@ data class AddSendState(
data class Error(
val title: Text?,
val message: Text,
val throwable: Throwable? = null,
) : DialogState()
/**
@@ -317,6 +317,7 @@ private fun VaultItemListingDialogs(
title = dialogState.title?.invoke(),
message = dialogState.message(),
onDismissRequest = onDismissRequest,
throwable = dialogState.throwable,
)
is VaultItemListingState.DialogState.Loading -> BitwardenLoadingDialog(
@@ -1206,13 +1206,14 @@ class VaultItemListingViewModel @Inject constructor(
private fun handleDeleteSendResultReceive(
action: VaultItemListingsAction.Internal.DeleteSendResultReceive,
) {
when (action.result) {
DeleteSendResult.Error -> {
when (val result = action.result) {
is DeleteSendResult.Error -> {
mutableStateFlow.update {
it.copy(
dialogState = VaultItemListingState.DialogState.Error(
title = R.string.an_error_has_occurred.asText(),
message = R.string.generic_error_message.asText(),
throwable = result.error,
),
)
}
@@ -1238,6 +1239,7 @@ class VaultItemListingViewModel @Inject constructor(
.errorMessage
?.asText()
?: R.string.generic_error_message.asText(),
throwable = result.error,
),
)
}
@@ -1310,6 +1312,8 @@ class VaultItemListingViewModel @Inject constructor(
dialogState = VaultItemListingState.DialogState.Error(
title = null,
message = R.string.generic_error_message.asText(),
// TODO PM-19425 update ValidatePasswordResult to propagate error.
throwable = null,
),
)
}
@@ -1322,6 +1326,8 @@ class VaultItemListingViewModel @Inject constructor(
dialogState = VaultItemListingState.DialogState.Error(
title = null,
message = R.string.invalid_master_password.asText(),
// TODO PM-19425 update ValidatePasswordResult to propagate error.
throwable = null,
),
)
}
@@ -2025,6 +2031,7 @@ data class VaultItemListingState(
data class Error(
val title: Text?,
val message: Text,
val throwable: Throwable? = null,
) : DialogState()
/**
@@ -25,6 +25,7 @@ import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager
import com.x8bit.bitwarden.data.auth.repository.util.toSdkParams
import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
import com.x8bit.bitwarden.data.platform.error.NoActiveUserException
import com.x8bit.bitwarden.data.platform.manager.DatabaseSchemeManager
import com.x8bit.bitwarden.data.platform.manager.PushManager
import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager
@@ -109,8 +110,10 @@ import io.mockk.coVerify
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkConstructor
import io.mockk.mockkStatic
import io.mockk.runs
import io.mockk.unmockkConstructor
import io.mockk.unmockkStatic
import io.mockk.verify
import kotlinx.coroutines.flow.Flow
@@ -248,6 +251,10 @@ class VaultRepositoryTest {
mockkStatic(Uri::class)
mockkStatic(MessageDigest::class)
mockkStatic(Base64::class)
mockkConstructor(NoActiveUserException::class)
every {
anyConstructed<NoActiveUserException>() == any<NoActiveUserException>()
} returns true
}
@AfterEach
@@ -256,6 +263,7 @@ class VaultRepositoryTest {
unmockkStatic(Uri::class)
unmockkStatic(MessageDigest::class)
unmockkStatic(Base64::class)
unmockkConstructor(NoActiveUserException::class)
}
@Test
@@ -2116,7 +2124,7 @@ class VaultRepositoryTest {
)
assertEquals(
CreateSendResult.Error(message = null),
CreateSendResult.Error(message = null, error = NoActiveUserException()),
result,
)
}
@@ -2127,13 +2135,14 @@ class VaultRepositoryTest {
fakeAuthDiskSource.userState = MOCK_USER_STATE
val userId = "mockId-1"
val mockSendView = createMockSendView(number = 1)
val error = IllegalStateException()
coEvery {
vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView)
} returns IllegalStateException().asFailure()
} returns error.asFailure()
val result = vaultRepository.createSend(sendView = mockSendView, fileUri = null)
assertEquals(CreateSendResult.Error(message = null), result)
assertEquals(CreateSendResult.Error(message = null, error = error), result)
}
@Test
@@ -2143,6 +2152,7 @@ class VaultRepositoryTest {
fakeAuthDiskSource.userState = MOCK_USER_STATE
val userId = "mockId-1"
val mockSendView = createMockSendView(number = 1, type = SendType.TEXT)
val error = IllegalStateException()
coEvery {
vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView)
} returns createMockSdkSend(number = 1, type = SendType.TEXT).asSuccess()
@@ -2151,11 +2161,11 @@ class VaultRepositoryTest {
body = createMockSendJsonRequest(number = 1, type = SendTypeJson.TEXT)
.copy(fileLength = null),
)
} returns IllegalStateException().asFailure()
} returns error.asFailure()
val result = vaultRepository.createSend(sendView = mockSendView, fileUri = null)
assertEquals(CreateSendResult.Error(IllegalStateException().message), result)
assertEquals(CreateSendResult.Error(message = error.message, error = error), result)
}
@Suppress("MaxLineLength")
@@ -2219,13 +2229,14 @@ class VaultRepositoryTest {
destinationFilePath = "mockAbsolutePath",
)
} returns encryptedFile.asSuccess()
val error = IllegalStateException()
coEvery {
sendsService.createFileSend(body = createMockSendJsonRequest(number = 1))
} returns IllegalStateException().asFailure()
} returns error.asFailure()
val result = vaultRepository.createSend(sendView = mockSendView, fileUri = uri)
assertEquals(CreateSendResult.Error(IllegalStateException().message), result)
assertEquals(CreateSendResult.Error(message = error.message, error = error), result)
}
@Test
@@ -2254,6 +2265,7 @@ class VaultRepositoryTest {
type = SendTypeJson.FILE,
),
)
val error = Throwable()
coEvery {
vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView)
} returns mockSdkSend.asSuccess()
@@ -2284,11 +2296,11 @@ class VaultRepositoryTest {
sendFileResponse = sendFileResponse.createFileJsonResponse,
encryptedFile = encryptedFile,
)
} returns Throwable().asFailure()
} returns error.asFailure()
val result = vaultRepository.createSend(sendView = mockSendView, fileUri = uri)
assertEquals(CreateSendResult.Error(null), result)
assertEquals(CreateSendResult.Error(message = null, error = error), result)
}
@Test
@@ -2301,14 +2313,15 @@ class VaultRepositoryTest {
val uri = setupMockUri(url = url)
val mockSendView = createMockSendView(number = 1)
val mockSdkSend = createMockSdkSend(number = 1)
val error = Throwable()
coEvery {
vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView)
} returns mockSdkSend.asSuccess()
coEvery { fileManager.writeUriToCache(any()) } returns Throwable().asFailure()
coEvery { fileManager.writeUriToCache(any()) } returns error.asFailure()
val result = vaultRepository.createSend(sendView = mockSendView, fileUri = uri)
assertEquals(CreateSendResult.Error(message = null), result)
assertEquals(CreateSendResult.Error(message = null, error = error), result)
}
@Test
@@ -2381,7 +2394,7 @@ class VaultRepositoryTest {
)
assertEquals(
UpdateSendResult.Error(null),
UpdateSendResult.Error(errorMessage = null, error = NoActiveUserException()),
result,
)
}
@@ -2393,16 +2406,17 @@ class VaultRepositoryTest {
val userId = "mockId-1"
val sendId = "sendId1234"
val mockSendView = createMockSendView(number = 1)
val error = IllegalStateException()
coEvery {
vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView)
} returns IllegalStateException().asFailure()
} returns error.asFailure()
val result = vaultRepository.updateSend(
sendId = sendId,
sendView = mockSendView,
)
assertEquals(UpdateSendResult.Error(errorMessage = null), result)
assertEquals(UpdateSendResult.Error(errorMessage = null, error = error), result)
}
@Test
@@ -2416,20 +2430,21 @@ class VaultRepositoryTest {
coEvery {
vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView)
} returns createMockSdkSend(number = 1, type = SendType.TEXT).asSuccess()
val error = IllegalStateException()
coEvery {
sendsService.updateSend(
sendId = sendId,
body = createMockSendJsonRequest(number = 1, type = SendTypeJson.TEXT)
.copy(fileLength = null),
)
} returns IllegalStateException().asFailure()
} returns error.asFailure()
val result = vaultRepository.updateSend(
sendId = sendId,
sendView = mockSendView,
)
assertEquals(UpdateSendResult.Error(errorMessage = null), result)
assertEquals(UpdateSendResult.Error(errorMessage = null, error = error), result)
}
@Test
@@ -2464,6 +2479,7 @@ class VaultRepositoryTest {
assertEquals(
UpdateSendResult.Error(
errorMessage = "You do not have permission to edit this.",
error = null,
),
result,
)
@@ -2488,11 +2504,12 @@ class VaultRepositoryTest {
.copy(fileLength = null),
)
} returns UpdateSendResponseJson.Success(send = mockSend).asSuccess()
val error = Throwable("Fail")
coEvery {
vaultSdkSource.decryptSend(
userId = userId, send = createMockSdkSend(number = 1, type = SendType.TEXT),
)
} returns Throwable("Fail").asFailure()
} returns error.asFailure()
coEvery { vaultDiskSource.saveSend(userId = userId, send = mockSend) } just runs
val result = vaultRepository.updateSend(
@@ -2500,7 +2517,7 @@ class VaultRepositoryTest {
sendView = mockSendView,
)
assertEquals(UpdateSendResult.Error(errorMessage = null), result)
assertEquals(UpdateSendResult.Error(errorMessage = null, error = error), result)
}
@Test
@@ -2549,7 +2566,10 @@ class VaultRepositoryTest {
)
assertEquals(
RemovePasswordSendResult.Error(null),
RemovePasswordSendResult.Error(
errorMessage = null,
error = NoActiveUserException(),
),
result,
)
}
@@ -2560,13 +2580,14 @@ class VaultRepositoryTest {
runTest {
fakeAuthDiskSource.userState = MOCK_USER_STATE
val sendId = "sendId1234"
val error = Throwable("Fail")
coEvery {
sendsService.removeSendPassword(sendId = sendId)
} returns Throwable("Fail").asFailure()
} returns error.asFailure()
val result = vaultRepository.removePasswordSend(sendId = sendId)
assertEquals(RemovePasswordSendResult.Error(errorMessage = null), result)
assertEquals(RemovePasswordSendResult.Error(errorMessage = null, error = error), result)
}
@Test
@@ -2577,17 +2598,18 @@ class VaultRepositoryTest {
val userId = "mockId-1"
val sendId = "sendId1234"
val mockSend = createMockSend(number = 1)
val error = Throwable("Fail")
coEvery {
sendsService.removeSendPassword(sendId = sendId)
} returns UpdateSendResponseJson.Success(send = mockSend).asSuccess()
coEvery {
vaultSdkSource.decryptSend(userId = userId, send = createMockSdkSend(number = 1))
} returns Throwable("Fail").asFailure()
} returns error.asFailure()
coEvery { vaultDiskSource.saveSend(userId = userId, send = mockSend) } just runs
val result = vaultRepository.removePasswordSend(sendId = sendId)
assertEquals(RemovePasswordSendResult.Error(errorMessage = null), result)
assertEquals(RemovePasswordSendResult.Error(errorMessage = null, error = error), result)
}
@Test
@@ -2622,7 +2644,7 @@ class VaultRepositoryTest {
)
assertEquals(
DeleteSendResult.Error,
DeleteSendResult.Error(error = NoActiveUserException()),
result,
)
}
@@ -2632,13 +2654,14 @@ class VaultRepositoryTest {
runTest {
fakeAuthDiskSource.userState = MOCK_USER_STATE
val sendId = "mockId-1"
val error = Throwable("Fail")
coEvery {
sendsService.deleteSend(sendId = sendId)
} returns Throwable("Fail").asFailure()
} returns error.asFailure()
val result = vaultRepository.deleteSend(sendId)
assertEquals(DeleteSendResult.Error, result)
assertEquals(DeleteSendResult.Error(error = error), result)
}
@Test
@@ -715,8 +715,11 @@ class SearchViewModelTest : BaseViewModelTest() {
@Test
fun `OverflowOptionClick Send DeleteClick with deleteSend error should display error dialog`() =
runTest {
val error = Throwable("Ahhh")
val sendId = "sendId1234"
coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error
coEvery {
vaultRepository.deleteSend(sendId)
} returns DeleteSendResult.Error(error = error)
val viewModel = createViewModel()
viewModel.stateFlow.test {
@@ -739,6 +742,7 @@ class SearchViewModelTest : BaseViewModelTest() {
dialogState = SearchState.DialogState.Error(
title = R.string.an_error_has_occurred.asText(),
message = R.string.generic_error_message.asText(),
throwable = error,
),
),
awaitItem(),
@@ -787,7 +791,7 @@ class SearchViewModelTest : BaseViewModelTest() {
val sendId = "sendId1234"
coEvery {
vaultRepository.removePasswordSend(sendId)
} returns RemovePasswordSendResult.Error(errorMessage = null)
} returns RemovePasswordSendResult.Error(errorMessage = null, error = null)
val viewModel = createViewModel()
viewModel.stateFlow.test {
@@ -138,7 +138,8 @@ class SendViewModelTest : BaseViewModelTest() {
val sendItem = mockk<SendState.ViewState.Content.SendItem> {
every { id } returns sendId
}
coEvery { vaultRepo.deleteSend(sendId) } returns DeleteSendResult.Error
val error = Throwable("Oops")
coEvery { vaultRepo.deleteSend(sendId) } returns DeleteSendResult.Error(error = error)
val viewModel = createViewModel()
viewModel.stateFlow.test {
@@ -155,6 +156,7 @@ class SendViewModelTest : BaseViewModelTest() {
dialogState = SendState.DialogState.Error(
title = R.string.an_error_has_occurred.asText(),
message = R.string.generic_error_message.asText(),
throwable = error,
),
),
awaitItem(),
@@ -186,7 +188,7 @@ class SendViewModelTest : BaseViewModelTest() {
}
coEvery {
vaultRepo.removePasswordSend(sendId)
} returns RemovePasswordSendResult.Error(errorMessage = null)
} returns RemovePasswordSendResult.Error(errorMessage = null, error = null)
val viewModel = createViewModel()
viewModel.stateFlow.test {
@@ -242,7 +242,7 @@ class AddSendViewModelTest : BaseViewModelTest() {
every { viewState.toSendView(clock) } returns mockSendView
coEvery {
vaultRepository.createSend(sendView = mockSendView, fileUri = null)
} returns CreateSendResult.Error("Fail")
} returns CreateSendResult.Error(message = "Fail", error = null)
val viewModel = createViewModel(initialState)
viewModel.stateFlow.test {
@@ -337,7 +337,7 @@ class AddSendViewModelTest : BaseViewModelTest() {
every { viewState.toSendView(clock) } returns mockSendView
coEvery {
vaultRepository.updateSend(sendId = sendId, sendView = mockSendView)
} returns UpdateSendResult.Error(errorMessage = errorMessage)
} returns UpdateSendResult.Error(errorMessage = errorMessage, error = null)
mutableSendDataStateFlow.value = DataState.Loaded(mockSendView)
val viewModel = createViewModel(initialState, AddSendType.EditItem(sendId))
@@ -493,7 +493,7 @@ class AddSendViewModelTest : BaseViewModelTest() {
val sendId = "mockId-1"
coEvery {
vaultRepository.removePasswordSend(sendId)
} returns RemovePasswordSendResult.Error(errorMessage = null)
} returns RemovePasswordSendResult.Error(errorMessage = null, error = null)
val initialState = DEFAULT_STATE.copy(
addSendType = AddSendType.EditItem(sendItemId = sendId),
)
@@ -542,7 +542,7 @@ class AddSendViewModelTest : BaseViewModelTest() {
val errorMessage = "Fail"
coEvery {
vaultRepository.removePasswordSend(sendId)
} returns RemovePasswordSendResult.Error(errorMessage = errorMessage)
} returns RemovePasswordSendResult.Error(errorMessage = errorMessage, error = null)
val mockSendView = createMockSendView(number = 1)
every {
mockSendView.toViewState(
@@ -608,8 +608,11 @@ class AddSendViewModelTest : BaseViewModelTest() {
@Test
fun `DeleteClick vaultRepository deleteSend Error should show error dialog`() = runTest {
val error = Throwable("Ooops")
val sendId = "mockId-1"
coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error
coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error(
error = error,
)
val initialState = DEFAULT_STATE.copy(
addSendType = AddSendType.EditItem(sendItemId = sendId),
)
@@ -643,6 +646,7 @@ class AddSendViewModelTest : BaseViewModelTest() {
dialogState = AddSendState.DialogState.Error(
title = R.string.an_error_has_occurred.asText(),
message = R.string.generic_error_message.asText(),
throwable = error,
),
),
awaitItem(),
@@ -1232,7 +1232,10 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
fun `OverflowOptionClick Send DeleteClick with deleteSend error should display error dialog`() =
runTest {
val sendId = "sendId1234"
coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error
val error = Throwable("Oops")
coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error(
error = error,
)
val viewModel = createVaultItemListingViewModel()
viewModel.stateFlow.test {
@@ -1255,6 +1258,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
dialogState = VaultItemListingState.DialogState.Error(
title = R.string.an_error_has_occurred.asText(),
message = R.string.generic_error_message.asText(),
throwable = error,
),
),
awaitItem(),
@@ -1301,9 +1305,10 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
fun `OverflowOptionClick Send RemovePasswordClick with removePasswordSend error should display error dialog`() =
runTest {
val sendId = "sendId1234"
val error = Throwable("Oops")
coEvery {
vaultRepository.removePasswordSend(sendId)
} returns RemovePasswordSendResult.Error(errorMessage = null)
} returns RemovePasswordSendResult.Error(errorMessage = null, error = error)
val viewModel = createVaultItemListingViewModel()
viewModel.stateFlow.test {
@@ -1326,6 +1331,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
dialogState = VaultItemListingState.DialogState.Error(
title = R.string.an_error_has_occurred.asText(),
message = R.string.generic_error_message.asText(),
throwable = error,
),
),
awaitItem(),