Updated ui tests and robots
This commit is contained in:
parent
995b785ca1
commit
5e739c94c8
|
@ -21,7 +21,7 @@ package me.proton.core.test.android.uitests.tests.medium.auth.signup
|
|||
import me.proton.android.core.coreexample.BuildConfig
|
||||
import me.proton.core.test.android.instrumented.utils.StringUtils.randomString
|
||||
import me.proton.core.test.android.plugins.data.User
|
||||
import me.proton.core.test.android.plugins.data.Plan.Free
|
||||
import me.proton.core.test.android.plugins.data.Plan.Dev
|
||||
import me.proton.core.test.android.robots.CoreRobot
|
||||
import me.proton.core.test.android.robots.auth.ChooseUsernameRobot
|
||||
import me.proton.core.test.android.robots.humanverification.CodeVerificationRobot
|
||||
|
@ -76,6 +76,6 @@ class ExternalSetupTests : BaseTest() {
|
|||
.setAndConfirmPassword<CodeVerificationRobot>(user.password)
|
||||
.setCode(defaultCode)
|
||||
.verifyCode<SelectPlanRobot>()
|
||||
.verify { canSelectPlan(Free) }
|
||||
.verify { canSelectPlan(Dev) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import me.proton.core.test.android.robots.auth.signup.RecoveryMethodsRobot
|
|||
import me.proton.core.test.android.robots.auth.signup.RecoveryMethodsRobot.RecoveryMethodType
|
||||
import me.proton.core.test.android.uitests.CoreexampleRobot
|
||||
import me.proton.core.test.android.uitests.tests.BaseTest
|
||||
import me.proton.core.test.android.plugins.data.Plan.Free
|
||||
import me.proton.core.test.android.plugins.data.Plan.Dev
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
|
@ -74,8 +74,8 @@ class RecoveryMethodsSetupTests : BaseTest() {
|
|||
.skip()
|
||||
.skipConfirm()
|
||||
.verify {
|
||||
planDetailsDisplayed(Free)
|
||||
canSelectPlan(Free)
|
||||
planDetailsDisplayed(Dev)
|
||||
canSelectPlan(Dev)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,8 +85,8 @@ class RecoveryMethodsSetupTests : BaseTest() {
|
|||
.next<RecoveryMethodsRobot.SkipRecoveryRobot>()
|
||||
.skipConfirm()
|
||||
.verify {
|
||||
planDetailsDisplayed(Free)
|
||||
canSelectPlan(Free)
|
||||
planDetailsDisplayed(Dev)
|
||||
canSelectPlan(Dev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import me.proton.core.test.android.uitests.tests.SmokeTest
|
|||
import me.proton.core.test.android.plugins.data.Plan.Free
|
||||
import me.proton.core.test.android.plugins.data.Plan.Dev
|
||||
import me.proton.core.test.android.plugins.data.User
|
||||
import me.proton.core.plan.R
|
||||
import me.proton.core.test.android.robots.auth.AddAccountRobot
|
||||
import me.proton.core.test.android.robots.auth.signup.RecoveryMethodsRobot
|
||||
import me.proton.core.test.android.robots.humanverification.HumanVerificationRobot
|
||||
|
@ -56,12 +55,6 @@ class SelectPlanTests : BaseTest() {
|
|||
@Test
|
||||
@SmokeTest
|
||||
fun selectFreeAndCancelHumanVerification() {
|
||||
selectPlanRobot
|
||||
.view.withId(R.id.scrollContent)
|
||||
.hasDescendant(
|
||||
selectPlanRobot.view.withId(R.id.plansView)
|
||||
).swipeUp()
|
||||
|
||||
selectPlanRobot
|
||||
.selectPlan<HumanVerificationRobot>(Free)
|
||||
.verify {
|
||||
|
|
|
@ -50,8 +50,7 @@ class ExistingPaymentMethodTests : BaseTest() {
|
|||
loginRobot
|
||||
.loginUser<CoreexampleRobot>(user)
|
||||
.plansUpgrade()
|
||||
.selectPlan(plan)
|
||||
|
||||
.upgradeToPlan(plan)
|
||||
|
||||
@Test
|
||||
@Ignore("Requires user with paypal account linked")
|
||||
|
|
|
@ -45,8 +45,8 @@ class NewCreditCardTests : BaseTest() {
|
|||
.loginUser<CoreexampleRobot>(userWithoutCard)
|
||||
.plansUpgrade()
|
||||
.changeCurrency(Currency.CHF)
|
||||
.selectPlan<AddCreditCardRobot>(Plan.Dev)
|
||||
.verify { billingDetailsDisplayed(Plan.Dev, BillingCycle.Yearly, Currency.CHF.symbol, 47.88) }
|
||||
.upgradeToPlan<AddCreditCardRobot>(Plan.Dev)
|
||||
.verify { billingDetailsDisplayed(Plan.Dev, BillingCycle.Yearly, Currency.CHF.symbol) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -49,10 +49,10 @@ class CurrentPlanTests : BaseTest() {
|
|||
fun userWithFreePlan() {
|
||||
val freeUser = users.getUser { !it.isPaid }
|
||||
navigateUserToCurrentPlans(freeUser)
|
||||
.scrollToPlan(Plan.Dev)
|
||||
.verify {
|
||||
canSelectPlan(Plan.Dev)
|
||||
canUpgradeToPlan(Plan.Dev)
|
||||
planDetailsDisplayed(Plan.Dev)
|
||||
planDetailsDisplayed(Plan.Free)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,8 +57,9 @@ class UpgradePlanTests : BaseTest() {
|
|||
@SmokeTest
|
||||
fun userWithFreePlan() {
|
||||
navigateUserToCurrentPlans(freeUser)
|
||||
.scrollToPlan(Plan.Dev)
|
||||
.verify {
|
||||
canSelectPlan(Plan.Dev)
|
||||
canUpgradeToPlan(Plan.Dev)
|
||||
planDetailsDisplayed(Plan.Dev)
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ import org.junit.runner.Description
|
|||
open class ProtonTest(
|
||||
private val activity: Class<out Activity>,
|
||||
defaultTimeout: Long = 10_000L,
|
||||
tries: Int = 2,
|
||||
tries: Int = 1,
|
||||
testWatcher: TestWatcher = TestExecutionWatcher(),
|
||||
activityScenarioRule: ActivityScenarioRule<out Activity> = ActivityScenarioRule(activity),
|
||||
) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package me.proton.core.test.android.instrumented.builders
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.PerformException
|
||||
|
@ -33,6 +34,7 @@ import androidx.test.espresso.contrib.RecyclerViewActions.actionOnHolderItem
|
|||
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import me.proton.core.test.android.instrumented.ui.Actions.clickOnMatchedDescendant
|
||||
import me.proton.core.test.android.instrumented.utils.StringUtils
|
||||
import org.hamcrest.Matcher
|
||||
import org.hamcrest.core.AllOf
|
||||
|
||||
|
@ -65,6 +67,10 @@ class OnRecyclerView : ConditionWatcher {
|
|||
matchers.add(ViewMatchers.withText(text))
|
||||
}
|
||||
|
||||
fun withText(@StringRes textId: Int) = apply {
|
||||
matchers.add(ViewMatchers.withText(StringUtils.stringFromResource(textId)))
|
||||
}
|
||||
|
||||
/** [RecyclerViewActions] **/
|
||||
fun click() = apply {
|
||||
perform(ViewActions.click())
|
||||
|
@ -94,6 +100,10 @@ class OnRecyclerView : ConditionWatcher {
|
|||
perform(ViewActions.swipeUp())
|
||||
}
|
||||
|
||||
fun scrollTo() = apply {
|
||||
perform(ViewActions.scrollTo())
|
||||
}
|
||||
|
||||
fun waitUntilGone() = apply {
|
||||
waitForCondition({ viewInteraction().check(ViewAssertions.doesNotExist()) })
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import me.proton.core.test.android.instrumented.ProtonTest.Companion.getTargetCo
|
|||
@Serializable
|
||||
enum class Plan(var planName: String, var text: String) {
|
||||
Free("free", "Free"),
|
||||
Professional("pro", "Professional"),
|
||||
Professional("pro", "ProtonMail Professional"),
|
||||
Visionary("visionary", "Visionary"),
|
||||
Plus("plus", "ProtonMail Plus"),
|
||||
Dev("", "")
|
||||
|
@ -36,9 +36,10 @@ fun randomPaidPlan(): Plan = Plan.values().filter { it != Plan.Free }.random()
|
|||
val supportedBillingCycles: Array<String> =
|
||||
getTargetContext().resources.getStringArray(R.array.supported_billing_cycle)
|
||||
|
||||
enum class BillingCycle(val value: String) {
|
||||
Monthly(supportedBillingCycles[0]),
|
||||
Yearly(supportedBillingCycles[1]),
|
||||
enum class BillingCycle(val value: String, val monthlyPrice: Double, val yearlyPrice: Number) {
|
||||
Monthly(supportedBillingCycles[0], 5.00, 0.00),
|
||||
Yearly(supportedBillingCycles[1], 4.00, 48.00),
|
||||
TwoYear(supportedBillingCycles[2], 3.29, 39.48)
|
||||
}
|
||||
|
||||
enum class Currency(val symbol: String, val code: String) {
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package me.proton.core.test.android.robots.payments
|
||||
|
||||
import android.widget.EditText
|
||||
import me.proton.core.payment.presentation.R
|
||||
import me.proton.core.test.android.plugins.data.BillingCycle
|
||||
import me.proton.core.test.android.plugins.data.Plan
|
||||
|
@ -41,12 +40,12 @@ open class PaymentRobot : CoreRobot() {
|
|||
fun billingDetailsDisplayed(
|
||||
plan: Plan,
|
||||
billingCycle: BillingCycle,
|
||||
currency: String,
|
||||
amount: Number
|
||||
currency: String
|
||||
) {
|
||||
val yearlyPriceString = String.format("%.2f", billingCycle.yearlyPrice)
|
||||
view.withId(R.id.planNameText).withText(plan.text).checkDisplayed()
|
||||
view.withId(R.id.billingPeriodText).withText("Billed ${billingCycle.toString().lowercase()}").checkDisplayed()
|
||||
view.withId(R.id.amountText).withText("$currency$amount").checkDisplayed()
|
||||
view.withId(R.id.amountText).withText("$currency$yearlyPriceString").checkDisplayed()
|
||||
}
|
||||
|
||||
fun paymentMethodDisplayed(title: String, details: String) {
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
package me.proton.core.test.android.robots.plans
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import me.proton.core.plan.presentation.R
|
||||
import me.proton.core.test.android.instrumented.utils.StringUtils.stringFromResource
|
||||
import me.proton.core.test.android.plugins.data.BillingCycle
|
||||
|
@ -26,15 +28,51 @@ import me.proton.core.test.android.plugins.data.Plan
|
|||
import me.proton.core.test.android.robots.CoreRobot
|
||||
import me.proton.core.test.android.robots.CoreVerify
|
||||
|
||||
|
||||
class SelectPlanRobot : CoreRobot() {
|
||||
|
||||
/**
|
||||
* Scrolls to a provided [plan]
|
||||
* @return an instance of [SelectPlanRobot]
|
||||
*/
|
||||
fun scrollToPlan(plan: Plan): SelectPlanRobot {
|
||||
// Only one paid plan is currently implemented
|
||||
val position = when (plan) {
|
||||
Plan.Dev -> 0
|
||||
Plan.Free -> 1
|
||||
else -> -1
|
||||
}
|
||||
|
||||
recyclerView.withId(R.id.planListRecyclerView)
|
||||
.onItemAtPosition(position).scrollTo()
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks 'Select' button on a provided [plan]
|
||||
* @param T next Robot in flow
|
||||
* @return an instance of [T]
|
||||
*/
|
||||
inline fun <reified T> selectPlan(plan: Plan): T {
|
||||
view.withText(R.string.plans_select_plan)
|
||||
inline fun <reified T> selectPlan(plan: Plan): T =
|
||||
scrollToPlan(plan)
|
||||
.clickPlanButtonWithText(plan, R.string.plans_select_plan)
|
||||
|
||||
/**
|
||||
* Clicks 'Upgrade' button on a provided [plan]
|
||||
* @param T next Robot in flow
|
||||
* @return an instance of [T]
|
||||
*/
|
||||
inline fun <reified T> upgradeToPlan(plan: Plan): T =
|
||||
scrollToPlan(plan)
|
||||
.clickPlanButtonWithText(plan, R.string.plans_upgrade_plan)
|
||||
|
||||
/**
|
||||
* Clicks button with [textId] resource on a provided [plan]
|
||||
* @param T next Robot in flow
|
||||
* @return an instance of [T]
|
||||
*/
|
||||
inline fun <reified T> clickPlanButtonWithText(plan: Plan, @StringRes textId: Int): T {
|
||||
view.withText(textId)
|
||||
.isDescendantOf(
|
||||
view.withId(R.id.planGroup).hasSibling(
|
||||
view.withText(plan.text)
|
||||
|
@ -47,6 +85,7 @@ class SelectPlanRobot : CoreRobot() {
|
|||
* Changes billing cycle to provided [billingCycle]
|
||||
*/
|
||||
fun changeBillingCycle(billingCycle: BillingCycle): SelectPlanRobot {
|
||||
view.instanceOf(NestedScrollView::class.java).swipeDown()
|
||||
view.withId(R.id.billingCycleSpinner).click()
|
||||
view.withText(billingCycle.value).click()
|
||||
return this
|
||||
|
@ -56,12 +95,15 @@ class SelectPlanRobot : CoreRobot() {
|
|||
* Changes currency to provided [currency]
|
||||
*/
|
||||
fun changeCurrency(currency: Currency): SelectPlanRobot {
|
||||
view.withId(R.id.billingCycleSpinner).checkDisplayed()
|
||||
view.instanceOf(NestedScrollView::class.java).swipeUp()
|
||||
view.withId(R.id.currencySpinner).click()
|
||||
view.withText(currency.code).click()
|
||||
return this
|
||||
}
|
||||
|
||||
class Verify : CoreVerify() {
|
||||
|
||||
fun planDetailsDisplayed(plan: Plan) {
|
||||
view.withText(plan.text).checkDisplayed()
|
||||
}
|
||||
|
@ -75,17 +117,27 @@ class SelectPlanRobot : CoreRobot() {
|
|||
).checkDisplayed()
|
||||
}
|
||||
|
||||
fun canUpgradeToPlan(plan: Plan) {
|
||||
view.withText(R.string.plans_upgrade_plan)
|
||||
.isDescendantOf(
|
||||
view.withId(R.id.planGroup).hasSibling(
|
||||
view.withText(plan.text)
|
||||
)
|
||||
).checkDisplayed()
|
||||
}
|
||||
|
||||
fun billingCycleIs(billingCycle: BillingCycle, currency: Currency = Currency.Euro) {
|
||||
// TODO: re-work to reflect 4.5 design
|
||||
view.withId(R.id.planPriceText).withText("${currency.symbol}${billingCycle.monthlyPrice}")
|
||||
when (billingCycle) {
|
||||
BillingCycle.Monthly -> {
|
||||
view.withId(R.id.planPriceText).withText("${currency.symbol}4.99")
|
||||
view.withText(R.string.plans_save_20).checkDisplayed()
|
||||
}
|
||||
BillingCycle.Yearly -> {
|
||||
else -> {
|
||||
val yearlyPriceString = String.format("%.2f", billingCycle.yearlyPrice)
|
||||
val billedAsString =
|
||||
stringFromResource(R.string.plans_billed_yearly).format("${currency.symbol}47.88")
|
||||
view.withId(R.id.planPriceDescriptionText).checkContains(billedAsString)
|
||||
view.withId(R.id.planPriceText).checkContains("${currency.symbol}3.99")
|
||||
stringFromResource(R.string.plans_billed_yearly).format("${currency.symbol}$yearlyPriceString")
|
||||
view.withId(R.id.planPriceDescriptionText).withText(billedAsString).checkDisplayed()
|
||||
view.withText(R.string.plans_renew_info).checkDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue