diff --git a/.gitignore b/.gitignore index 061d655f6e..20be860f3b 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ sentry.properties # Test users credentials **/users.json **/internal_api.json +**/internal_apis.json # UI Tests Assets backup lockfile scripts/uitests/AssetsFile.lock.bak diff --git a/mail-composer/presentation/src/main/kotlin/ch/protonmail/android/mailcomposer/presentation/mapper/ParticipantMapper.kt b/mail-composer/presentation/src/main/kotlin/ch/protonmail/android/mailcomposer/presentation/mapper/ParticipantMapper.kt index 86ad71eac2..62357de20f 100644 --- a/mail-composer/presentation/src/main/kotlin/ch/protonmail/android/mailcomposer/presentation/mapper/ParticipantMapper.kt +++ b/mail-composer/presentation/src/main/kotlin/ch/protonmail/android/mailcomposer/presentation/mapper/ParticipantMapper.kt @@ -29,7 +29,11 @@ class ParticipantMapper @Inject constructor() { fun recipientUiModelToParticipant(recipient: RecipientUiModel.Valid, contacts: List): Participant { val contactEmail = contacts.firstNotNullOfOrNull { contact -> - contact.contactEmails.find { it.email.equalsNoCase(recipient.address) } + contact.contactEmails.find { + // match by email and fallback to canonical version (fallback only makes sense if we actually + // get canonical version of inputted address from API, it doesn't happen yet) + recipient.address.equalsNoCase(it.email) || recipient.address.equalsNoCase(it.canonicalEmail) + } } return Participant( diff --git a/mail-composer/presentation/src/test/kotlin/ch/protonmail/android/mailcomposer/presentation/mapper/ParticipantMapperTest.kt b/mail-composer/presentation/src/test/kotlin/ch/protonmail/android/mailcomposer/presentation/mapper/ParticipantMapperTest.kt index d1f2fccb71..14bd2dc6b6 100644 --- a/mail-composer/presentation/src/test/kotlin/ch/protonmail/android/mailcomposer/presentation/mapper/ParticipantMapperTest.kt +++ b/mail-composer/presentation/src/test/kotlin/ch/protonmail/android/mailcomposer/presentation/mapper/ParticipantMapperTest.kt @@ -31,6 +31,8 @@ import kotlin.test.assertEquals class ParticipantMapperTest { private val recipientUiModel = RecipientUiModel.Valid("test1@protonmail.com") + private val recipientUiModelNotInContacts = RecipientUiModel.Valid("test_not_in_contacts@protonmail.com") + private val recipientUiModelEmptyNames = RecipientUiModel.Valid("test3@protonmail.com") private val participantMapper = ParticipantMapper() private val contacts = listOf( @@ -40,8 +42,8 @@ class ParticipantMapperTest { ContactEmail( UserIdTestData.userId, ContactEmailId("contact email id 1"), - "First name", - "test1@protonmail.com", + "First name from contact email", + "test1+alias@protonmail.com", 0, 0, ContactIdTestData.contactId1, @@ -51,17 +53,28 @@ class ParticipantMapperTest { ) ), Contact( - UserIdTestData.userId, ContactIdTestData.contactId2, "second contact", + UserIdTestData.userId, ContactIdTestData.contactId2, "", listOf( ContactEmail( UserIdTestData.userId, ContactEmailId("contact email id 2"), - "Second name", + "", "test2@protonmail.com", 0, 0, + ContactIdTestData.contactId2, + "test2@protonmail.com", + emptyList() + ), + ContactEmail( + UserIdTestData.userId, + ContactEmailId("contact email id 3"), + "", + "test3@protonmail.com", + 0, + 0, ContactIdTestData.contactId1, - "test2@protonmail.com", + "test3@protonmail.com", emptyList() ) ) @@ -69,11 +82,11 @@ class ParticipantMapperTest { ) @Test - fun `valid recipient ui model is mapped to participant`() { + fun `valid recipient ui model is mapped to participant, name from ContactEmail`() { // Given val expectedResult = Participant( address = "test1@protonmail.com", - name = "First name", + name = "First name from contact email", isProton = false ) @@ -83,4 +96,36 @@ class ParticipantMapperTest { // Then assertEquals(expectedResult, result) } + + @Test + fun `valid recipient ui model is mapped to participant, Contact names are empty, fallback name to email address`() { + // Given + val expectedResult = Participant( + address = "test_not_in_contacts@protonmail.com", + name = "test_not_in_contacts@protonmail.com", + isProton = false + ) + + // When + val result = participantMapper.recipientUiModelToParticipant(recipientUiModelNotInContacts, contacts) + + // Then + assertEquals(expectedResult, result) + } + + @Test + fun `valid recipient ui model is mapped to participant, not found in Contacts, fallback name to email address`() { + // Given + val expectedResult = Participant( + address = "test3@protonmail.com", + name = "test3@protonmail.com", + isProton = false + ) + + // When + val result = participantMapper.recipientUiModelToParticipant(recipientUiModelEmptyNames, contacts) + + // Then + assertEquals(expectedResult, result) + } } diff --git a/mail-composer/presentation/src/test/kotlin/ch/protonmail/android/mailcomposer/presentation/viewmodel/ComposerViewModelTest.kt b/mail-composer/presentation/src/test/kotlin/ch/protonmail/android/mailcomposer/presentation/viewmodel/ComposerViewModelTest.kt index 2262367655..94c6c52398 100644 --- a/mail-composer/presentation/src/test/kotlin/ch/protonmail/android/mailcomposer/presentation/viewmodel/ComposerViewModelTest.kt +++ b/mail-composer/presentation/src/test/kotlin/ch/protonmail/android/mailcomposer/presentation/viewmodel/ComposerViewModelTest.kt @@ -53,6 +53,7 @@ import ch.protonmail.android.mailmessage.domain.entity.Recipient import ch.protonmail.android.mailmessage.domain.sample.MessageIdSample import ch.protonmail.android.test.utils.rule.LoggingTestRule import ch.protonmail.android.test.utils.rule.MainDispatcherRule +import ch.protonmail.android.testdata.contact.ContactSample import io.mockk.Called import io.mockk.coEvery import io.mockk.coVerify @@ -62,7 +63,6 @@ import io.mockk.mockkObject import io.mockk.unmockkObject import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest -import me.proton.core.contact.domain.entity.Contact import me.proton.core.domain.entity.UserId import me.proton.core.user.domain.entity.UserAddress import kotlin.test.AfterTest @@ -213,18 +213,9 @@ class ComposerViewModelTest { expectedMessageId, expectedSenderEmail, expectedUserId, - expectedTo = expectedRecipients, - expectedCc = null, - expectedBcc = null + expectedTo = expectedRecipients ) - val expectedContacts = emptyList() - coEvery { getContactsMock.invoke(UserIdSample.Primary) } returns expectedContacts.right() - every { - participantMapperMock.recipientUiModelToParticipant( - RecipientUiModel.Valid("valid@email.com"), - expectedContacts - ) - } returns Recipient("valid@email.com", "Valid Email", false) + mockParticipantMapper() // When viewModel.submit(action) @@ -259,18 +250,9 @@ class ComposerViewModelTest { expectedMessageId, expectedSenderEmail, expectedUserId, - expectedTo = null, - expectedCc = expectedRecipients, - expectedBcc = null + expectedCc = expectedRecipients ) - val expectedContacts = emptyList() - coEvery { getContactsMock.invoke(UserIdSample.Primary) } returns expectedContacts.right() - every { - participantMapperMock.recipientUiModelToParticipant( - RecipientUiModel.Valid("valid@email.com"), - expectedContacts - ) - } returns Recipient("valid@email.com", "Valid Email", false) + mockParticipantMapper() // When viewModel.submit(action) @@ -305,18 +287,9 @@ class ComposerViewModelTest { expectedMessageId, expectedSenderEmail, expectedUserId, - expectedTo = null, - expectedCc = null, expectedBcc = expectedRecipients ) - val expectedContacts = emptyList() - coEvery { getContactsMock.invoke(UserIdSample.Primary) } returns expectedContacts.right() - every { - participantMapperMock.recipientUiModelToParticipant( - RecipientUiModel.Valid("valid@email.com"), - expectedContacts - ) - } returns Recipient("valid@email.com", "Valid Email", false) + mockParticipantMapper() // When viewModel.submit(action) @@ -581,14 +554,7 @@ class ComposerViewModelTest { ) { StoreDraftWithRecipients.Error.DraftSaveError } - val expectedContacts = emptyList() - coEvery { getContactsMock.invoke(UserIdSample.Primary) } returns expectedContacts.right() - every { - participantMapperMock.recipientUiModelToParticipant( - RecipientUiModel.Valid("valid@email.com"), - expectedContacts - ) - } returns Recipient("valid@email.com", "Valid Email", false) + mockParticipantMapper() // When viewModel.submit(action) @@ -619,14 +585,7 @@ class ComposerViewModelTest { ) { StoreDraftWithRecipients.Error.DraftSaveError } - val expectedContacts = emptyList() - coEvery { getContactsMock.invoke(UserIdSample.Primary) } returns expectedContacts.right() - every { - participantMapperMock.recipientUiModelToParticipant( - RecipientUiModel.Valid("valid@email.com"), - expectedContacts - ) - } returns Recipient("valid@email.com", "Valid Email", false) + mockParticipantMapper() // When viewModel.submit(action) @@ -657,14 +616,7 @@ class ComposerViewModelTest { ) { StoreDraftWithRecipients.Error.DraftSaveError } - val expectedContacts = emptyList() - coEvery { getContactsMock.invoke(UserIdSample.Primary) } returns expectedContacts.right() - every { - participantMapperMock.recipientUiModelToParticipant( - RecipientUiModel.Valid("valid@email.com"), - expectedContacts - ) - } returns Recipient("valid@email.com", "Valid Email", false) + mockParticipantMapper() // When viewModel.submit(action) @@ -801,9 +753,9 @@ class ComposerViewModelTest { expectedMessageId: MessageId, expectedSenderEmail: SenderEmail, expectedUserId: UserId, - expectedTo: List? = emptyList(), - expectedCc: List? = emptyList(), - expectedBcc: List? = emptyList() + expectedTo: List? = null, + expectedCc: List? = null, + expectedBcc: List? = null ) { coEvery { storeDraftWithRecipientsMock( @@ -852,6 +804,17 @@ class ComposerViewModelTest { } returns Unit } + private fun mockParticipantMapper() { + val expectedContacts = listOf(ContactSample.Doe, ContactSample.John) + coEvery { getContactsMock.invoke(UserIdSample.Primary) } returns expectedContacts.right() + every { + participantMapperMock.recipientUiModelToParticipant( + RecipientUiModel.Valid("valid@email.com"), + expectedContacts + ) + } returns Recipient("valid@email.com", "Valid Email", false) + } + companion object TestData { const val RawDraftBody = "I'm a message body"