Skip to content

Commit

Permalink
Merge branch 'create-a-pop-wip-poc-pr-droid-1435'
Browse files Browse the repository at this point in the history
  • Loading branch information
Rawa committed Dec 3, 2024
2 parents 46ec55f + f59eb65 commit ce8c122
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package net.mullvad.mullvadvpn.test.common.page

import androidx.test.uiautomator.By
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class ConnectPage internal constructor() : Page() {
override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(By.res("connect_card_header_test_tag"))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package net.mullvad.mullvadvpn.test.common.page

import android.widget.Button
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import net.mullvad.mullvadvpn.test.common.constant.DEFAULT_TIMEOUT
import net.mullvad.mullvadvpn.test.common.constant.EXTREMELY_LONG_TIMEOUT
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class LoginPage internal constructor() : Page() {
fun enterAccountNumber(accountNumber: String) {
uiDevice.findObjectWithTimeout(By.clazz("android.widget.EditText")).text = accountNumber
}

fun tapLoginButton() {
val accountTextField = uiDevice.findObjectWithTimeout(By.clazz("android.widget.EditText"))
val loginButton = accountTextField.parent.findObject(By.clazz(Button::class.java))
loginButton.wait(Until.enabled(true), DEFAULT_TIMEOUT)
loginButton.click()
}

fun verifyShowingInvalidAccount() {
uiDevice.findObjectWithTimeout(By.text("Invalid account number"), EXTREMELY_LONG_TIMEOUT)
}

override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(By.text("Login"))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.mullvad.mullvadvpn.test.common.page

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice

sealed class Page {
protected val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

abstract fun assertIsDisplayed()
}

inline fun <reified T : Page> on(scope: T.() -> Unit = {}) {
val page = T::class.java.getConstructor().newInstance()
page.assertIsDisplayed()
return page.scope()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package net.mullvad.mullvadvpn.test.common.page

import android.os.Build
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import net.mullvad.mullvadvpn.test.common.constant.DEFAULT_TIMEOUT
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class PrivacyPage internal constructor() : Page() {
override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(By.text("Privacy"))
}

fun clickAgreeOnPrivacyDisclaimer() {
uiDevice.findObjectWithTimeout(By.text("Agree and continue")).click()
}

fun clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove(
timeout: Long = DEFAULT_TIMEOUT
) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
// Skipping as notification permissions are not shown.
return
}

val selector = By.text("Allow")

uiDevice.wait(Until.hasObject(selector), timeout)

try {
uiDevice.findObjectWithTimeout(selector).click()
} catch (e: IllegalArgumentException) {
throw IllegalArgumentException(
"Failed to allow notification permission within timeout ($timeout)"
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package net.mullvad.mullvadvpn.test.e2e

import androidx.test.uiautomator.By
import net.mullvad.mullvadvpn.test.common.constant.EXTREMELY_LONG_TIMEOUT
import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
import net.mullvad.mullvadvpn.test.common.page.ConnectPage
import net.mullvad.mullvadvpn.test.common.page.LoginPage
import net.mullvad.mullvadvpn.test.common.page.PrivacyPage
import net.mullvad.mullvadvpn.test.common.page.on
import net.mullvad.mullvadvpn.test.e2e.misc.AccountTestRule
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
Expand All @@ -16,30 +15,39 @@ class LoginTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {

@Test
fun testLoginWithValidCredentials() {
// Given
val validTestAccountNumber = accountTestRule.validAccountNumber

// When
app.launchAndEnsureLoggedIn(validTestAccountNumber)
app.launch()

on<PrivacyPage> {
clickAgreeOnPrivacyDisclaimer()
clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
}

// Then
app.ensureLoggedIn()
on<LoginPage> {
enterAccountNumber(validTestAccountNumber)
tapLoginButton()
}

on<ConnectPage>()
}

@Test
@Disabled("Failed login attempts are highly rate limited and cause test flakiness")
fun testLoginWithInvalidCredentials() {
// Given
val invalidDummyAccountNumber = accountTestRule.invalidAccountNumber

// When
app.launch()
device.clickAgreeOnPrivacyDisclaimer()
device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
app.waitForLoginPrompt()
app.attemptLogin(invalidDummyAccountNumber)

// Then
device.findObjectWithTimeout(By.text("Invalid account number"), EXTREMELY_LONG_TIMEOUT)
on<PrivacyPage> {
clickAgreeOnPrivacyDisclaimer()
clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
}

on<LoginPage> {
enterAccountNumber(invalidDummyAccountNumber)
tapLoginButton()
verifyShowingInvalidAccount()
}
}
}

0 comments on commit ce8c122

Please sign in to comment.