summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2025-05-12 14:10:59 +0200
committerDavid Göransson <david.goransson@mullvad.net>2025-05-12 14:10:59 +0200
commit64baf404f469ff7ec8f2842663cbf5bb548c7304 (patch)
tree8195719809c07921056735b991c6fb797ce8adf9
parent405b0be1f551906890be84f5e8aca3539b6bcfbf (diff)
parent069e7a52de87e665f7fdae8a664182f23150da55 (diff)
downloadmullvadvpn-64baf404f469ff7ec8f2842663cbf5bb548c7304.tar.xz
mullvadvpn-64baf404f469ff7ec8f2842663cbf5bb548c7304.zip
Merge branch 'convert-tests-page-pattern'
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/extension/UiAutomatorExtensions.kt39
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt138
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/misc/CaptureScreenRecordingsExtension.kt3
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/LoginPage.kt12
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/OutOfTimePage.kt13
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/TooManyDevicesPage.kt46
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/WelcomePage.kt25
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/WireGuardCustomPortDialog.kt4
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/CaptureScreenshotOnFailedTestRule.kt2
-rw-r--r--android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/ForgetAllVpnAppsInSettingsTestRule.kt19
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt15
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/EndToEndTest.kt11
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LaunchAppTest.kt2
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LeakTest.kt4
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt6
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LogoutTest.kt4
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/WebLinkTest.kt2
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/constant/TextConstants.kt4
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/interactor/SystemSettingsInteractor.kt33
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt44
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt36
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/CreateAccountMockApiTest.kt41
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt34
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt27
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/ManageDevicesMockApiTest.kt15
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt6
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt38
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/constant/Constants.kt14
28 files changed, 245 insertions, 392 deletions
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/extension/UiAutomatorExtensions.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/extension/UiAutomatorExtensions.kt
index aa993025f5..c14be06208 100644
--- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/extension/UiAutomatorExtensions.kt
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/extension/UiAutomatorExtensions.kt
@@ -1,6 +1,5 @@
package net.mullvad.mullvadvpn.test.common.extension
-import android.os.Build
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.StaleObjectException
@@ -18,10 +17,6 @@ fun UiDevice.findObjectByCaseInsensitiveText(text: String): UiObject2 {
return findObjectWithTimeout(By.text(Pattern.compile(text, Pattern.CASE_INSENSITIVE)))
}
-fun UiObject2.findObjectByCaseInsensitiveText(text: String): UiObject2 {
- return findObjectWithTimeout(By.text(Pattern.compile(text, Pattern.CASE_INSENSITIVE)))
-}
-
fun UiDevice.hasObjectWithTimeout(selector: BySelector, timeout: Long = DEFAULT_TIMEOUT): Boolean =
wait(Until.hasObject(selector), timeout)
@@ -89,40 +84,6 @@ fun UiDevice.clickObjectAwaitIsChecked(selector: BySelector, timeout: Long = LON
)
}
-fun UiDevice.clickAgreeOnPrivacyDisclaimer() {
- findObjectWithTimeout(By.text("Agree and continue")).click()
-}
-
-// The dialog will only be shown when there's a new version code and bundled release notes.
-fun UiDevice.dismissChangelogDialogIfShown() {
- try {
- findObjectWithTimeout(By.text("Got it!")).click()
- } catch (e: IllegalArgumentException) {
- // This is OK since it means the changes dialog wasn't shown.
- }
-}
-
-fun UiDevice.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")
-
- wait(Until.hasObject(selector), timeout)
-
- try {
- findObjectWithTimeout(selector).click()
- } catch (e: IllegalArgumentException) {
- throw IllegalArgumentException(
- "Failed to allow notification permission within timeout ($timeout ms)"
- )
- }
-}
-
fun UiDevice.pressBackTwice() {
pressBack()
pressBack()
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt
index b3a35d21e3..7bf2a5911d 100644
--- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt
@@ -2,37 +2,29 @@ package net.mullvad.mullvadvpn.test.common.interactor
import android.content.Context
import android.content.Intent
-import android.widget.Button
+import android.os.Build
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointOverride
import net.mullvad.mullvadvpn.lib.endpoint.putApiEndpointConfigurationExtra
-import net.mullvad.mullvadvpn.lib.ui.tag.CONNECT_CARD_HEADER_TEST_TAG
-import net.mullvad.mullvadvpn.lib.ui.tag.LOCATION_INFO_CONNECTION_IN_TEST_TAG
-import net.mullvad.mullvadvpn.lib.ui.tag.LOCATION_INFO_CONNECTION_OUT_TEST_TAG
-import net.mullvad.mullvadvpn.lib.ui.tag.OUT_OF_TIME_SCREEN_TITLE_TEST_TAG
-import net.mullvad.mullvadvpn.lib.ui.tag.TOP_BAR_ACCOUNT_BUTTON_TEST_TAG
-import net.mullvad.mullvadvpn.lib.ui.tag.TOP_BAR_SETTINGS_BUTTON_TEST_TAG
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.constant.LONG_TIMEOUT
-import net.mullvad.mullvadvpn.test.common.constant.VERY_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.dismissChangelogDialogIfShown
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
+import net.mullvad.mullvadvpn.test.common.page.LoginPage
+import net.mullvad.mullvadvpn.test.common.page.on
class AppInteractor(
private val device: UiDevice,
private val targetContext: Context,
- private val targetPackageName: String,
+ private val customApiEndpointConfiguration: ApiEndpointOverride? = null,
) {
- fun launch(customApiEndpointConfiguration: ApiEndpointOverride? = null) {
+ fun launch() {
device.pressHome()
// Wait for launcher
device.wait(Until.hasObject(By.pkg(device.launcherPackageName).depth(0)), LONG_TIMEOUT)
+ val targetPackageName = targetContext.packageName
val intent =
targetContext.packageManager.getLaunchIntentForPackage(targetPackageName)?.apply {
// Clear out any previous instances
@@ -47,111 +39,41 @@ class AppInteractor(
fun launchAndEnsureOnLoginPage() {
launch()
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- waitForLoginPrompt()
+ clickAgreeOnPrivacyDisclaimer()
+ clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
+ on<LoginPage>()
}
- fun launchAndEnsureLoggedIn(accountNumber: String) {
+ fun launchAndLogIn(accountNumber: String) {
launchAndEnsureOnLoginPage()
- attemptLogin(accountNumber)
- device.dismissChangelogDialogIfShown()
- ensureLoggedIn()
- }
-
- fun attemptLogin(accountNumber: String) {
- val loginObject =
- device.findObjectWithTimeout(By.clazz("android.widget.EditText")).apply {
- text = accountNumber
- }
- val loginButton = loginObject.parent.findObject(By.clazz(Button::class.java))
- loginButton.wait(Until.enabled(true), DEFAULT_TIMEOUT)
- loginButton.click()
- }
-
- fun attemptCreateAccount() {
- device.findObjectWithTimeout(By.text("Create account")).click()
- }
-
- fun ensureAccountCreated(accountNumber: String? = null) {
- device.findObjectWithTimeout(By.text("Congrats!"), VERY_LONG_TIMEOUT)
- accountNumber?.let { device.findObjectWithTimeout(By.text(accountNumber), DEFAULT_TIMEOUT) }
- }
-
- fun ensureAccountCreationFailed() {
- device.findObjectWithTimeout(By.text("Failed to create account"), EXTREMELY_LONG_TIMEOUT)
- }
-
- fun ensureLoggedIn() {
- device.findObjectWithTimeout(By.text("DISCONNECTED"), VERY_LONG_TIMEOUT)
- }
-
- fun ensureOutOfTime() {
- device.findObjectWithTimeout(By.res(OUT_OF_TIME_SCREEN_TITLE_TEST_TAG))
- }
-
- fun ensureAccountScreen() {
- device.findObjectWithTimeout(By.text("Account"))
- }
-
- fun extractOutIpv4Address(): String {
- device.findObjectWithTimeout(By.res(CONNECT_CARD_HEADER_TEST_TAG)).click()
- return device
- .findObjectWithTimeout(
- // Text exist and contains IP address
- By.res(LOCATION_INFO_CONNECTION_OUT_TEST_TAG).textContains("."),
- VERY_LONG_TIMEOUT,
- )
- .text
- }
-
- fun extractInIpv4Address(): String {
- device.findObjectWithTimeout(By.res(CONNECT_CARD_HEADER_TEST_TAG)).click()
- val inString =
- device
- .findObjectWithTimeout(
- By.res(LOCATION_INFO_CONNECTION_IN_TEST_TAG),
- VERY_LONG_TIMEOUT,
- )
- .text
-
- val extractedIpAddress = inString.split(" ")[0].split(":")[0]
- return extractedIpAddress
- }
-
- fun clickSettingsCog() {
- device.findObjectWithTimeout(By.res(TOP_BAR_SETTINGS_BUTTON_TEST_TAG)).click()
- }
-
- fun clickAccountCog() {
- device.findObjectWithTimeout(By.res(TOP_BAR_ACCOUNT_BUTTON_TEST_TAG)).click()
+ on<LoginPage> {
+ enterAccountNumber(accountNumber)
+ clickLoginButton()
+ }
}
- fun clickListItemByText(text: String) {
- device.findObjectWithTimeout(By.text(text)).click()
+ private fun clickAgreeOnPrivacyDisclaimer() {
+ device.findObjectWithTimeout(By.text("Agree and continue")).click()
}
- fun clickActionButtonByText(text: String) {
- device.findObjectWithTimeout(By.text(text)).click()
- }
+ private fun clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove(
+ timeout: Long = DEFAULT_TIMEOUT
+ ) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+ // Skipping as notification permissions are not shown.
+ return
+ }
- fun waitForLoginPrompt(timeout: Long = VERY_LONG_TIMEOUT) {
- device.findObjectWithTimeout(By.text("Login"), timeout)
- }
+ val selector = By.text("Allow")
- fun attemptToRemoveDevice() {
- device.findObjectWithTimeout(By.desc("Remove")).click()
- clickActionButtonByText("Yes, log out device")
- }
+ device.wait(Until.hasObject(selector), timeout)
- fun dismissStorePasswordPromptIfShown() {
try {
- device.waitForIdle()
- val selector = By.textContains("password")
- device.wait(Until.hasObject(selector), DEFAULT_TIMEOUT)
- device.pressBack()
- } catch (e: IllegalArgumentException) {
- // This is OK since it means the password prompt wasn't shown.
+ device.findObjectWithTimeout(selector).click()
+ } catch (_: IllegalArgumentException) {
+ throw IllegalArgumentException(
+ "Failed to allow notification permission within timeout ($timeout ms)"
+ )
}
}
}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/misc/CaptureScreenRecordingsExtension.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/misc/CaptureScreenRecordingsExtension.kt
index 21cc915482..de804ccb8e 100644
--- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/misc/CaptureScreenRecordingsExtension.kt
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/misc/CaptureScreenRecordingsExtension.kt
@@ -34,7 +34,7 @@ class CaptureScreenRecordingsExtension : BeforeEachCallback, AfterEachCallback {
}
private fun startScreenRecord(fileName: String) {
- if (File(OUTPUT_DIRECTORY).exists().not()) {
+ if (!File(OUTPUT_DIRECTORY).exists()) {
File(OUTPUT_DIRECTORY).mkdirs()
}
@@ -49,6 +49,7 @@ class CaptureScreenRecordingsExtension : BeforeEachCallback, AfterEachCallback {
device.executeShellCommand("pkill -2 screenrecord")
runBlocking { job.join() }
} catch (e: Exception) {
+ Logger.e("Failed to stop recording", e)
fail("Failed to stop screen recording")
}
}
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
index 173fde50fa..223ea378c6 100644
--- 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
@@ -20,17 +20,27 @@ class LoginPage internal constructor() : Page() {
uiDevice.findObjectWithTimeout(By.clazz("android.widget.EditText")).text = accountNumber
}
- fun tapLoginButton() {
+ fun clickLoginButton() {
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 clickCreateAccount() {
+ uiDevice.findObjectWithTimeout(By.text("Create account")).click()
+ }
+
fun verifyShowingInvalidAccount() {
uiDevice.findObjectWithTimeout(invalidAccountNumberSelector, EXTREMELY_LONG_TIMEOUT)
}
+ fun assertHasAccountHistory(accountNumber: String) {
+ // This can be improved, if we've entered the same account number in the TextField we might
+ // get a false positive.
+ uiDevice.findObjectWithTimeout(By.text(accountNumber))
+ }
+
override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(loginSelector)
}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/OutOfTimePage.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/OutOfTimePage.kt
new file mode 100644
index 0000000000..33e11f4a2e
--- /dev/null
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/OutOfTimePage.kt
@@ -0,0 +1,13 @@
+package net.mullvad.mullvadvpn.test.common.page
+
+import androidx.test.uiautomator.By
+import net.mullvad.mullvadvpn.lib.ui.tag.OUT_OF_TIME_SCREEN_TITLE_TEST_TAG
+import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
+
+class OutOfTimePage internal constructor() : Page() {
+ private val outOfTimeSelector = By.res(OUT_OF_TIME_SCREEN_TITLE_TEST_TAG)
+
+ override fun assertIsDisplayed() {
+ uiDevice.findObjectWithTimeout(outOfTimeSelector)
+ }
+}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/TooManyDevicesPage.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/TooManyDevicesPage.kt
new file mode 100644
index 0000000000..2f5f8c4133
--- /dev/null
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/TooManyDevicesPage.kt
@@ -0,0 +1,46 @@
+package net.mullvad.mullvadvpn.test.common.page
+
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.waitForStableInActiveWindow
+import net.mullvad.mullvadvpn.test.common.extension.expectObjectToDisappearWithTimeout
+import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
+
+class TooManyDevicesPage internal constructor() : Page() {
+ private val tooManyDevicesSelector = By.text("Too many devices")
+
+ override fun assertIsDisplayed() {
+ uiDevice.findObjectWithTimeout(tooManyDevicesSelector)
+
+ // Assert that we have too many devices
+ // And that the continue with login button is disabled
+ uiDevice.findObjectWithTimeout(
+ By.text("Continue with login").hasParent(By.enabled((false)))
+ )
+ }
+
+ fun clickRemoveDevice(deviceName: String) {
+ val deviceRow = uiDevice.findObjectWithTimeout(By.text(deviceName)).parent
+ deviceRow.findObjectWithTimeout(By.desc("Remove")).click()
+ }
+
+ fun assertReadyToLogin() {
+ uiDevice.findObjectWithTimeout(By.text("Super!"))
+ }
+
+ fun clickContinueWithLogin() {
+ uiDevice.findObjectWithTimeout(By.text("Continue with login")).click()
+ }
+}
+
+/** Remove a device and click confirm on the confirmation dialog. */
+fun TooManyDevicesPage.removeDeviceFlow(deviceName: String) {
+ clickRemoveDevice(deviceName)
+
+ // Wait for the confirmation dialog to appear
+ uiDevice.waitForStableInActiveWindow()
+ // Confirm logout
+ uiDevice.findObjectWithTimeout(By.text("Yes, log out device")).click()
+
+ // Await the device to be removed
+ uiDevice.expectObjectToDisappearWithTimeout(By.text(deviceName))
+}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/WelcomePage.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/WelcomePage.kt
new file mode 100644
index 0000000000..4589f82e56
--- /dev/null
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/WelcomePage.kt
@@ -0,0 +1,25 @@
+package net.mullvad.mullvadvpn.test.common.page
+
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import net.mullvad.mullvadvpn.test.common.constant.DEFAULT_TIMEOUT
+import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
+
+class WelcomePage internal constructor() : Page() {
+ private val welcomeSelector = By.text("Congrats!")
+
+ override fun assertIsDisplayed() {
+ uiDevice.findObjectWithTimeout(welcomeSelector)
+ }
+}
+
+fun UiDevice.dismissStorePasswordPromptIfShown() {
+ try {
+ val selector = By.textContains("password")
+ wait(Until.hasObject(selector), DEFAULT_TIMEOUT)
+ pressBack()
+ } catch (_: IllegalArgumentException) {
+ // This is OK since it means the password prompt wasn't shown.
+ }
+}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/WireGuardCustomPortDialog.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/WireGuardCustomPortDialog.kt
index ee112a5d46..2966cdeccf 100644
--- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/WireGuardCustomPortDialog.kt
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/page/WireGuardCustomPortDialog.kt
@@ -23,8 +23,4 @@ class WireGuardCustomPortDialog internal constructor() : Page() {
fun clickCancel() {
uiDevice.findObjectWithTimeout(cancelSelector).click()
}
-
- companion object {
- const val TEXT_FIELD_TEST_TAG = "custom_port_dialog_input_test_tag"
- }
}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/CaptureScreenshotOnFailedTestRule.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/CaptureScreenshotOnFailedTestRule.kt
index ecabb3c60a..adb195fec8 100644
--- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/CaptureScreenshotOnFailedTestRule.kt
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/CaptureScreenshotOnFailedTestRule.kt
@@ -83,7 +83,7 @@ class CaptureScreenshotOnFailedTestRule(private val testTag: String) : TestWatch
)
.toFile()
.apply {
- if (exists().not()) {
+ if (!exists()) {
mkdirs()
}
}
diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/ForgetAllVpnAppsInSettingsTestRule.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/ForgetAllVpnAppsInSettingsTestRule.kt
index 2a4a4dfeb1..b1cd894871 100644
--- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/ForgetAllVpnAppsInSettingsTestRule.kt
+++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/ForgetAllVpnAppsInSettingsTestRule.kt
@@ -34,19 +34,16 @@ class ForgetAllVpnAppsInSettingsTestRule : BeforeTestExecutionCallback {
.filter { !it.isHardcodedVpn() }
.forEach { button ->
button.click()
-
- if (device.hasObjectWithTimeout(By.text(FORGET_VPN_VPN_BUTTON_TEXT))) {
- device.findObjectWithTimeout(By.text(FORGET_VPN_VPN_BUTTON_TEXT)).click()
- device
- .findObjectByCaseInsensitiveText(FORGET_VPN_VPN_CONFIRM_BUTTON_TEXT)
- .click()
+ if (device.hasObjectWithTimeout(By.text(FORGET_VPN_BUTTON_TEXT))) {
+ device.findObjectWithTimeout(By.text(FORGET_VPN_BUTTON_TEXT)).click()
+ device.findObjectByCaseInsensitiveText(FORGET_VPN_CONFIRM_BUTTON_TEXT).click()
} else if (device.hasObjectWithTimeout(By.text(DELETE_VPN_PROFILE_TEXT))) {
device.findObjectWithTimeout(By.text(DELETE_VPN_PROFILE_TEXT)).click()
device
.findObjectWithTimeout(By.text(DELETE_VPN_CONFIRM_BUTTON_TEXT_REGEXP))
.click()
- } else if (device.hasObjectWithTimeout(By.text(FORGET_VPN_BUTTON_TEXT))) {
- device.findObjectWithTimeout(By.text(FORGET_VPN_BUTTON_TEXT)).click()
+ } else if (device.hasObjectWithTimeout(By.text(FORGET_BUTTON_TEXT))) {
+ device.findObjectWithTimeout(By.text(FORGET_BUTTON_TEXT)).click()
} else {
fail("Unable to find forget or delete button")
}
@@ -61,10 +58,10 @@ class ForgetAllVpnAppsInSettingsTestRule : BeforeTestExecutionCallback {
companion object {
private val HARDCODED_VPN_PROFILE_NAMES = listOf("VPN by Google")
- private const val FORGET_VPN_VPN_BUTTON_TEXT = "Forget VPN"
- private const val FORGET_VPN_BUTTON_TEXT = "Forget" // Legacy VPN
+ private const val FORGET_VPN_BUTTON_TEXT = "Forget VPN"
+ private const val FORGET_BUTTON_TEXT = "Forget" // Legacy VPN
private const val DELETE_VPN_PROFILE_TEXT = "Delete VPN profile"
- private const val FORGET_VPN_VPN_CONFIRM_BUTTON_TEXT = "Forget"
+ private const val FORGET_VPN_CONFIRM_BUTTON_TEXT = "Forget"
// Samsung S22 shows "Delete"
// Stock Android shows "DELETE"
private val DELETE_VPN_CONFIRM_BUTTON_TEXT_REGEXP = Pattern.compile("DELETE|Delete")
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt
index e7761b163f..0908d8f4ed 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt
@@ -3,7 +3,6 @@ package net.mullvad.mullvadvpn.test.e2e
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.runTest
-import net.mullvad.mullvadvpn.BuildConfig
import net.mullvad.mullvadvpn.test.common.constant.EXTREMELY_LONG_TIMEOUT
import net.mullvad.mullvadvpn.test.common.page.ConnectPage
import net.mullvad.mullvadvpn.test.common.page.SelectLocationPage
@@ -25,7 +24,7 @@ import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.RegisterExtension
-class ConnectionTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
+class ConnectionTest : EndToEndTest() {
@RegisterExtension @JvmField val accountTestRule = AccountTestRule()
@@ -39,7 +38,7 @@ class ConnectionTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
@Test
fun testConnect() {
// Given
- app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber)
+ app.launchAndLogIn(accountTestRule.validAccountNumber)
on<ConnectPage> { clickConnect() }
@@ -51,7 +50,7 @@ class ConnectionTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
@Test
fun testConnectAndVerifyWithConnectionCheck() = runTest {
// Given
- app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber)
+ app.launchAndLogIn(accountTestRule.validAccountNumber)
on<ConnectPage> { clickConnect() }
@@ -74,7 +73,7 @@ class ConnectionTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
@HasDependencyOnLocalAPI
@ClearFirewallRules
fun testWireGuardObfuscationAutomatic() = runTest {
- app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber)
+ app.launchAndLogIn(accountTestRule.validAccountNumber)
on<ConnectPage> { enableLocalNetworkSharingStory() }
on<ConnectPage> { clickSelectLocation() }
@@ -111,7 +110,7 @@ class ConnectionTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
@HasDependencyOnLocalAPI
@ClearFirewallRules
fun testWireGuardObfuscationOff() = runTest {
- app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber)
+ app.launchAndLogIn(accountTestRule.validAccountNumber)
on<ConnectPage> { enableLocalNetworkSharingStory() }
on<ConnectPage> { clickSelectLocation() }
@@ -163,7 +162,7 @@ class ConnectionTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
@HasDependencyOnLocalAPI
@ClearFirewallRules
fun testUDPOverTCP() = runTest {
- app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber)
+ app.launchAndLogIn(accountTestRule.validAccountNumber)
on<ConnectPage> { enableLocalNetworkSharingStory() }
on<ConnectPage> { clickSelectLocation() }
@@ -212,7 +211,7 @@ class ConnectionTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
@HasDependencyOnLocalAPI
@ClearFirewallRules
fun testShadowsocks() = runTest {
- app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber)
+ app.launchAndLogIn(accountTestRule.validAccountNumber)
on<ConnectPage> { enableLocalNetworkSharingStory() }
on<ConnectPage> { disableObfuscationStory() }
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/EndToEndTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/EndToEndTest.kt
index f74355ae2a..e944dd3606 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/EndToEndTest.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/EndToEndTest.kt
@@ -16,7 +16,7 @@ import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.extension.RegisterExtension
@ExtendWith(CaptureScreenRecordingsExtension::class)
-abstract class EndToEndTest(private val infra: String) {
+abstract class EndToEndTest {
@RegisterExtension @JvmField val rule = CaptureScreenshotOnFailedTestRule(LOG_TAG)
@@ -43,14 +43,7 @@ abstract class EndToEndTest(private val infra: String) {
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
targetContext = InstrumentationRegistry.getInstrumentation().targetContext
- val targetPackageNameSuffix =
- when (infra) {
- "devmole" -> ".devmole"
- "stagemole" -> ".stagemole"
- else -> ""
- }
-
- app = AppInteractor(device, targetContext, "net.mullvad.mullvadvpn$targetPackageNameSuffix")
+ app = AppInteractor(device, targetContext)
}
companion object {
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LaunchAppTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LaunchAppTest.kt
index 724bffcad0..f68df92854 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LaunchAppTest.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LaunchAppTest.kt
@@ -2,7 +2,7 @@ package net.mullvad.mullvadvpn.test.e2e
import org.junit.jupiter.api.Test
-class LaunchAppTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
+class LaunchAppTest : EndToEndTest() {
@Test
fun testLaunchApp() {
app.launch()
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LeakTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LeakTest.kt
index 70146e9dc4..0ccc42e80b 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LeakTest.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LeakTest.kt
@@ -29,7 +29,7 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.RegisterExtension
-class LeakTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
+class LeakTest : EndToEndTest() {
@RegisterExtension @JvmField val accountTestRule = AccountTestRule()
@@ -39,7 +39,7 @@ class LeakTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
@BeforeEach
fun setupVPNSettings() {
- app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber)
+ app.launchAndLogIn(accountTestRule.validAccountNumber)
on<ConnectPage> { clickSettings() }
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 bfd78422c0..824f9b6aad 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
@@ -9,7 +9,7 @@ import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.RegisterExtension
-class LoginTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
+class LoginTest : EndToEndTest() {
@RegisterExtension @JvmField val accountTestRule = AccountTestRule()
@@ -26,7 +26,7 @@ class LoginTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
on<LoginPage> {
enterAccountNumber(validTestAccountNumber)
- tapLoginButton()
+ clickLoginButton()
}
on<ConnectPage>()
@@ -46,7 +46,7 @@ class LoginTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
on<LoginPage> {
enterAccountNumber(invalidDummyAccountNumber)
- tapLoginButton()
+ clickLoginButton()
verifyShowingInvalidAccount()
}
}
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LogoutTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LogoutTest.kt
index f99cfc5161..96678b3f26 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LogoutTest.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LogoutTest.kt
@@ -8,14 +8,14 @@ import net.mullvad.mullvadvpn.test.e2e.misc.AccountTestRule
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.RegisterExtension
-class LogoutTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
+class LogoutTest : EndToEndTest() {
@RegisterExtension @JvmField val accountTestRule = AccountTestRule()
@Test
fun testLogout() {
// Given
- app.launchAndEnsureLoggedIn(accountTestRule.validAccountNumber)
+ app.launchAndLogIn(accountTestRule.validAccountNumber)
on<ConnectPage> { clickAccount() }
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/WebLinkTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/WebLinkTest.kt
index 8d8467392c..1c2cbb6a4a 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/WebLinkTest.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/WebLinkTest.kt
@@ -7,7 +7,7 @@ import net.mullvad.mullvadvpn.test.common.page.SettingsPage
import net.mullvad.mullvadvpn.test.common.page.on
import org.junit.jupiter.api.Test
-class WebLinkTest : EndToEndTest(BuildConfig.FLAVOR_infrastructure) {
+class WebLinkTest : EndToEndTest() {
@Test
@SkipForFlavors(currentFlavor = BuildConfig.FLAVOR_billing, "play")
fun testOpenFaqFromApp() {
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/constant/TextConstants.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/constant/TextConstants.kt
deleted file mode 100644
index cfc4080ea4..0000000000
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/constant/TextConstants.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package net.mullvad.mullvadvpn.test.e2e.constant
-
-const val CONNECTION_CHECK_IS_CONNECTED = "Using Mullvad VPN"
-const val CONNECTION_CHECK_IS_NOT_CONNECTED = "Not using Mullvad VPN"
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/interactor/SystemSettingsInteractor.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/interactor/SystemSettingsInteractor.kt
deleted file mode 100644
index bcf4adcc9e..0000000000
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/interactor/SystemSettingsInteractor.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package net.mullvad.mullvadvpn.test.e2e.interactor
-
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import androidx.test.uiautomator.By
-import androidx.test.uiautomator.UiDevice
-import net.mullvad.mullvadvpn.test.common.extension.findObjectByCaseInsensitiveText
-
-class SystemSettingsInteractor(private val uiDevice: UiDevice, private val context: Context) {
- fun openVpnSettings() {
- val intent =
- Intent("com.intent.MAIN").apply {
- addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- }
- intent.component =
- ComponentName.unflattenFromString("com.android.settings/.Settings\$VpnSettingsActivity")
- context.startActivity(intent)
- Thread.sleep(1000)
- }
-
- fun removeAllVpnPermissions() {
- openVpnSettings()
- uiDevice.findObjects(By.descContains("Settings")).forEach {
- it.click()
- Thread.sleep(1000)
- uiDevice.findObjectByCaseInsensitiveText("forget vpn").click()
- Thread.sleep(1000)
- uiDevice.findObjectByCaseInsensitiveText("forget").click()
- }
- }
-}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt
index d89313fc45..7aec8f4725 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt
@@ -2,10 +2,11 @@ package net.mullvad.mullvadvpn.test.mockapi
import androidx.test.uiautomator.By
import java.time.ZonedDateTime
-import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
-import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
-import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
+import net.mullvad.mullvadvpn.test.common.page.AccountPage
+import net.mullvad.mullvadvpn.test.common.page.ConnectPage
+import net.mullvad.mullvadvpn.test.common.page.OutOfTimePage
+import net.mullvad.mullvadvpn.test.common.page.on
import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2
@@ -27,25 +28,18 @@ class AccountExpiryMockApiTest : MockApiTest() {
}
// Act
- app.launch(endpoint)
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptLogin(validAccountNumber)
-
- // Assert logged in
- device.dismissChangelogDialogIfShown()
- app.ensureLoggedIn()
+ app.launchAndLogIn(validAccountNumber)
// Add one month to the account expiry
val newAccountExpiry = oldAccountExpiry.plusMonths(1)
apiDispatcher.accountExpiry = newAccountExpiry
- // Go to account page to update the account expiry
- app.clickAccountCog()
+ on<ConnectPage> { clickAccount() }
- app.ensureAccountScreen()
- device.findObjectWithTimeout(By.text(newAccountExpiry.toExpiryDateString()))
+ on<AccountPage> {
+ // Assert that the account expiry date is updated
+ device.findObjectWithTimeout(By.text(newAccountExpiry.toExpiryDateString()))
+ }
}
@Test
@@ -61,28 +55,24 @@ class AccountExpiryMockApiTest : MockApiTest() {
}
// Act
- app.launch(endpoint)
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptLogin(validAccountNumber)
+ app.launchAndLogIn(validAccountNumber)
- // Assert logged in
- device.dismissChangelogDialogIfShown()
- app.ensureLoggedIn()
+ // Wait for us to be on connect page before changing expiry
+ on<ConnectPage>()
// Set account time as expired
val newAccountExpiry = oldAccountExpiry.minusMonths(2)
apiDispatcher.accountExpiry = newAccountExpiry
+ on<ConnectPage> { clickAccount() }
+
// Go to account page to update the account expiry
- app.clickAccountCog()
- app.ensureAccountScreen()
+ on<AccountPage>()
// Go back to the main screen
device.pressBack()
// Assert that we show the out of time screen
- app.ensureOutOfTime()
+ on<OutOfTimePage>()
}
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt
index 095ad66c64..2f15d83d09 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt
@@ -2,15 +2,14 @@ package net.mullvad.mullvadvpn.test.mockapi
import androidx.test.uiautomator.By
import java.time.ZonedDateTime
-import net.mullvad.mullvadvpn.lib.ui.tag.LOGIN_INPUT_TEST_TAG
-import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
-import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
-import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
+import net.mullvad.mullvadvpn.test.common.page.AccountPage
+import net.mullvad.mullvadvpn.test.common.page.ConnectPage
+import net.mullvad.mullvadvpn.test.common.page.LoginPage
+import net.mullvad.mullvadvpn.test.common.page.on
import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2
-import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Test
class AccountHistoryMockApiTest : MockApiTest() {
@@ -26,25 +25,18 @@ class AccountHistoryMockApiTest : MockApiTest() {
devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2
}
- // Act
- app.launch(endpoint)
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptLogin(validAccountNumber)
- device.dismissChangelogDialogIfShown()
- app.ensureLoggedIn()
- app.clickAccountCog()
- app.clickActionButtonByText("Log out")
- app.waitForLoginPrompt()
- device.findObjectWithTimeout(By.res(LOGIN_INPUT_TEST_TAG)).click()
+ app.launchAndLogIn(validAccountNumber)
+
+ on<ConnectPage> { clickAccount() }
+
+ on<AccountPage> { clickLogOut() }
- // Assert
val expectedResult = "1234 1234 1234 1234"
- assertNotNull(device.findObjectWithTimeout(By.text(expectedResult)))
+ on<LoginPage> {
+ assertHasAccountHistory(expectedResult)
+ device.findObjectWithTimeout(By.text(expectedResult)).click()
+ }
- // Try to login with the same account again
- device.findObjectWithTimeout(By.text(expectedResult)).click()
- app.ensureLoggedIn()
+ on<ConnectPage>()
}
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/CreateAccountMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/CreateAccountMockApiTest.kt
index 9b5cf85b95..259691f7df 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/CreateAccountMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/CreateAccountMockApiTest.kt
@@ -1,8 +1,11 @@
package net.mullvad.mullvadvpn.test.mockapi
-import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
-import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
-import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
+import androidx.test.uiautomator.By
+import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
+import net.mullvad.mullvadvpn.test.common.page.LoginPage
+import net.mullvad.mullvadvpn.test.common.page.WelcomePage
+import net.mullvad.mullvadvpn.test.common.page.dismissStorePasswordPromptIfShown
+import net.mullvad.mullvadvpn.test.common.page.on
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2
import org.junit.jupiter.api.Test
@@ -16,34 +19,26 @@ class CreateAccountMockApiTest : MockApiTest() {
expectedAccountNumber = createdAccountNumber
devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2
}
- app.launch(endpoint)
+ app.launchAndEnsureOnLoginPage()
- // Act
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptCreateAccount()
+ on<LoginPage> { clickCreateAccount() }
- app.dismissStorePasswordPromptIfShown()
+ device.dismissStorePasswordPromptIfShown()
- // Assert
- val expectedResult = "1234 1234 1234 1234"
- app.ensureAccountCreated(expectedResult)
+ on<WelcomePage> {
+ // Ensure account number is visible
+ device.findObjectWithTimeout(By.text("1234 1234 1234 1234"))
+ }
}
@Test
fun testCreateAccountFailed() {
// Arrange
- app.launch(endpoint)
-
- // Act
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- device.dismissChangelogDialogIfShown()
- app.waitForLoginPrompt()
- app.attemptCreateAccount()
+ app.launchAndEnsureOnLoginPage()
- // Assert
- app.ensureAccountCreationFailed()
+ on<LoginPage> {
+ clickCreateAccount()
+ device.findObjectWithTimeout(By.text("Failed to create account"))
+ }
}
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt
index b246bf2062..699b19da32 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt
@@ -5,9 +5,9 @@ import androidx.test.uiautomator.Until
import java.time.ZonedDateTime
import net.mullvad.mullvadvpn.lib.ui.tag.LOGIN_TITLE_TEST_TAG
import net.mullvad.mullvadvpn.test.common.constant.DEFAULT_TIMEOUT
-import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
-import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
-import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
+import net.mullvad.mullvadvpn.test.common.page.ConnectPage
+import net.mullvad.mullvadvpn.test.common.page.OutOfTimePage
+import net.mullvad.mullvadvpn.test.common.page.on
import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2
@@ -23,14 +23,9 @@ class LoginMockApiTest : MockApiTest() {
expectedAccountNumber = null
accountExpiry = ZonedDateTime.now().plusDays(1)
}
- app.launch(endpoint)
- // Act
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptLogin(validAccountNumber)
- app.attemptLogin(validAccountNumber)
+ // Act login with invalid credentials
+ app.launchAndLogIn(validAccountNumber)
// Assert
val result =
@@ -53,15 +48,10 @@ class LoginMockApiTest : MockApiTest() {
}
// Act
- app.launch(endpoint)
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptLogin(validAccountNumber)
- device.dismissChangelogDialogIfShown()
+ app.launchAndLogIn(validAccountNumber)
// Assert
- app.ensureLoggedIn()
+ on<ConnectPage>()
}
@Test
@@ -75,15 +65,9 @@ class LoginMockApiTest : MockApiTest() {
devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2
}
- // Act
- app.launch(endpoint)
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptLogin(validAccountNumber)
- device.dismissChangelogDialogIfShown()
+ app.launchAndLogIn(validAccountNumber)
// Assert
- app.ensureOutOfTime()
+ on<OutOfTimePage>()
}
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt
index da41d41066..08bc8d7862 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt
@@ -1,15 +1,13 @@
package net.mullvad.mullvadvpn.test.mockapi
-import androidx.test.uiautomator.By
import java.time.ZonedDateTime
-import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
-import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
-import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
-import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
+import net.mullvad.mullvadvpn.test.common.page.AccountPage
+import net.mullvad.mullvadvpn.test.common.page.ConnectPage
+import net.mullvad.mullvadvpn.test.common.page.LoginPage
+import net.mullvad.mullvadvpn.test.common.page.on
import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2
-import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Test
class LogoutMockApiTest : MockApiTest() {
@@ -26,17 +24,12 @@ class LogoutMockApiTest : MockApiTest() {
}
// Act
- app.launch(endpoint)
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptLogin(validAccountNumber)
- device.dismissChangelogDialogIfShown()
- app.ensureLoggedIn()
- app.clickAccountCog()
- app.clickActionButtonByText("Log out")
+ app.launchAndLogIn(validAccountNumber)
- // Assert
- assertNotNull(device.findObjectWithTimeout(By.text("Login")))
+ on<ConnectPage> { clickAccount() }
+
+ on<AccountPage> { clickLogOut() }
+
+ on<LoginPage>()
}
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/ManageDevicesMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/ManageDevicesMockApiTest.kt
index 1b087ec0fe..3a729032ab 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/ManageDevicesMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/ManageDevicesMockApiTest.kt
@@ -2,9 +2,6 @@ package net.mullvad.mullvadvpn.test.mockapi
import androidx.test.uiautomator.By
import java.time.ZonedDateTime
-import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
-import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
-import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
import net.mullvad.mullvadvpn.test.common.page.AccountPage
import net.mullvad.mullvadvpn.test.common.page.ConnectPage
@@ -29,13 +26,7 @@ class ManageDevicesMockApiTest : MockApiTest() {
}
// Act - go to devices screen
- app.launch(endpoint)
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptLogin(validAccountNumber)
- device.waitForIdle()
- device.dismissChangelogDialogIfShown()
+ app.launchAndLogIn(validAccountNumber)
on<ConnectPage> { clickAccount() }
@@ -48,8 +39,8 @@ class ManageDevicesMockApiTest : MockApiTest() {
removeDevice("Yellow Hat")
- // Confirm removal of device
- app.clickActionButtonByText("Remove")
+ // Confirm the removal of the device
+ device.findObjectWithTimeout(By.text("Remove")).click()
expectDeviceToBeRemoved("Yellow Hat")
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt
index c7cb8f0377..6327a54757 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt
@@ -12,7 +12,6 @@ import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointOverride
import net.mullvad.mullvadvpn.test.common.interactor.AppInteractor
import net.mullvad.mullvadvpn.test.common.rule.CaptureScreenshotOnFailedTestRule
import net.mullvad.mullvadvpn.test.mockapi.constant.LOG_TAG
-import net.mullvad.mullvadvpn.test.mockapi.constant.PACKAGE_NAME
import okhttp3.mockwebserver.MockWebServer
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
@@ -42,11 +41,12 @@ abstract class MockApiTest {
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
targetContext = InstrumentationRegistry.getInstrumentation().targetContext
- app = AppInteractor(device, targetContext, PACKAGE_NAME)
-
mockWebServer.start()
Logger.d("Mocked web server started using port: ${mockWebServer.port}")
endpoint = createEndpoint(mockWebServer.port)
+
+ Logger.d("targetContext packageName: ${targetContext.packageName}")
+ app = AppInteractor(device, targetContext, endpoint)
}
@AfterEach
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt
index 2a5d91feaa..15638c6add 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt
@@ -1,11 +1,10 @@
package net.mullvad.mullvadvpn.test.mockapi
-import androidx.test.uiautomator.By
import java.time.ZonedDateTime
-import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
-import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
-import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
-import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
+import net.mullvad.mullvadvpn.test.common.page.ConnectPage
+import net.mullvad.mullvadvpn.test.common.page.TooManyDevicesPage
+import net.mullvad.mullvadvpn.test.common.page.on
+import net.mullvad.mullvadvpn.test.common.page.removeDeviceFlow
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_6
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_6
import net.mullvad.mullvadvpn.test.mockapi.constant.FULL_DEVICE_LIST
@@ -24,31 +23,16 @@ class TooManyDevicesMockApiTest : MockApiTest() {
}
// Act
- app.launch(endpoint)
- device.clickAgreeOnPrivacyDisclaimer()
- device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove()
- app.waitForLoginPrompt()
- app.attemptLogin(validAccountNumber)
+ app.launchAndLogIn(validAccountNumber)
// Assert that we have too many devices
- device.findObjectWithTimeout(By.text("Too many devices"))
- // And that the continue with login button is disabled
- device.findObjectWithTimeout(By.text("Continue with login").hasParent(By.enabled((false))))
+ on<TooManyDevicesPage> {
+ removeDeviceFlow(FULL_DEVICE_LIST.values.first())
- // Act
- // Wait until the application is idle to avoid skipping input events that are filtered out
- // depending on lifecycle state (dropUnlessResumed).
- device.waitForIdle()
- app.attemptToRemoveDevice()
-
- // Assert that a device was removed
- device.findObjectWithTimeout(By.text("Super!"))
-
- // Act
- app.clickActionButtonByText("Continue with login")
+ assertReadyToLogin()
+ clickContinueWithLogin()
+ }
- // Assert that we are logged in
- device.dismissChangelogDialogIfShown()
- app.ensureLoggedIn()
+ on<ConnectPage>()
}
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/constant/Constants.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/constant/Constants.kt
index 083fcc1160..4e907e106d 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/constant/Constants.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/constant/Constants.kt
@@ -1,7 +1,5 @@
package net.mullvad.mullvadvpn.test.mockapi.constant
-const val PACKAGE_NAME = "net.mullvad.mullvadvpn"
-
const val LOG_TAG = "mullvad-mockapi"
const val AUTH_TOKEN_URL_PATH = "/auth/v1/token"
@@ -10,17 +8,17 @@ const val ACCOUNT_URL_PATH = "/accounts/v1/accounts/me"
const val CREATE_ACCOUNT_URL_PATH = "/accounts/v1/accounts"
const val DUMMY_ID_1 = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
-const val DUMMY_DEVICE_NAME_1 = "mole mole"
+const val DUMMY_DEVICE_NAME_1 = "Mole Mole"
const val DUMMY_ID_2 = "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
-const val DUMMY_DEVICE_NAME_2 = "elom elom"
+const val DUMMY_DEVICE_NAME_2 = "Elom Elom"
const val DUMMY_ID_3 = "cccccccc-cccc-cccc-cccc-cccccccccccc"
-const val DUMMY_DEVICE_NAME_3 = "mole elom"
+const val DUMMY_DEVICE_NAME_3 = "Mole Elom"
const val DUMMY_ID_4 = "dddddddd-dddd-dddd-dddd-dddddddddddd"
-const val DUMMY_DEVICE_NAME_4 = "yellow hat"
+const val DUMMY_DEVICE_NAME_4 = "Yellow Hat"
const val DUMMY_ID_5 = "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"
-const val DUMMY_DEVICE_NAME_5 = "secure tunnel"
+const val DUMMY_DEVICE_NAME_5 = "Secure Tunnel"
const val DUMMY_ID_6 = "ffffffff-ffff-ffff-ffff-ffffffffffff"
-const val DUMMY_DEVICE_NAME_6 = "red lobster"
+const val DUMMY_DEVICE_NAME_6 = "Red Lobster"
const val DUMMY_ACCESS_TOKEN =
"mva_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"