271 lines
10 KiB
Kotlin
271 lines
10 KiB
Kotlin
/*
|
|
* Copyright (c) 2022 Proton AG
|
|
*
|
|
* This file is part of Proton Mail.
|
|
*
|
|
* Proton Mail is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Proton Mail is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Proton Mail. If not, see https://www.gnu.org/licenses/.
|
|
*/
|
|
@file:Suppress("UNCHECKED_CAST")
|
|
|
|
package ch.protonmail.android.uitests.robots.mailbox
|
|
|
|
import android.widget.ImageView
|
|
import androidx.annotation.IdRes
|
|
import androidx.recyclerview.widget.RecyclerView
|
|
import androidx.test.espresso.Espresso
|
|
import androidx.test.espresso.Espresso.onView
|
|
import androidx.test.espresso.ViewAction
|
|
import androidx.test.espresso.ViewInteraction
|
|
import androidx.test.espresso.action.ViewActions
|
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
|
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition
|
|
import androidx.test.espresso.matcher.ViewMatchers
|
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
|
import ch.protonmail.android.R
|
|
import ch.protonmail.android.uitests.robots.mailbox.MailboxMatchers.withFirstInstanceMessageSubject
|
|
import ch.protonmail.android.uitests.robots.mailbox.MailboxMatchers.withMessageSubject
|
|
import ch.protonmail.android.uitests.robots.mailbox.MailboxMatchers.withMessageSubjectAndFlag
|
|
import ch.protonmail.android.uitests.robots.mailbox.MailboxMatchers.withMessageSubjectAndRecipient
|
|
import ch.protonmail.android.uitests.robots.mailbox.composer.ComposerRobot
|
|
import ch.protonmail.android.uitests.robots.mailbox.inbox.InboxRobot
|
|
import ch.protonmail.android.uitests.robots.mailbox.messagedetail.MessageRobot
|
|
import ch.protonmail.android.uitests.robots.mailbox.search.SearchRobot
|
|
import ch.protonmail.android.uitests.robots.menu.MenuRobot
|
|
import ch.protonmail.android.uitests.testsHelper.StringUtils
|
|
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.TIMEOUT_15S
|
|
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.TIMEOUT_30S
|
|
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.TIMEOUT_60S
|
|
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.saveMessageSubject
|
|
import ch.protonmail.android.uitests.testsHelper.waitForCondition
|
|
import com.google.android.material.snackbar.SnackbarContentLayout
|
|
import me.proton.fusion.Fusion
|
|
import okhttp3.internal.wait
|
|
|
|
interface MailboxRobotInterface : Fusion {
|
|
|
|
fun swipeLeftMessageAtPosition(position: Int): Any {
|
|
saveMessageSubjectAtPosition(messagesRecyclerViewId, position, (::SetSwipeLeftMessage)())
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
.onItemAtPosition(position)
|
|
.swipeLeft()
|
|
return Any()
|
|
}
|
|
|
|
fun longClickMessageOnPosition(position: Int): Any {
|
|
saveMessageSubjectAtPosition(messagesRecyclerViewId, position, (::SetLongClickMessage)())
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
.onItemAtPosition(position)
|
|
.longClick()
|
|
return Any()
|
|
}
|
|
|
|
fun deleteMessageWithSwipe(subject: String): Any {
|
|
recyclerView.onHolderItem(withMessageSubject(subject)).swipeRight()
|
|
return Any()
|
|
}
|
|
|
|
fun deleteMessageWithSwipe(position: Int): Any {
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
.onItemAtPosition(position)
|
|
.withTimeout(TIMEOUT_15S)
|
|
.swipeRight()
|
|
return Any()
|
|
}
|
|
|
|
fun searchBar(): SearchRobot {
|
|
view.withId(R.id.search).click()
|
|
return SearchRobot()
|
|
}
|
|
|
|
fun compose(): ComposerRobot {
|
|
view.withId(R.id.compose).withTimeout(TIMEOUT_60S).click()
|
|
return ComposerRobot()
|
|
}
|
|
|
|
fun menuDrawer(): MenuRobot {
|
|
waitForCondition(
|
|
{ onView(withId(drawerLayoutId)).check(matches(isDisplayed())) },
|
|
watchTimeout = TIMEOUT_60S
|
|
)
|
|
view.withId(drawerLayoutId).openDrawer()
|
|
return MenuRobot()
|
|
}
|
|
|
|
fun clickMessageByPosition(position: Int): MessageRobot {
|
|
saveMessageSubjectAtPosition(messagesRecyclerViewId, position, (::SetSelectMessage)())
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
// .waitUntilPopulated()
|
|
.onItemAtPosition(position)
|
|
.click()
|
|
return MessageRobot()
|
|
}
|
|
|
|
fun clickMessageBySubject(subject: String): MessageRobot {
|
|
view.withId(R.id.subject_text_view).withText(subject).click()
|
|
return MessageRobot()
|
|
}
|
|
|
|
fun clickFirstMatchedMessageBySubject(subject: String): MessageRobot {
|
|
view.instanceOf(ImageView::class.java).hasParent(view.withId(R.id.mailboxRecyclerView)).checkDoesNotExist()
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
// .waitUntilPopulated()
|
|
.onHolderItem(withFirstInstanceMessageSubject(subject))
|
|
.click()
|
|
return MessageRobot()
|
|
}
|
|
|
|
fun refreshMessageList(): Any {
|
|
// recyclerView.withId(messagesRecyclerViewId).waitUntilPopulated()
|
|
view.withId(messagesRecyclerViewId).swipeDown()
|
|
// Waits for loading icon to disappear
|
|
view.instanceOf(ImageView::class.java).hasParent(view.withId(messagesRecyclerViewId)).checkDoesNotExist()
|
|
// recyclerView.withId(messagesRecyclerViewId).waitUntilPopulated()
|
|
return Any()
|
|
}
|
|
|
|
fun mailboxLayoutShown() {
|
|
// recyclerView.withId(messagesRecyclerViewId).waitUntilPopulated()
|
|
}
|
|
|
|
/**
|
|
* Contains all the validations that can be performed by [InboxRobot].
|
|
*/
|
|
@Suppress("ClassName")
|
|
open class verify : Fusion {
|
|
|
|
fun messageExists(messageSubject: String) {
|
|
view.withId(messageTitleTextViewId).withText(messageSubject).checkIsDisplayed()
|
|
}
|
|
|
|
fun draftWithAttachmentSaved(draftSubject: String) {
|
|
view.withId(messageTitleTextViewId).withText(draftSubject).checkIsDisplayed()
|
|
}
|
|
|
|
fun messageMovedToTrash(subject: String) {
|
|
view.withText(R.string.swipe_action_trash).waitForDisplayed().checkIsDisplayed()
|
|
view.withId(R.id.subject_text_view).withText(subject).waitUntilGone().checkDoesNotExist()
|
|
}
|
|
|
|
fun messageDeleted(subject: String) {
|
|
view.withId(R.id.subject_text_view).withText(subject).checkDoesNotExist()
|
|
}
|
|
|
|
fun multipleMessagesMovedToTrash(subjectMessageOne: String, subjectMessageTwo: String) {
|
|
val messagesMovedToTrash = StringUtils.quantityStringFromResource(R.plurals.action_move_to_trash, 2)
|
|
view.withText(messagesMovedToTrash).waitForDisplayed().checkIsDisplayed()
|
|
view.withId(R.id.subject_text_view).withText(subjectMessageOne).checkDoesNotExist()
|
|
view.withId(R.id.subject_text_view).withText(subjectMessageTwo).checkDoesNotExist()
|
|
}
|
|
|
|
fun multipleMessagesDeleted(subjectMessageOne: String, subjectMessageTwo: String) {
|
|
view.withId(R.id.subject_text_view).withText(subjectMessageOne).checkDoesNotExist()
|
|
view.withId(R.id.subject_text_view).withText(subjectMessageTwo).checkDoesNotExist()
|
|
}
|
|
|
|
fun messageWithSubjectExists(subject: String) {
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
.withTimeout(TIMEOUT_30S)
|
|
.scrollToHolder(withFirstInstanceMessageSubject(subject))
|
|
}
|
|
|
|
fun messageWithSubjectHasRepliedFlag(subject: String) {
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
.scrollToHolder(withMessageSubjectAndFlag(subject, R.id.reply_image_view))
|
|
}
|
|
|
|
fun messageWithSubjectHasRepliedAllFlag(subject: String) {
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
.scrollToHolder(withMessageSubjectAndFlag(subject, R.id.reply_all_image_view))
|
|
}
|
|
|
|
fun messageWithSubjectHasForwardedFlag(subject: String) {
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
.withTimeout(TIMEOUT_30S)
|
|
.scrollToHolder(withMessageSubjectAndFlag(subject, R.id.forward_image_view))
|
|
}
|
|
|
|
fun messageWithSubjectAndRecipientExists(subject: String, to: String) {
|
|
recyclerView
|
|
.withId(messagesRecyclerViewId)
|
|
.scrollToHolder(withMessageSubjectAndRecipient(subject, to))
|
|
}
|
|
}
|
|
|
|
private class SetLongClickMessage : (String, String) -> Unit {
|
|
|
|
override fun invoke(subject: String, date: String) {
|
|
longClickedMessageSubject = subject
|
|
longClickedMessageDate = date
|
|
}
|
|
}
|
|
|
|
private class SetSwipeLeftMessage : (String, String) -> Unit {
|
|
|
|
override fun invoke(subject: String, date: String) {
|
|
swipeLeftMessageSubject = subject
|
|
swipeLeftMessageDate = date
|
|
}
|
|
}
|
|
|
|
private class SetDeleteWithSwipeMessage : (String, String) -> Unit {
|
|
|
|
override fun invoke(subject: String, date: String) {
|
|
deletedMessageSubject = subject
|
|
deletedMessageDate = date
|
|
}
|
|
}
|
|
|
|
class SetSelectMessage : (String, String) -> Unit {
|
|
|
|
override fun invoke(subject: String, date: String) {
|
|
selectedMessageSubject = subject
|
|
selectedMessageDate = date
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
|
|
// TODO replace below line with core test lib code
|
|
fun saveMessageSubjectAtPosition(
|
|
@IdRes recyclerViewId: Int,
|
|
position: Int,
|
|
method: (String, String) -> Unit
|
|
): ViewInteraction = Espresso.onView(ViewMatchers.withId(recyclerViewId))
|
|
.perform(saveMessageSubject(position, method))
|
|
|
|
var longClickedMessageSubject = ""
|
|
var longClickedMessageDate = ""
|
|
var swipeLeftMessageSubject = ""
|
|
var swipeLeftMessageDate = ""
|
|
var selectedMessageSubject = ""
|
|
var selectedMessageDate = ""
|
|
var deletedMessageSubject = ""
|
|
var deletedMessageDate = ""
|
|
|
|
private const val messagesRecyclerViewId = R.id.mailboxRecyclerView
|
|
private const val messageTitleTextViewId = R.id.subject_text_view
|
|
private const val drawerLayoutId = R.id.drawer_layout
|
|
}
|
|
}
|