Regression test suite.

Affected: UI tests, Reply, ReplyAll and Forward message functionality (buttons are enabled after message is decrypted).

MAILAND-1041
This commit is contained in:
denys zelenchuk 2020-10-12 14:27:38 +02:00 committed by Zorica Stojchevska
parent 418429d78e
commit c4a0f26283
34 changed files with 625 additions and 421 deletions

View File

@ -30,6 +30,8 @@ stages:
#####################
.detekt-analysis-common:
stage: analyze
except:
- schedules
tags:
- android
script:
@ -52,6 +54,7 @@ detekt analysis:
- release
- prerelease
- tags
- schedules
build debug:
stage: build
@ -67,6 +70,8 @@ build debug:
build prerelease:
stage: build
except:
- schedules
only:
- prerelease
- tags
@ -81,6 +86,8 @@ build prerelease:
build release:
stage: build
except:
- schedules
only:
- releases
tags:
@ -95,6 +102,8 @@ build release:
unit tests:
stage: test
except:
- schedules
tags:
- android
script:
@ -103,6 +112,8 @@ unit tests:
firebase tests:
stage: test
except:
- schedules
script:
- wget --quiet --output-document=/tmp/google-cloud-sdk.tar.gz https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz
- mkdir -p /opt
@ -121,13 +132,57 @@ firebase tests:
--test-targets "class ch.protonmail.android.uitests.tests.suites.SmokeSuite"
--use-orchestrator
--num-flaky-test-attempts=2
--timeout 30m
#UI tests:
# stage: test
# tags:
# - android
# script:
# - ./gradlew eBDTOB -PUSER1="$USER1" -PUSER2="$USER2" -PUSER3="$USER3" -PUSER4="$USER4" -PRECIPIENT1="$RECIPIENT1" -PRECIPIENT2="$RECIPIENT2" -PRECIPIENT3="$RECIPIENT3" -PRECIPIENT4="$RECIPIENT4" -PBROWSERSTACK_USER="$BROWSERSTACK_USER" -PBROWSERSTACK_KEY="$BROWSERSTACK_KEY"
firebase regression tests:
stage: test
rules:
- if: '$TEST_TYPE == "regression"'
script:
- wget --quiet --output-document=/tmp/google-cloud-sdk.tar.gz https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz
- mkdir -p /opt
- tar zxf /tmp/google-cloud-sdk.tar.gz --directory /opt
- /opt/google-cloud-sdk/install.sh --quiet
- source /opt/google-cloud-sdk/path.bash.inc
- gcloud components update
- echo $CLOUD_PROJECT_ID_MAIL
- gcloud config set project $CLOUD_PROJECT_ID_MAIL
- echo $SERVICE_ACCOUNT_MAIL > /tmp/service-account.json
- gcloud auth activate-service-account --key-file /tmp/service-account.json
- export CLOUDSDK_CORE_DISABLE_PROMPTS=1
- gcloud beta --quiet firebase test android run
--app app/build/outputs/apk/beta/debug/ProtonMail-Android-${VERSION_NAME}-beta-debug.apk
--test app/build/outputs/apk/androidTest/beta/debug/ProtonMail-Android-${VERSION_NAME}-beta-debug-androidTest.apk
--device model=Pixel2,version=$API_LEVEL
--test-targets "class ch.protonmail.android.uitests.tests.suites.RegressionSuite"
--use-orchestrator
--num-uniform-shards=20
--timeout 1h
firebase feature tests:
stage: test
rules:
- if: '$TEST_TYPE == "feature"'
script:
- wget --quiet --output-document=/tmp/google-cloud-sdk.tar.gz https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz
- mkdir -p /opt
- tar zxf /tmp/google-cloud-sdk.tar.gz --directory /opt
- /opt/google-cloud-sdk/install.sh --quiet
- source /opt/google-cloud-sdk/path.bash.inc
- gcloud components update
- echo $CLOUD_PROJECT_ID_MAIL
- gcloud config set project $CLOUD_PROJECT_ID_MAIL
- echo $SERVICE_ACCOUNT_MAIL > /tmp/service-account.json
- gcloud auth activate-service-account --key-file /tmp/service-account.json
- export CLOUDSDK_CORE_DISABLE_PROMPTS=1
- gcloud --quiet firebase test android run
--app app/build/outputs/apk/beta/debug/ProtonMail-Android-${VERSION_NAME}-beta-debug.apk
--test app/build/outputs/apk/androidTest/beta/debug/ProtonMail-Android-${VERSION_NAME}-beta-debug-androidTest.apk
--device model=Pixel2,version=$API_LEVEL
--test-targets "class ch.protonmail.android.uitests.tests.$TEST_CLASS"
--use-orchestrator
--num-flaky-test-attempts=1
--timeout 1h
include:
- project: 'translations/generator'
@ -147,13 +202,18 @@ i18n-sync-crowdin:
variables:
I18N_SYNC_CROWDIN_PROJECT: 'android-mail'
extends: .i18n-sync-crowdin-shared
except:
variables:
- $TEST_TYPE == "feature" || $TEST_TYPE == "regression"
i18n-commit-locales:
stage: bot-i18n
variables:
I18N_COMMIT_CROWDIN_PROJECT: 'android-mail'
extends: .i18n-commit-locales-shared
except:
variables:
- $TEST_TYPE == "feature" || $TEST_TYPE == "regression"
release-publish-github:
stage: manual-release
@ -185,5 +245,3 @@ publish-github:
RELEASE_GITHUB_REPOSITORY: ProtonMail/proton-mail-android
RELEASE_GITHUB_BRANCH: 'release'
extends: .release-make-release

View File

@ -102,6 +102,7 @@ import ch.protonmail.android.utils.ui.MODE_ACCORDION
import ch.protonmail.android.utils.ui.dialogs.DialogUtils.Companion.showDeleteConfirmationDialog
import ch.protonmail.android.utils.ui.dialogs.DialogUtils.Companion.showInfoDialogWithTwoButtons
import ch.protonmail.android.utils.ui.dialogs.DialogUtils.Companion.showSignedInSnack
import ch.protonmail.android.views.MessageActionButton
import ch.protonmail.android.views.PMWebViewClient
import ch.protonmail.android.worker.KEY_POST_LABEL_WORKER_RESULT_ERROR
import ch.protonmail.android.worker.PostLabelWorker
@ -205,6 +206,10 @@ internal class MessageDetailsActivity :
} else {
continueSetup()
}
findViewById<MessageActionButton>(R.id.reply).isEnabled = false
findViewById<MessageActionButton>(R.id.reply_all).isEnabled = false
findViewById<MessageActionButton>(R.id.forward).isEnabled = false
}
private fun continueSetup() {
@ -870,6 +875,10 @@ internal class MessageDetailsActivity :
UiUtil.showInfoSnack(mSnackLayout, this@MessageDetailsActivity, R.string.decryption_error_desc).show()
return
}
findViewById<MessageActionButton>(R.id.reply).isEnabled = true
findViewById<MessageActionButton>(R.id.reply_all).isEnabled = true
findViewById<MessageActionButton>(R.id.forward).isEnabled = true
messageExpandableAdapter.setMessageData(message)
messageExpandableAdapter.refreshRecipientsLayout()
if (viewModel.refreshedKeys) {

View File

@ -277,7 +277,7 @@ class ProtonRetrofitSecure(
endpointUri,
TEN_SECONDS,
interceptor,
HttpLoggingInterceptor.Level.BODY,
HttpLoggingInterceptor.Level.BASIC,
spec,
serverTimeInterceptor
)

View File

@ -52,7 +52,6 @@ class AddContactRobot {
private fun save(): ContactsRobot {
UIActions.id.clickViewWithId(R.id.action_save)
UIActions.wait.forViewWithText(R.string.contact_saved)
return ContactsRobot()
}
}

View File

@ -123,8 +123,12 @@ object ContactsMatchers {
return object : BoundedMatcher<RecyclerView.ViewHolder,
RecyclerView.ViewHolder>(RecyclerView.ViewHolder::class.java) {
val contactGroupsList = ArrayList<String>()
override fun describeTo(description: Description) {
description.appendText("With contact group name: \"$name\"")
description.appendText("Here is the actual list of groups:\n")
contactGroupsList.forEach { description.appendText(" - \"$it\"\n") }
}
override fun matchesSafely(item: RecyclerView.ViewHolder): Boolean {
@ -135,6 +139,7 @@ object ContactsMatchers {
.findViewById<TextView>(R.id.contact_name).text.toString()
val groupMembersCount = contactDataParent
.findViewById<TextView>(R.id.contact_email).text.toString()
contactGroupsList.add(groupName)
return groupName == name && groupMembersCount == membersCount
}
}

View File

@ -34,7 +34,7 @@ import org.hamcrest.CoreMatchers.instanceOf
/**
* [ContactsRobot] class contains actions and verifications for Contacts functionality.
*/
open class ContactsRobot {
class ContactsRobot {
fun addContact(): AddContactRobot {
UIActions.allOf.clickMatchedView(
@ -60,7 +60,7 @@ open class ContactsRobot {
fun openOptionsMenu(): ContactsMoreOptions {
UIActions.system.clickMoreOptionsButton()
UIActions.system.waitForMoreOptionsButton().click()
return ContactsMoreOptions()
}
@ -81,10 +81,10 @@ open class ContactsRobot {
}
fun clickContactByEmail(email: String): ContactDetailsRobot {
UIActions.wait.forViewWithId(contactsRecyclerView)
UIActions.recyclerView
.waitForBeingPopulated(contactsRecyclerView)
.waitForItemWithIdAndText(contactsRecyclerView, R.id.contact_email, email)
.clickContactItem(contactsRecyclerView, email)
.clickContactItemWithRetry(contactsRecyclerView, email)
return ContactDetailsRobot()
}
@ -95,6 +95,12 @@ open class ContactsRobot {
return ContactDetailsRobot()
}
fun navigateUpToInbox(): InboxRobot {
UIActions.wait.forViewWithId(contactsRecyclerView)
UIActions.system.clickHamburgerOrUpButton()
return InboxRobot()
}
fun clickSendMessageToContact(contactName: String): ComposerRobot {
UIActions.recyclerView
.waitForBeingPopulated(contactsRecyclerView)
@ -109,6 +115,12 @@ open class ContactsRobot {
class ContactsGroupView {
fun navigateUpToInbox(): InboxRobot {
UIActions.wait.forViewWithId(contactGroupsRecyclerView)
UIActions.system.clickHamburgerOrUpButton()
return InboxRobot()
}
fun clickGroup(withName: String): GroupDetailsRobot {
UIActions.recyclerView
.waitForBeingPopulated(R.id.contactGroupsRecyclerView)
@ -117,10 +129,10 @@ open class ContactsRobot {
}
fun clickGroupWithMembersCount(name: String, membersCount: String): GroupDetailsRobot {
UIActions.wait.forViewWithId(contactGroupsRecyclerView)
UIActions.recyclerView
.waitForBeingPopulated(contactGroupsRecyclerView)
.waitForItemWithIdAndText(contactGroupsRecyclerView, R.id.contact_name, name)
.clickOnRecyclerViewMatchedItem(
.clickOnRecyclerViewMatchedItemWithRetry(
contactGroupsRecyclerView,
withContactGroupNameAndMembersCount(name, membersCount)
)
@ -177,19 +189,17 @@ open class ContactsRobot {
fun contactExists(name: String, email: String) {
UIActions.recyclerView
.waitForBeingPopulated(contactsRecyclerView)
.scrollToRecyclerViewMatchedItem(contactsRecyclerView, withContactNameAndEmail(name, email))
}
fun contactDoesNotExists(name: String, email: String) {
UIActions.wait.forViewWithId(contactsRecyclerView)
UIActions.recyclerView
.waitForBeingPopulated(contactsRecyclerView)
.checkDoesNotContainContact(contactsRecyclerView, name, email)
}
fun contactsRefreshed() {
UIActions.wait.forViewWithText(R.string.fetching_contacts)
UIActions.wait.untilViewWithIdIsGone(R.id.progress_bar)
UIActions.wait.untilViewWithIdDisabled(R.id.progress_bar)
}
}

View File

@ -50,7 +50,7 @@ open class GroupDetailsRobot {
}
private fun confirmDeletion(): ContactsRobot {
UIActions.system.clickPositiveDialogButton()
UIActions.wait.forViewWithId(android.R.id.button1).click()
return ContactsRobot()
}

View File

@ -22,6 +22,7 @@ import ch.protonmail.android.R
import ch.protonmail.android.uitests.robots.mailbox.inbox.InboxRobot
import ch.protonmail.android.uitests.testsHelper.UIActions
import ch.protonmail.android.uitests.testsHelper.User
import ch.protonmail.android.uitests.testsHelper.click
import ch.protonmail.android.uitests.testsHelper.insert
/**
@ -88,12 +89,12 @@ class LoginRobot {
}
private fun confirm2Fa(): InboxRobot {
UIActions.system.clickPositiveDialogButton()
UIActions.wait.forViewWithId(android.R.id.button1).click()
return InboxRobot()
}
private fun confirm2FaMailbox(): MailboxPasswordRobot {
UIActions.system.clickPositiveDialogButton()
UIActions.wait.untilViewWithIdEnabled(android.R.id.button1).click()
return MailboxPasswordRobot()
}

View File

@ -35,6 +35,7 @@ import ch.protonmail.android.uitests.robots.mailbox.search.SearchRobot
import ch.protonmail.android.uitests.robots.menu.MenuRobot
import ch.protonmail.android.uitests.testsHelper.UIActions
import ch.protonmail.android.uitests.testsHelper.click
import ch.protonmail.android.uitests.testsHelper.swipeViewDown
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.instanceOf
@ -75,7 +76,7 @@ interface MailboxRobotInterface {
}
fun menuDrawer(): MenuRobot {
UIActions.wait.forViewWithId(drawerLayoutId)
UIActions.wait.forViewWithId(drawerLayoutId, 15_000L)
UIActions.id.openMenuDrawerWithId(drawerLayoutId)
return MenuRobot()
}
@ -88,13 +89,6 @@ interface MailboxRobotInterface {
}
fun clickMessageBySubject(subject: String): MessageRobot {
UIActions.wait
.forViewByViewInteraction(onView(
allOf(
instanceOf(ImageView::class.java),
withParent(withId(R.id.messages_list_view))
)
))
UIActions.wait
.untilViewByViewInteractionIsGone(onView(
allOf(
@ -108,6 +102,11 @@ interface MailboxRobotInterface {
return MessageRobot()
}
fun refreshMessageList(): Any {
UIActions.wait.forViewWithId(messagesRecyclerViewId).swipeViewDown()
return Any()
}
/**
* Contains all the validations that can be performed by [InboxRobot].
*/

View File

@ -33,6 +33,7 @@ import ch.protonmail.android.uitests.testsHelper.TestData
import ch.protonmail.android.uitests.testsHelper.UIActions
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.setValueInNumberPicker
import ch.protonmail.android.uitests.testsHelper.click
import ch.protonmail.android.uitests.testsHelper.insert
import ch.protonmail.android.uitests.testsHelper.type
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.allOf
@ -54,15 +55,21 @@ class ComposerRobot {
.body(body)
.sendToContact()
fun sendMessageToGroup(subject: String, body: String): ContactsRobot.ContactsGroupView {
subject(subject)
.body(body)
.sendToContact()
return ContactsRobot.ContactsGroupView()
}
fun forwardMessage(to: String, body: String): MessageRobot =
recipients(to)
.body(body)
.forward()
fun changeSubjectAndForwardMessage(to: String, subject: String, body: String): MessageRobot =
fun changeSubjectAndForwardMessage(to: String, subject: String): MessageRobot =
recipients(to)
.subject(subject)
.body(body)
.updateSubject(subject)
.forward()
fun sendMessageTOandCC(to: String, cc: String, subject: String, body: String): InboxRobot =
@ -135,6 +142,25 @@ class ComposerRobot {
.addImageCaptureAttachment(logoDrawable)
.send()
fun sendMessageEOAndExpiryTimeWithAttachmentAndConfirmation(
to: String,
subject: String,
body: String,
days: Int,
password: String,
hint: String
): InboxRobot =
composeMessage(to, subject, body)
.setMessagePassword()
.definePasswordWithHint(password, hint)
.messageExpiration()
.setExpirationInDays(days)
.hideExpirationView()
.attachments()
.addImageCaptureAttachment(logoDrawable)
.sendWithNotSupportedExpiryConfirmation()
.sendAnyway()
fun sendMessageCameraCaptureAttachment(to: String, subject: String, body: String): InboxRobot =
composeMessage(to, subject, body)
.attachments()
@ -168,7 +194,8 @@ class ComposerRobot {
.addImageCaptureAttachment(logoDrawable)
}
fun editBodyAndReply(messageBody: String): MessageRobot = body(messageBody).reply()
fun editBodyAndReply(currentBody: String, newBody: String): MessageRobot =
body(newBody).reply()
fun clickUpButton(): ComposerRobot {
UIActions.system.clickHamburgerOrUpButton()
@ -191,6 +218,7 @@ class ComposerRobot {
.body(body)
fun recipients(email: String): ComposerRobot {
UIActions.wait.forViewWithId(R.id.to_recipients)
UIActions.id.typeTextIntoFieldWithIdAndPressImeAction(R.id.to_recipients, email)
return this
}
@ -222,13 +250,18 @@ class ComposerRobot {
return this
}
fun updateSubject(text: String): ComposerRobot {
UIActions.wait.forViewWithId(R.id.message_title).insert(text)
return this
}
private fun body(text: String): ComposerRobot {
UIActions.id.insertTextIntoFieldWithId(R.id.message_body, text)
UIActions.wait.forViewWithId(R.id.message_body).insert(text)
return this
}
private fun showAdditionalRows(): ComposerRobot {
UIActions.id.clickViewWithId(R.id.show_additional_rows)
UIActions.wait.forViewWithId(R.id.show_additional_rows).click()
return this
}
@ -278,10 +311,9 @@ class ComposerRobot {
}
private fun waitForConditionAndSend() {
UIActions.wait.forViewWithId(R.id.tokenPgpText)
UIActions.wait.untilViewWithIdIsGone(R.id.text1)
UIActions.wait.untilViewWithIdEnabled(sendMessageId)
UIActions.id.clickViewWithId(sendMessageId)
UIActions.wait.forViewWithText(R.string.message_sent)
UIActions.wait.untilViewWithTextIsGone(R.string.message_sent)
}
/**

View File

@ -45,6 +45,11 @@ class DraftsRobot : MailboxRobotInterface {
return this
}
override fun refreshMessageList(): DraftsRobot {
super.refreshMessageList()
return this
}
fun moreOptions(): DraftsRobot {
UIActions.system.clickMoreOptionsButton()
return this

View File

@ -22,6 +22,7 @@ import ch.protonmail.android.R
import ch.protonmail.android.uitests.robots.mailbox.MailboxRobotInterface
import ch.protonmail.android.uitests.robots.mailbox.MoveToFolderRobotInterface
import ch.protonmail.android.uitests.robots.mailbox.SelectionStateRobotInterface
import ch.protonmail.android.uitests.robots.mailbox.sent.SentRobot
import ch.protonmail.android.uitests.testsHelper.UIActions
/**
@ -45,6 +46,11 @@ class InboxRobot : MailboxRobotInterface {
return this
}
override fun refreshMessageList(): SentRobot {
super.refreshMessageList()
return SentRobot()
}
/**
* Contains all the validations that can be performed by [InboxRobot].
*/

View File

@ -57,18 +57,20 @@ class MessageRobot {
}
fun reply(): ComposerRobot {
UIActions.wait.forViewWithId(R.id.reply).click()
UIActions.wait.forViewWithId(R.id.reply)
UIActions.wait.untilViewWithIdEnabled(R.id.reply).click()
return ComposerRobot()
}
fun replyAll(): ComposerRobot {
UIActions.wait.forViewWithId(R.id.reply_all).click()
UIActions.wait.forViewWithId(R.id.reply_all)
UIActions.wait.untilViewWithIdEnabled(R.id.reply_all).click()
return ComposerRobot()
}
fun forward(): ComposerRobot {
UIActions.wait.forViewWithId(R.id.message_body)
UIActions.wait.forViewWithId(R.id.forward).click()
UIActions.wait.forViewWithId(R.id.forward)
UIActions.wait.untilViewWithIdEnabled(R.id.forward).click()
return ComposerRobot()
}
@ -78,11 +80,13 @@ class MessageRobot {
}
fun navigateUpToSearch(): SearchRobot {
UIActions.wait.forViewWithId(R.id.messageWebViewContainer)
UIActions.system.clickHamburgerOrUpButton()
return SearchRobot()
}
fun navigateUpToSent(): SentRobot {
UIActions.wait.forViewWithId(R.id.reply_all)
UIActions.system.clickHamburgerOrUpButton()
return SentRobot()
}
@ -121,6 +125,10 @@ class MessageRobot {
fun pgpIconShown() {
UIActions.wait.forViewWithId(R.id.pgp_icon)
}
fun messageWebViewContainerShown() {
UIActions.wait.forViewWithId(R.id.messageWebViewContainer)
}
}
inline fun verify(block: Verify.() -> Unit) = Verify().apply(block)

View File

@ -32,7 +32,7 @@ class ViewHeadersRobot {
*/
class Verify {
fun messageHeadersDisplayed() {
UIActions.check.viewWithIdIsDisplayed(R.id.viewHeadersText)
UIActions.wait.forViewWithId(R.id.viewHeadersText)
}
}

View File

@ -34,7 +34,7 @@ import ch.protonmail.android.uitests.testsHelper.UIActions
class SearchRobot {
fun searchMessageText(subject: String): SearchRobot {
UIActions.id.typeTextIntoFieldWithIdAndPressImeAction(R.id.search_src_text, subject)
UIActions.id.insertTextInFieldWithIdAndPressImeAction(R.id.search_src_text, subject)
return this
}

View File

@ -46,6 +46,11 @@ class SentRobot : MailboxRobotInterface {
return this
}
override fun refreshMessageList(): SentRobot {
super.refreshMessageList()
return SentRobot()
}
/**
* Handles Mailbox selection state actions and verifications after user long click one of the messages.
*/

View File

@ -6,6 +6,7 @@ import ch.protonmail.android.uitests.robots.mailbox.inbox.InboxRobot
import ch.protonmail.android.uitests.robots.manageaccounts.ManageAccountsMatchers.withPrimaryAccountInAccountManager
import ch.protonmail.android.uitests.testsHelper.StringUtils.stringFromResource
import ch.protonmail.android.uitests.testsHelper.UIActions
import ch.protonmail.android.uitests.testsHelper.click
/**
* [AccountManagerRobot] class contains actions and verifications for Account Manager functionality.
@ -55,7 +56,7 @@ open class AccountManagerRobot {
}
private fun logout(): AccountManagerRobot {
UIActions.text.clickViewWithText(R.string.logout)
UIActions.wait.forViewWithText(R.string.logout).click()
return AccountManagerRobot()
}
@ -75,7 +76,7 @@ open class AccountManagerRobot {
}
private fun confirmLastAccountLogout(): LoginRobot {
UIActions.system.clickPositiveButtonInDialogRoot()
UIActions.wait.forViewWithId(android.R.id.button1).click()
return LoginRobot()
}

View File

@ -21,6 +21,8 @@ package ch.protonmail.android.uitests.tests
import android.Manifest.permission.READ_CONTACTS
import android.Manifest.permission.READ_EXTERNAL_STORAGE
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.app.Activity
import android.app.Instrumentation
import android.content.Context
import android.os.Bundle
import android.preference.PreferenceManager
@ -29,6 +31,7 @@ import android.widget.Toast
import androidx.test.espresso.Espresso
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.matcher.IntentMatchers.isInternal
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
@ -41,6 +44,7 @@ import ch.protonmail.android.uitests.testsHelper.TestData
import ch.protonmail.android.uitests.testsHelper.TestExecutionWatcher
import ch.protonmail.android.uitests.testsHelper.User
import ch.protonmail.android.uitests.testsHelper.testRail.TestRailService
import org.hamcrest.CoreMatchers.not
import org.junit.After
import org.junit.Before
import org.junit.BeforeClass
@ -72,8 +76,10 @@ open class BaseTest {
Log.d(testTag, "Starting test execution for test: ${testName.methodName}")
// Show toast with test case name for better test analysis in recorded videos especially on Firebase.
InstrumentationRegistry.getInstrumentation().runOnMainSync {
Toast.makeText(targetContext, testName.methodName, twoSeconds).show()
Toast.makeText(targetContext, testName.methodName, tenSeconds).show()
}
Intents.intending(not(isInternal()))
.respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, null))
}
@After
@ -107,7 +113,7 @@ open class BaseTest {
private const val password = 1
private const val mailboxPassword = 2
private const val twoFaKey = 3
private const val twoSeconds = 2000
private const val tenSeconds = 10000
val device: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@JvmStatic

View File

@ -52,6 +52,7 @@ class ForwardMessageTests : BaseTest() {
.sendMessage(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.clickMessageBySubject(subject)
.forward()
.forwardMessage(to, body)
@ -69,6 +70,7 @@ class ForwardMessageTests : BaseTest() {
.sendMessageWithFileAttachment(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.clickMessageBySubject(subject)
.forward()
.forwardMessage(to, body)
@ -88,7 +90,7 @@ class ForwardMessageTests : BaseTest() {
.searchMessageText(reSubject(searchMessageSubject))
.clickSearchedMessageBySubjectPart(searchMessageSubjectPart)
.forward()
.changeSubjectAndForwardMessage(to, subject, body)
.changeSubjectAndForwardMessage(to, subject)
.navigateUpToSearch()
.navigateUpToInbox()
.menuDrawer()

View File

@ -22,8 +22,8 @@ import ch.protonmail.android.uitests.robots.login.LoginRobot
import ch.protonmail.android.uitests.tests.BaseTest
import ch.protonmail.android.uitests.testsHelper.TestData
import ch.protonmail.android.uitests.testsHelper.TestData.onePassUser
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import ch.protonmail.android.uitests.testsHelper.annotations.TestId
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import org.junit.Before
import org.junit.Test
import org.junit.experimental.categories.Category
@ -52,9 +52,10 @@ class ReplyToMessageTests : BaseTest() {
.sendMessage(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.clickMessageBySubject(subject)
.reply()
.editBodyAndReply("Robot Reply")
.editBodyAndReply(body, "Robot Reply")
.navigateUpToSent()
.verify {
messageWithSubjectExists(TestData.reSubject(subject))
@ -71,9 +72,10 @@ class ReplyToMessageTests : BaseTest() {
.sendMessageCameraCaptureAttachment(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.clickMessageBySubject(subject)
.reply()
.editBodyAndReply("Robot Reply With Attachment ")
.editBodyAndReply(body, "Robot Reply With Attachment ")
.navigateUpToSent()
.verify { messageWithSubjectExists(TestData.reSubject(subject)) }
}
@ -88,9 +90,10 @@ class ReplyToMessageTests : BaseTest() {
.sendMessage(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.clickMessageBySubject(subject)
.replyAll()
.editBodyAndReply("Robot ReplyAll ")
.editBodyAndReply(body, "Robot ReplyAll ")
.navigateUpToSent()
.verify { messageWithSubjectExists(TestData.reSubject(subject)) }
}

View File

@ -29,8 +29,8 @@ import ch.protonmail.android.uitests.testsHelper.TestData.internalEmailNotTruste
import ch.protonmail.android.uitests.testsHelper.TestData.internalEmailTrustedKeys
import ch.protonmail.android.uitests.testsHelper.TestData.onePassUser
import ch.protonmail.android.uitests.testsHelper.TestData.twoPassUser
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import ch.protonmail.android.uitests.testsHelper.annotations.TestId
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import org.junit.Before
import org.junit.Test
import org.junit.experimental.categories.Category
@ -58,6 +58,7 @@ class SendNewMessageTests : BaseTest() {
.sendMessage(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@ -71,13 +72,14 @@ class SendNewMessageTests : BaseTest() {
.sendMessage(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("1543")
@Category(SmokeTest::class)
@Test
fun sendMessageToPGPEncryptedContact() {
fun sendExternalMessageToPGPEncryptedContact() {
val to = externalGmailPGPEncrypted.email
loginRobot
.loginUser(onePassUser)
@ -85,13 +87,14 @@ class SendNewMessageTests : BaseTest() {
.sendMessage(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("1544")
@Category(SmokeTest::class)
@Test
fun sendMessageToPGPSignedContact() {
fun sendExternalMessageToPGPSignedContact() {
val to = externalGmailPGPEncrypted.email
loginRobot
.loginUser(onePassUser)
@ -99,19 +102,21 @@ class SendNewMessageTests : BaseTest() {
.sendMessage(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@Test
fun sendMessageTOandCC() {
val to = internalEmailTrustedKeys.email
val cc = externalOutlookPGPSigned.email
val cc = internalEmailNotTrustedKeys.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageTOandCC(to, cc, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@ -127,54 +132,28 @@ class SendNewMessageTests : BaseTest() {
.sendMessageTOandCCandBCC(to, cc, bcc, subject, body)
.menuDrawer()
.sent()
.verify { messageWithSubjectExists(subject) }
}
@TestId("1542")
@Test
fun sendMessageEO() {
val to = externalOutlookPGPSigned.email
val password = editedPassword
val hint = editedPasswordHint
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageWithPassword(to, subject, body, password, hint)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("1550")
@Test
fun sendMessageExpiryTime() {
val to = externalOutlookPGPSigned.email
fun sendMessageWithExpiryTime() {
val to = internalEmailTrustedKeys.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageExpiryTimeInDays(to, subject, body, 2)
.menuDrawer()
.sent()
.verify { messageWithSubjectExists(subject) }
}
@TestId("1548")
@Test
fun sendMessageExpiryTimeExternalContact() {
val to = externalGmailPGPEncrypted.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageExpiryTimeInDaysWithConfirmation(to, subject, body, 2)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("21090")
@Test
fun sendMessageEOAndExpiryTime() {
val to = externalOutlookPGPSigned.email
fun sendMessageWithPasswordAndExpiryTime() {
val to = internalEmailTrustedKeys.email
val password = editedPassword
val hint = editedPasswordHint
loginRobot
@ -184,91 +163,50 @@ class SendNewMessageTests : BaseTest() {
.sendMessageEOAndExpiryTime(to, subject, body, 1, password, hint)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("21091")
@Test
fun sendMessageEOAndExpiryTimeWithAttachment() {
val to = externalOutlookPGPSigned.email
val password = editedPassword
val hint = editedPasswordHint
loginRobot
.loginTwoPasswordUser(twoPassUser)
.decryptMailbox(password)
.compose()
.sendMessageEOAndExpiryTimeWithAttachment(to, subject, body, 1, password, hint)
.menuDrawer()
.sent()
.verify { messageWithSubjectExists(subject) }
}
@Test
fun sendMessageToInternalTrustedContactCameraCaptureAttachment() {
val to = externalOutlookPGPSigned.email
fun sendMessageToInternalTrustedContactWithCameraCaptureAttachment() {
val to = internalEmailTrustedKeys.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageCameraCaptureAttachment(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@Test
fun sendMessageToInternalNotTrustedContactChooseAttachment() {
val to = externalOutlookPGPSigned.email
fun sendMessageToInternalNotTrustedContactWithAttachment() {
val to = internalEmailNotTrustedKeys.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageWithFileAttachment(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@Test
fun sendMessageToInternalContactWithTwoAttachments() {
val to = externalOutlookPGPSigned.email
val to = internalEmailTrustedKeys.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageTwoImageCaptureAttachments(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("15539")
@Test
fun sendMessageToExternalContactWithOneAttachment() {
val to = externalOutlookPGPSigned.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageCameraCaptureAttachment(to, subject, body)
.menuDrawer()
.sent()
.verify { messageWithSubjectExists(subject) }
}
@TestId("15540")
@Test
fun sendMessageToExternalContactWithTwoAttachments() {
val to = externalOutlookPGPSigned.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageTwoImageCaptureAttachments(to, subject, body)
.menuDrawer()
.sent()
.verify { messageWithSubjectExists(subject) }
}
@TestId("C1484")
@TestId("1484")
@Test
fun sendMessageFromPmMe() {
val onePassUserPmMeAddress = onePassUser.pmMe
@ -280,10 +218,11 @@ class SendNewMessageTests : BaseTest() {
.sendMessage(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("C1485")
@TestId("1485")
@Test
fun sendMessageWithAttachmentFromPmMe() {
val onePassUserPmMeAddress = onePassUser.pmMe
@ -295,6 +234,82 @@ class SendNewMessageTests : BaseTest() {
.sendMessageWithFileAttachment(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("1542")
//TODO - fix failing test
fun sendMessageWithPasswordToExternalContact() {
val to = externalOutlookPGPSigned.email
val password = editedPassword
val hint = editedPasswordHint
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageWithPassword(to, subject, body, password, hint)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("21091")
//TODO - enable back after MAILAND-789 is fixed
fun sendExternalMessageWithPasswordExpiryTimeAndAttachment() {
val to = externalOutlookPGPSigned.email
val password = editedPassword
val hint = editedPasswordHint
loginRobot
.loginTwoPasswordUser(twoPassUser)
.decryptMailbox(password)
.compose()
.sendMessageEOAndExpiryTimeWithAttachment(to, subject, body, 1, password, hint)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("15539")
//TODO - enable back after MAILAND-789 is fixed
fun sendExternalMessageWithOneAttachment() {
val to = externalOutlookPGPSigned.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageCameraCaptureAttachment(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("1548")
//TODO - enable back after MAILAND-789 is fixed
fun sendExternalMessageWithExpiryTime() {
val to = externalGmailPGPEncrypted.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageExpiryTimeInDaysWithConfirmation(to, subject, body, 2)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("15540")
//TODO - enable back after MAILAND-789 is fixed
fun sendExternalMessageWithTwoAttachments() {
val to = externalOutlookPGPSigned.email
loginRobot
.loginUser(onePassUser)
.compose()
.sendMessageTwoImageCaptureAttachments(to, subject, body)
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
}

View File

@ -18,7 +18,6 @@
*/
package ch.protonmail.android.uitests.tests.contacts
import androidx.test.filters.LargeTest
import ch.protonmail.android.R
import ch.protonmail.android.uitests.robots.contacts.ContactsRobot
import ch.protonmail.android.uitests.robots.login.LoginRobot
@ -28,16 +27,12 @@ import ch.protonmail.android.uitests.testsHelper.TestData
import ch.protonmail.android.uitests.testsHelper.TestData.internalEmailTrustedKeys
import ch.protonmail.android.uitests.testsHelper.TestData.onePassUser
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.checkGroupDoesNotExist
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import ch.protonmail.android.uitests.testsHelper.annotations.TestId
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.experimental.categories.Category
import org.junit.runners.MethodSorters
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@LargeTest
class ContactsTests : BaseTest() {
private lateinit var contactsRobot: ContactsRobot
@ -52,7 +47,6 @@ class ContactsTests : BaseTest() {
.contacts()
}
@TestId("1419")
@Test
fun createContact() {
val name = TestData.newContactName
@ -60,6 +54,8 @@ class ContactsTests : BaseTest() {
contactsRobot
.addContact()
.setNameEmailAndSave(name, email)
.openOptionsMenu()
.refresh()
.clickContactByEmail(email)
.deleteContact()
.verify { contactDoesNotExists(name, email) }
@ -76,6 +72,8 @@ class ContactsTests : BaseTest() {
contactsRobot
.addContact()
.setNameEmailAndSave(name, email)
.openOptionsMenu()
.refresh()
.clickContactByEmail(email)
.editContact()
.editNameEmailAndSave(editedName, editedEmail)
@ -93,12 +91,15 @@ class ContactsTests : BaseTest() {
contactsRobot
.addContact()
.setNameEmailAndSave(name, email)
.openOptionsMenu()
.refresh()
.clickContactByEmail(email)
.deleteContact()
.verify { contactDoesNotExists(name, email) }
}
@TestId("1421")
@Test
fun createGroup() {
val contactEmail = internalEmailTrustedKeys
val groupName = getEmailString()
@ -110,6 +111,8 @@ class ContactsTests : BaseTest() {
.manageAddresses()
.addContactToGroup(contactEmail.email)
.done()
.openOptionsMenu()
.refresh()
.groupsView()
.clickGroupWithMembersCount(groupName, groupMembersCount)
.deleteGroup()
@ -118,6 +121,7 @@ class ContactsTests : BaseTest() {
}
@TestId("1422")
@Test
fun editGroup() {
val contactEmail = internalEmailTrustedKeys
val groupName = getEmailString()
@ -130,11 +134,15 @@ class ContactsTests : BaseTest() {
.manageAddresses()
.addContactToGroup(contactEmail.email)
.done()
.openOptionsMenu()
.refresh()
.groupsView()
.clickGroup(groupName)
.edit()
.editNameAndSave(newGroupName)
.navigateUp()
.openOptionsMenu()
.refresh()
.groupsView()
.clickGroupWithMembersCount(newGroupName, groupMembersCount)
.deleteGroup()
@ -143,6 +151,7 @@ class ContactsTests : BaseTest() {
}
@TestId("21240")
@Test
fun deleteGroup() {
val contactEmail = internalEmailTrustedKeys
val groupName = getEmailString()
@ -154,6 +163,8 @@ class ContactsTests : BaseTest() {
.manageAddresses()
.addContactToGroup(contactEmail.email)
.done()
.openOptionsMenu()
.refresh()
.groupsView()
.clickGroupWithMembersCount(groupName, groupMembersCount)
.deleteGroup()
@ -161,15 +172,6 @@ class ContactsTests : BaseTest() {
.verify { checkGroupDoesNotExist(groupName, groupMembersCount) }
}
@TestId("1606")
@Test
fun contactListRefresh() {
contactsRobot
.openOptionsMenu()
.refresh()
.verify { contactsRefreshed() }
}
@TestId("30833")
@Category(SmokeTest::class)
@Test
@ -183,9 +185,8 @@ class ContactsTests : BaseTest() {
.navigateUpToInbox()
.menuDrawer()
.sent()
.verify {
messageWithSubjectExists(subject)
}
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("1423")
@ -197,12 +198,11 @@ class ContactsTests : BaseTest() {
contactsRobot
.groupsView()
.clickSendMessageToGroup(groupName)
.sendMessageToContact(subject, body)
.sendMessageToGroup(subject, body)
.navigateUpToInbox()
.menuDrawer()
.sent()
.verify {
messageWithSubjectExists(subject)
}
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
}

View File

@ -24,8 +24,8 @@ import ch.protonmail.android.uitests.tests.BaseTest
import ch.protonmail.android.uitests.testsHelper.TestData
import ch.protonmail.android.uitests.testsHelper.TestData.internalEmailTrustedKeys
import ch.protonmail.android.uitests.testsHelper.TestData.onePassUser
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import ch.protonmail.android.uitests.testsHelper.annotations.TestId
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import org.junit.Before
import org.junit.Test
import org.junit.experimental.categories.Category
@ -56,6 +56,7 @@ class DraftsTests : BaseTest() {
.confirmDraftSaving()
.menuDrawer()
.drafts()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@ -66,29 +67,15 @@ class DraftsTests : BaseTest() {
loginRobot
.loginUser(onePassUser)
.compose()
.draftSubjectBody(subject, body)
.draftSubjectBodyAttachment(to, subject, body)
.clickUpButton()
.confirmDraftSaving()
.menuDrawer()
.drafts()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
// Ignore test until https://jira.protontech.ch/browse/MAILAND-982 is fixed.
@TestId("1382")
fun openDraftFromSearch() {
loginRobot
.loginUser(onePassUser)
.compose()
.draftSubjectBody(subject, body)
.clickUpButton()
.confirmDraftSaving()
.searchBar()
.searchMessageText(subject)
.clickSearchedDraftBySubject(subject)
.verify { messageWithSubjectOpened(subject) }
}
@TestId("1383")
@Test
fun sendDraftWithAttachment() {
@ -100,13 +87,37 @@ class DraftsTests : BaseTest() {
.confirmDraftSaving()
.menuDrawer()
.drafts()
.refreshMessageList()
.clickDraftBySubject(subject)
.send()
.menuDrawer()
.sent()
.refreshMessageList()
.verify { messageWithSubjectExists(subject) }
}
@TestId("4278")
@Test
fun changeDraftSender() {
val onePassUserSecondEmail = "2${onePassUser.email}"
val to = internalEmailTrustedKeys.email
loginRobot
.loginUser(onePassUser)
.compose()
.draftToSubjectBody(to, subject, body)
.clickUpButton()
.confirmDraftSaving()
.menuDrawer()
.drafts()
.clickDraftBySubject(subject)
.recipients(to)
.changeSenderTo(onePassUserSecondEmail)
.clickUpButton()
.confirmDraftSavingFromDrafts()
.clickDraftBySubject(subject)
.verify { fromEmailIs(onePassUserSecondEmail) }
}
@TestId("1384")
@Test
fun addRecipientsToDraft() {
@ -119,6 +130,7 @@ class DraftsTests : BaseTest() {
.confirmDraftSaving()
.menuDrawer()
.drafts()
.refreshMessageList()
.clickDraftBySubject(subject)
.recipients(to)
.clickUpButton()
@ -126,25 +138,18 @@ class DraftsTests : BaseTest() {
.verify { messageWithSubjectAndRecipientExists(subject, to) }
}
@TestId("4278")
@Test
fun changeDraftSender() {
val onePassUserSecondEmail = "2${onePassUser.email}"
val to = internalEmailTrustedKeys.email
// Ignore test until MAILAND-982 is fixed.
// @RailId("1382")
fun openDraftFromSearch() {
loginRobot
.loginUser(onePassUser)
.compose()
.draftSubjectBody(subject, body)
.draftToSubjectBody(to, subject, body)
.clickUpButton()
.confirmDraftSaving()
.menuDrawer()
.drafts()
.clickDraftBySubject(subject)
.recipients(to)
.changeSenderTo(onePassUserSecondEmail)
.clickUpButton()
.confirmDraftSavingFromDrafts()
.clickDraftBySubject(subject)
.verify { fromEmailIs(onePassUserSecondEmail) }
.searchBar()
.searchMessageText(subject)
.clickSearchedDraftBySubject(subject)
.verify { messageWithSubjectOpened(subject) }
}
}

View File

@ -30,10 +30,9 @@ import ch.protonmail.android.uitests.tests.BaseTest
import ch.protonmail.android.uitests.testsHelper.TestData
import ch.protonmail.android.uitests.testsHelper.TestData.externalGmailPGPEncrypted
import ch.protonmail.android.uitests.testsHelper.TestData.externalOutlookPGPSigned
import ch.protonmail.android.uitests.testsHelper.TestData.internalEmailTrustedKeys
import ch.protonmail.android.uitests.testsHelper.TestData.onePassUser
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import ch.protonmail.android.uitests.testsHelper.annotations.TestId
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import ch.protonmail.android.uitests.testsHelper.mailer.Mail
import org.junit.Before
import org.junit.Test
@ -61,8 +60,9 @@ class InboxTests : BaseTest() {
val to = onePassUser
Mail.gmail.from(from).to(to).withSubject(subject).withBody(body).send()
inboxRobot
.refreshMessageList()
.clickMessageBySubject(subject)
.verify { pgpIconShown() }
.verify { messageWebViewContainerShown() }
}
@TestId("29747")
@ -72,22 +72,24 @@ class InboxTests : BaseTest() {
val to = onePassUser
Mail.outlook.from(from).to(to).withSubject(subject).withBody(body).send()
inboxRobot
.refreshMessageList()
.clickMessageBySubject(subject)
.verify { pgpIconShown() }
.verify { messageWebViewContainerShown() }
}
@TestId("C1486")
@TestId("1486")
@Test
fun receiveMessageOnPmMe() {
val from = externalOutlookPGPSigned
val to = onePassUser
Mail.outlook.from(from).to(to).withSubject(subject).withBody(body).sendToPmMe()
inboxRobot
.refreshMessageList()
.clickMessageBySubject(subject)
.verify { pgpIconShown() }
.verify { messageWebViewContainerShown() }
}
@TestId("C1487")
@TestId("1487")
@Test
fun receiveMessageWithAttachmentOnPmMe() {
loginRobot
@ -125,19 +127,6 @@ class InboxTests : BaseTest() {
.verify { messageWithSubjectExists(subject) }
}
@TestId("29722")
@Test
fun deleteMessageLongClick() {
inboxRobot
.menuDrawer()
.sent()
.longClickMessageOnPosition(0)
.moveToTrash()
.verify {
messageDeleted(longClickedMessageSubject, longClickedMessageDate)
}
}
@TestId("29723")
@Category(SmokeTest::class)
@Test
@ -191,17 +180,6 @@ class InboxTests : BaseTest() {
.verify { messageMoved(longClickedMessageSubject) }
}
//TODO create a bug - app hangs in loading state after trying to empty the trash folder
fun emptyTrash() {
inboxRobot
.menuDrawer()
.trash()
.moreOptions()
.emptyFolder()
.confirm()
.verify { folderEmpty() }
}
@Test
fun messageDetailsViewHeaders() {
inboxRobot
@ -213,32 +191,16 @@ class InboxTests : BaseTest() {
.verify { messageHeadersDisplayed() }
}
@TestId("29722")
@Test
fun saveDraft() {
val draftSubject = "Draft ${TestData.messageSubject}"
val body = "Draft ${TestData.messageBody}"
fun deleteMessageLongClick() {
inboxRobot
.compose()
.draftToSubjectBody(internalEmailTrustedKeys.email, draftSubject, body)
.clickUpButton()
.confirmDraftSaving()
.menuDrawer()
.drafts()
.verify { draftMessageSaved(draftSubject) }
}
@Category(SmokeTest::class)
@Test
fun saveDraftWithAttachment() {
val draftSubject = "Draft ${TestData.messageSubject}"
val body = "Draft ${TestData.messageBody}"
inboxRobot
.compose()
.draftSubjectBodyAttachment(internalEmailTrustedKeys.email, draftSubject, body)
.clickUpButton()
.confirmDraftSaving()
.menuDrawer()
.drafts()
.verify { draftWithAttachmentSaved(draftSubject) }
.sent()
.longClickMessageOnPosition(0)
.moveToTrash()
.verify {
messageDeleted(longClickedMessageSubject, longClickedMessageDate)
}
}
}

View File

@ -58,7 +58,6 @@ class LoginTests : BaseTest() {
.verify { mailboxLayoutShown() }
}
@Test
fun loginWithTwoPassAnd2Fa() {
loginRobot
.loginUserWithTwoFa(twoPassUserWith2FA)

View File

@ -18,7 +18,6 @@
*/
package ch.protonmail.android.uitests.tests.manageaccounts
import androidx.test.filters.LargeTest
import ch.protonmail.android.uitests.robots.login.LoginRobot
import ch.protonmail.android.uitests.tests.BaseTest
import ch.protonmail.android.uitests.testsHelper.TestData.onePassUser
@ -29,7 +28,6 @@ import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import org.junit.Test
import org.junit.experimental.categories.Category
@LargeTest
class MultiuserManagementTests : BaseTest() {
private val loginRobot = LoginRobot()
@ -63,20 +61,6 @@ class MultiuserManagementTests : BaseTest() {
.verify { accountAdded(twoPassUser.email) }
}
@Test
fun connectTwoPassAccountWithTwoFa() {
loginRobot
.loginUser(onePassUser)
.menuDrawer()
.accountsList()
.manageAccounts()
.addAccount()
.connectTwoPassAccountWithTwoFa(twoPassUserWith2FA)
.menuDrawer()
.accountsList()
.verify { accountAdded(twoPassUserWith2FA.email) }
}
@Test
fun connectOnePassAccountWithTwoFa() {
loginRobot
@ -233,20 +217,6 @@ class MultiuserManagementTests : BaseTest() {
.verify { accountLoggedOut(onePassUserWith2FA.name) }
}
@Test
fun addTwoFreeAccounts() {
loginRobot
.loginUserWithTwoFa(twoPassUserWith2FA)
.provideTwoFaCodeMailbox(twoPassUserWith2FA.twoFaCode)
.decryptMailbox(twoPassUserWith2FA.mailboxPassword)
.menuDrawer()
.accountsList()
.manageAccounts()
.addAccount()
.connectSecondFreeOnePassAccountWithTwoFa(onePassUserWith2FA)
.verify { limitReachedDialogDisplayed() }
}
@Category(SmokeTest::class)
@Test
fun switchAccount() {
@ -264,4 +234,30 @@ class MultiuserManagementTests : BaseTest() {
.manageAccounts()
.verify { switchedToAccount(onePassUser.name) }
}
fun addTwoFreeAccounts() {
loginRobot
.loginUserWithTwoFa(twoPassUserWith2FA)
.provideTwoFaCodeMailbox(twoPassUserWith2FA.twoFaCode)
.decryptMailbox(twoPassUserWith2FA.mailboxPassword)
.menuDrawer()
.accountsList()
.manageAccounts()
.addAccount()
.connectSecondFreeOnePassAccountWithTwoFa(onePassUserWith2FA)
.verify { limitReachedDialogDisplayed() }
}
fun connectTwoPassAccountWithTwoFa() {
loginRobot
.loginUser(onePassUser)
.menuDrawer()
.accountsList()
.manageAccounts()
.addAccount()
.connectTwoPassAccountWithTwoFa(twoPassUserWith2FA)
.menuDrawer()
.accountsList()
.verify { accountAdded(twoPassUserWith2FA.email) }
}
}

View File

@ -18,7 +18,6 @@
*/
package ch.protonmail.android.uitests.tests.menu
import androidx.test.filters.LargeTest
import ch.protonmail.android.uitests.robots.login.LoginRobot
import ch.protonmail.android.uitests.robots.menu.MenuRobot
import ch.protonmail.android.uitests.tests.BaseTest
@ -26,7 +25,6 @@ import ch.protonmail.android.uitests.testsHelper.TestData
import org.junit.Before
import org.junit.Test
@LargeTest
class MenuTests : BaseTest() {
private lateinit var menuRobot: MenuRobot

View File

@ -18,18 +18,15 @@
*/
package ch.protonmail.android.uitests.tests.settings
import androidx.test.filters.LargeTest
import ch.protonmail.android.uitests.actions.settings.account.AccountSettingsRobot
import ch.protonmail.android.uitests.robots.login.LoginRobot
import ch.protonmail.android.uitests.tests.BaseTest
import ch.protonmail.android.uitests.testsHelper.StringUtils.getAlphaNumericStringWithSpecialCharacters
import ch.protonmail.android.uitests.testsHelper.TestData
import ch.protonmail.android.uitests.testsHelper.annotations.SmokeTest
import org.junit.Before
import org.junit.Test
import org.junit.experimental.categories.Category
@LargeTest
class AccountSettingsTests : BaseTest() {
private val accountSettingsRobot: AccountSettingsRobot = AccountSettingsRobot()
@ -52,25 +49,6 @@ class AccountSettingsTests : BaseTest() {
.verify { subscriptionViewShown() }
}
@Test
fun changeLoginPassword() {
accountSettingsRobot
.passwordManagement()
.changePassword(TestData.twoPassUser)
.verify {
accountSettingsOpened()
passwordChanged()
}
}
//TODO enable when multiple user login per test class will be supported
fun changeMailboxPassword() {
accountSettingsRobot
.passwordManagement()
.changeMailboxPassword(TestData.twoPassUser)
.verify { mailboxPasswordChanged() }
}
@Category(SmokeTest::class)
@Test
fun changeRecoveryEmail() {
@ -120,25 +98,21 @@ class AccountSettingsTests : BaseTest() {
.verify { mobileSignatureToggleCheckedStateIs(true) }
}
@Test
fun createLabel() {
val labelName = getAlphaNumericStringWithSpecialCharacters()
fun changeLoginPassword() {
accountSettingsRobot
.foldersAndLabels()
// TODO enable after MAILAND-750 will be fixed.
// .labelsManager()
// .addLabel(labelName)
// .verify { labelWithNameShown(labelName) }
.passwordManagement()
.changePassword(TestData.twoPassUser)
.verify {
accountSettingsOpened()
passwordChanged()
}
}
@Test
fun createFolder() {
val folderName = getAlphaNumericStringWithSpecialCharacters()
accountSettingsRobot
.foldersAndLabels()
// TODO enable after MAILAND-750 will be fixed.
// .foldersManager()
// .addFolder(folderName)
// .verify { folderWithNameShown(folderName) }
}
// //TODO enable when multiple user login per test class will be supported
// fun changeMailboxPassword() {
// accountSettingsRobot
// .passwordManagement()
// .changeMailboxPassword(TestData.twoPassUser)
// .verify { mailboxPasswordChanged() }
// }
}

View File

@ -22,6 +22,7 @@ import ch.protonmail.android.uitests.tests.composer.ForwardMessageTests
import ch.protonmail.android.uitests.tests.composer.ReplyToMessageTests
import ch.protonmail.android.uitests.tests.composer.SendNewMessageTests
import ch.protonmail.android.uitests.tests.contacts.ContactsTests
import ch.protonmail.android.uitests.tests.drafts.DraftsTests
import ch.protonmail.android.uitests.tests.inbox.InboxTests
import ch.protonmail.android.uitests.tests.inbox.SearchTests
import ch.protonmail.android.uitests.tests.login.LoginTests
@ -42,6 +43,8 @@ import org.junit.runners.Suite
ReplyToMessageTests::class,
// Contacts tests
ContactsTests::class,
// Drafts tests
DraftsTests::class,
// Inbox tests
InboxTests::class,
// Login tests

View File

@ -18,7 +18,7 @@
*/
package ch.protonmail.android.uitests.testsHelper
import androidx.fragment.app.FragmentActivity
import android.app.Activity
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry
import androidx.test.runner.lifecycle.Stage
@ -27,17 +27,17 @@ import androidx.test.runner.lifecycle.Stage
* Provides an activity which is in [Stage.RESUMED].
*/
object ActivityProvider {
val currentActivity: FragmentActivity? get() = getActivity()
val currentActivity: Activity? get() = getActivity()
private fun getActivity(): FragmentActivity? {
val currentActivity = arrayOfNulls<FragmentActivity>(1)
private fun getActivity(): Activity? {
val currentActivity = arrayOfNulls<Activity>(1)
getInstrumentation().runOnMainSync {
val activities = ActivityLifecycleMonitorRegistry
.getInstance()
.getActivitiesInStage(Stage.RESUMED)
if (activities.iterator().hasNext()) {
currentActivity[0] = activities.iterator().next() as FragmentActivity
currentActivity[0] = activities.iterator().next() as Activity
}
}
return currentActivity[0]

View File

@ -37,16 +37,13 @@ class ProtonFailureHandler(instrumentation: Instrumentation) : FailureHandler {
}
override fun handle(error: Throwable, viewMatcher: Matcher<View>) {
when (ProtonWatcher.status) {
ProtonWatcher.CONDITION_NOT_MET -> {
// just delegate as we are in the condition check loop
delegate.handle(error, viewMatcher)
}
else -> {
val file = File(artifactsPath, "${testName.methodName}-screenshot.png")
Falcon.takeScreenshot(ActivityProvider.currentActivity, file)
delegate.handle(error, viewMatcher)
}
if (ProtonWatcher.status == ProtonWatcher.CONDITION_NOT_MET) {
// just delegate as we are in the condition check loop
delegate.handle(error, viewMatcher)
} else {
val file = File(artifactsPath, "${testName.methodName}-screenshot.png")
Falcon.takeScreenshot(ActivityProvider.currentActivity, file)
delegate.handle(error, viewMatcher)
}
}
}

View File

@ -38,6 +38,8 @@ class ProtonWatcher {
private val instance = ProtonWatcher()
fun waitForCondition(condition: Condition) {
// reset to initial state
status = 0
var timeInterval = 0L
while (status != CONDITION_MET) {
if (condition.checkCondition()) {
@ -49,12 +51,9 @@ class ProtonWatcher {
Thread.sleep(instance.watchInterval)
} else {
status = TIMEOUT
break
}
}
}
// reset to initial state
status = 0
}
fun setTimeout(ms: Long) {

View File

@ -34,6 +34,7 @@ import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import androidx.test.espresso.action.ViewActions.longClick
import androidx.test.espresso.action.ViewActions.pressImeActionButton
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.action.ViewActions.swipeDown
import androidx.test.espresso.action.ViewActions.swipeLeft
import androidx.test.espresso.action.ViewActions.swipeRight
import androidx.test.espresso.action.ViewActions.typeText
@ -49,6 +50,7 @@ import androidx.test.espresso.matcher.ViewMatchers.Visibility
import androidx.test.espresso.matcher.ViewMatchers.isChecked
import androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isEnabled
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
@ -67,8 +69,10 @@ import ch.protonmail.android.uitests.testsHelper.StringUtils.stringFromResource
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.checkContactDoesNotExist
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.checkMessageDoesNotExist
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.clickOnChildWithId
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.performActionWithRetry
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.saveMessageSubject
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.waitForAdapterItemWithIdAndText
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.waitUntilMatcherFulfilled
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.waitUntilRecyclerViewPopulated
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.waitUntilViewAppears
import ch.protonmail.android.uitests.testsHelper.UICustomViewActions.waitUntilViewIsGone
@ -88,6 +92,9 @@ fun ViewInteraction.insert(text: String): ViewInteraction =
fun ViewInteraction.type(text: String): ViewInteraction =
this.perform(typeText(text), closeSoftKeyboard())
fun ViewInteraction.swipeViewDown(): ViewInteraction =
this.perform(swipeDown())
object UIActions {
private val targetContext: Context = InstrumentationRegistry.getInstrumentation().targetContext
@ -219,6 +226,8 @@ object UIActions {
fun swipeLeftViewWithId(@IdRes id: Int): ViewInteraction = onView(withId(id)).perform(swipeLeft())
fun swipeDownViewWithId(@IdRes id: Int): ViewInteraction = onView(withId(id)).perform(swipeDown())
fun typeTextIntoFieldWithIdAndPressImeAction(@IdRes id: Int, text: String): ViewInteraction =
onView(withId(id)).perform(click(), typeText(text), pressImeActionButton())
@ -236,9 +245,17 @@ object UIActions {
): ViewInteraction =
onView(withId(recyclerViewId)).perform(actionOnHolderItem(withMatcher, click()))
fun clickOnRecyclerViewMatchedItemWithRetry(
@IdRes recyclerViewId: Int,
withMatcher: Matcher<RecyclerView.ViewHolder>
): ViewInteraction = performActionWithRetry(onView(withId(recyclerViewId)), actionOnHolderItem(withMatcher, click()))
fun clickContactItem(@IdRes recyclerViewId: Int, withEmail: String): ViewInteraction =
onView(withId(recyclerViewId)).perform(actionOnHolderItem(withContactEmail(withEmail), click()))
fun clickContactItemWithRetry(@IdRes recyclerViewId: Int, withEmail: String): ViewInteraction =
performActionWithRetry(onView(withId(recyclerViewId)), actionOnHolderItem(withContactEmail(withEmail), click()))
fun clickContactItemView(
@IdRes recyclerViewId: Int,
withEmail: String,
@ -296,6 +313,10 @@ object UIActions {
onView(withId(recyclerViewId))
.perform(actionOnItemAtPosition<RecyclerView.ViewHolder>(childPosition, swipeRight()))
fun swipeDownToRightOnPosition(@IdRes recyclerViewId: Int, childPosition: Int): ViewInteraction =
onView(withId(recyclerViewId))
.perform(actionOnItemAtPosition<RecyclerView.ViewHolder>(childPosition, swipeDown()))
fun swipeRightToLeftObjectWithIdAtPosition(@IdRes recyclerViewId: Int, childPosition: Int): ViewInteraction =
onView(withId(recyclerViewId))
.perform(actionOnItemAtPosition<RecyclerView.ViewHolder>(childPosition, swipeLeft()))
@ -320,6 +341,12 @@ object UIActions {
fun clickHamburgerOrUpButtonInAnimatedToolbar(): ViewInteraction =
allOf.clickViewWithParentIdAndClass(R.id.animToolbar, AppCompatImageButton::class.java)
fun waitForMoreOptionsButton(): ViewInteraction =
wait.forViewByViewInteraction(onView(allOf(
instanceOf(AppCompatImageView::class.java),
withParent(instanceOf(ActionMenuView::class.java))))
)
fun clickMoreOptionsButton(): ViewInteraction =
allOf.clickViewByClassAndParentClass(AppCompatImageView::class.java, ActionMenuView::class.java)
@ -362,12 +389,11 @@ object UIActions {
fun forViewWithText(@StringRes textId: Int): ViewInteraction =
waitUntilViewAppears(onView(withText(stringFromResource(textId))))
fun forViewWithText(text: String): ViewInteraction =
waitUntilViewAppears(onView(withText(text)))
fun forViewWithId(@IdRes id: Int): ViewInteraction =
waitUntilViewAppears(onView(withId(id)))
fun forViewWithId(@IdRes id: Int, timeout: Long = 10_000L): ViewInteraction =
waitUntilViewAppears(onView(withId(id)), timeout)
fun forViewWithTextAndParentId(@StringRes text: Int, @IdRes parentId: Int): ViewInteraction =
waitUntilViewAppears(onView(allOf(withText(text), withParent(withId(parentId)))))
@ -378,6 +404,12 @@ object UIActions {
fun forViewByViewInteraction(interaction: ViewInteraction): ViewInteraction =
waitUntilViewAppears(interaction)
fun untilViewWithIdEnabled(@IdRes id: Int): ViewInteraction =
waitUntilMatcherFulfilled(onView(withId(id)), matches(isEnabled()))
fun untilViewWithIdDisabled(@IdRes id: Int): ViewInteraction =
waitUntilMatcherFulfilled(onView(withId(id)), matches(isEnabled()))
fun untilViewWithIdIsGone(@IdRes id: Int): ViewInteraction =
waitUntilViewIsGone(onView(withId(id)))

View File

@ -32,6 +32,7 @@ import androidx.test.espresso.NoMatchingViewException
import androidx.test.espresso.PerformException
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import androidx.test.espresso.ViewAssertion
import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.assertion.ViewAssertions.matches
@ -40,6 +41,8 @@ import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.platform.app.InstrumentationRegistry
import ch.protonmail.android.R
import ch.protonmail.android.contacts.list.listView.ContactsListAdapter
import ch.protonmail.android.uitests.testsHelper.ActivityProvider.currentActivity
import junit.framework.AssertionFailedError
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.Matcher
@ -52,92 +55,165 @@ object UICustomViewActions {
private val targetContext = InstrumentationRegistry.getInstrumentation().targetContext
fun waitUntilViewAppears(interaction: ViewInteraction, timeout: Long = TIMEOUT_10S): ViewInteraction {
try {
ProtonWatcher.setTimeout(timeout)
ProtonWatcher.waitForCondition(object : ProtonWatcher.Condition() {
var errorMessage = ""
override fun getDescription() = "UICustomViewActions.waitUntilViewAppears $errorMessage"
override fun checkCondition(): Boolean {
return try {
interaction.check(matches(isDisplayed()))
true
} catch (e: PerformException) {
errorMessage = "${e.viewDescription}, Action: ${e.actionDescription}"
false
} catch (e: NoMatchingViewException) {
errorMessage = e.viewMatcherDescription
false
} catch (e: NoMatchingRootException) {
false
} catch (e: AppNotIdleException) {
false
} catch (e: AmbiguousViewMatcherException) {
false
} catch (e: AssertionFailedError) {
false
}
}
})
} catch (e: Throwable) {
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
}
}
return interaction
val errorDescription = "UICustomViewActions.waitUntilViewAppears"
return waitUntilMatcherFulfilled(
interaction,
assertion = matches(isDisplayed()),
timeout = timeout,
errorDescription = errorDescription
)
}
fun waitUntilViewIsGone(interaction: ViewInteraction, timeout: Long = TIMEOUT_10S): ViewInteraction {
try {
ProtonWatcher.setTimeout(timeout)
ProtonWatcher.waitForCondition(object : ProtonWatcher.Condition() {
var errorMessage = ""
val errorDescription = "UICustomViewActions.waitUntilViewAppears"
return waitUntilMatcherFulfilled(
interaction,
assertion = doesNotExist(),
timeout = timeout,
errorDescription = errorDescription
)
}
override fun getDescription() = "waitForElement - $errorMessage"
fun waitUntilMatcherFulfilled(
interaction: ViewInteraction,
assertion: ViewAssertion,
timeout: Long = TIMEOUT_10S,
errorDescription: String = ""
): ViewInteraction {
ProtonWatcher.setTimeout(timeout)
ProtonWatcher.waitForCondition(object : ProtonWatcher.Condition() {
var errorMessage = ""
override fun checkCondition() = try {
interaction.check(doesNotExist())
override fun getDescription() = "UICustomViewActions.waitUntilMatcherFulfilled $errorMessage"
override fun checkCondition(): Boolean {
return try {
interaction.check(assertion)
true
} catch (e: PerformException) {
errorMessage = "${e.viewDescription}, Action: ${e.actionDescription}"
false
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: NoMatchingViewException) {
errorMessage = e.viewMatcherDescription
false
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: NoMatchingRootException) {
false
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: AppNotIdleException) {
false
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: AmbiguousViewMatcherException) {
false
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: AssertionFailedError) {
false
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
}
})
} catch (e: Throwable) {
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
}
}
})
return interaction
}
fun performActionWithRetry(
interaction: ViewInteraction,
action: ViewAction,
timeout: Long = TIMEOUT_10S
): ViewInteraction {
ProtonWatcher.setTimeout(timeout)
ProtonWatcher.waitForCondition(object : ProtonWatcher.Condition() {
var errorMessage = ""
override fun getDescription() = "UICustomViewActions.waitUntilMatcherFulfilled $errorMessage"
override fun checkCondition(): Boolean {
return try {
interaction.perform(action)
true
} catch (e: PerformException) {
errorMessage = "${e.viewDescription}, Action: ${e.actionDescription}"
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: NoMatchingViewException) {
errorMessage = e.viewMatcherDescription
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: NoMatchingRootException) {
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: AppNotIdleException) {
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: AmbiguousViewMatcherException) {
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
} catch (e: AssertionFailedError) {
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw e
} else {
false
}
}
}
})
return interaction
}
fun waitUntilRecyclerViewPopulated(@IdRes id: Int, timeout: Long = TIMEOUT_10S) {
ProtonWatcher.setTimeout(timeout)
ProtonWatcher.waitForCondition(object : ProtonWatcher.Condition() {
var errorMessage = ""
override fun getDescription() =
"RecyclerView: ${targetContext.resources.getResourceName(id)} was not populated with items"
override fun checkCondition() = try {
val rv = ActivityProvider.currentActivity!!.findViewById<RecyclerView>(id)
waitUntilLoaded { rv }
rv.adapter!!.itemCount > 0
} catch (e: Exception) {
errorMessage = e.message.toString()
false
val rv = currentActivity!!.findViewById<RecyclerView>(id)
if (rv != null) {
waitUntilLoaded { rv }
rv.adapter!!.itemCount > 0
} else {
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw Exception(getDescription())
} else {
false
}
}
} catch (e: Throwable) {
throw e
}
})
}
@ -150,29 +226,28 @@ object UICustomViewActions {
) {
ProtonWatcher.setTimeout(timeout)
ProtonWatcher.waitForCondition(object : ProtonWatcher.Condition() {
var errorMessage = ""
override fun getDescription() =
"RecyclerView: ${targetContext.resources.getResourceName(recyclerViewId)} was not populated with items"
override fun checkCondition(): Boolean {
try {
val rv = ActivityProvider.currentActivity!!.findViewById<RecyclerView>(recyclerViewId)
val rv = currentActivity!!.findViewById<RecyclerView>(recyclerViewId)
waitUntilLoaded { rv }
var isMatches: Boolean
var actualText: String
for (i in 0..rv.adapter!!.itemCount) {
val item = rv.getChildAt(i)
if (item != null) {
actualText = item.findViewById<TextView>(viewId)?.text.toString()
isMatches = actualText == text
if (isMatches) {
return true
(rv.adapter!! as ContactsListAdapter).items.forEach {
return if (it.getEmail() == text) {
return true
} else {
if (ProtonWatcher.status == ProtonWatcher.TIMEOUT) {
throw Exception(getDescription())
} else {
false
}
}
}
} catch (e: Exception) {
errorMessage = e.message.toString()
throw e
}
return false
}
@ -219,9 +294,9 @@ object UICustomViewActions {
val recyclerView = view as RecyclerView
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val messageSubject = layoutManager.getChildAt(position)
?.findViewById<TextView>(R.id.messageTitleTextView)!!.text.toString()
?.findViewById<TextView>(R.id.messageTitleTextView)?.text.toString()
val messageDate = layoutManager.getChildAt(position)
?.findViewById<TextView>(R.id.messageDateTextView)!!.text.toString()
?.findViewById<TextView>(R.id.messageDateTextView)?.text.toString()
saveSubject.invoke(messageSubject, messageDate)
}
}