summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNiklas Berglund <niklas.berglund@gmail.com>2024-10-18 11:08:01 +0200
committerDavid Göransson <david.goransson@mullvad.net>2024-12-03 08:34:59 +0100
commitf59eb65f21621092ee21c292b7ae1da0518a09ac (patch)
treee3f6a68e2d62e404f2170c8ae2d53fb6ff2c1975
parent46ec55fa5a9f249058d999a5c50fc094f4f46930 (diff)
downloadmullvadvpn-f59eb65f21621092ee21c292b7ae1da0518a09ac.tar.xz
mullvadvpn-f59eb65f21621092ee21c292b7ae1da0518a09ac.zip
Implement basic of page object pattern
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/ConnectPage.kt10
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/LoginPage.kt29
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/Page.kt16
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/PrivacyPage.kt38
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt44
5 files changed, 119 insertions, 18 deletions
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/ConnectPage.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/ConnectPage.kt
new file mode 100644
index 0000000000..fe1fafcc7f
--- /dev/null
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/ConnectPage.kt
@@ -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"))
+ }
+}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/LoginPage.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/LoginPage.kt
new file mode 100644
index 0000000000..9fdffe1eae
--- /dev/null
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/LoginPage.kt
@@ -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"))
+ }
+}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/Page.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/Page.kt
new file mode 100644
index 0000000000..3caac5bd95
--- /dev/null
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/Page.kt
@@ -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()
+}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/PrivacyPage.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/PrivacyPage.kt
new file mode 100644
index 0000000000..43ec183c50
--- /dev/null
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/PrivacyPage.kt
@@ -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)"
+ )
+ }
+ }
+}
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt
index 5a5d70fc9f..bfd78422c0 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt
@@ -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
@@ -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()
+ }
}
}