From 44945366dedd5056064ac8378681e879694a29b5 Mon Sep 17 00:00:00 2001 From: Andrei Calin Madescu Date: Mon, 2 Oct 2023 19:55:35 +0300 Subject: [PATCH] PIA-633 - Add Sign In tests, screen objects and helpers --- app/build.gradle | 4 ++ .../java/core/BaseUiAutomatorClass.kt | 32 ++++++++++++++ .../androidTest/java/helpers/ActionHelpers.kt | 18 ++++++++ .../androidTest/java/helpers/LocatorHelper.kt | 15 +++++++ .../screens/objects/MainScreenPageObjects.kt | 9 ++++ .../java/screens/objects/SignInPageObjects.kt | 20 +++++++++ .../java/screens/steps/SignInStepObjects.kt | 35 ++++++++++++++++ app/src/androidTest/java/tests/SignInTests.kt | 42 +++++++++++++++++++ 8 files changed, 175 insertions(+) create mode 100644 app/src/androidTest/java/core/BaseUiAutomatorClass.kt create mode 100644 app/src/androidTest/java/helpers/ActionHelpers.kt create mode 100644 app/src/androidTest/java/helpers/LocatorHelper.kt create mode 100644 app/src/androidTest/java/screens/objects/MainScreenPageObjects.kt create mode 100644 app/src/androidTest/java/screens/objects/SignInPageObjects.kt create mode 100644 app/src/androidTest/java/screens/steps/SignInStepObjects.kt create mode 100644 app/src/androidTest/java/tests/SignInTests.kt diff --git a/app/build.gradle b/app/build.gradle index 1b26905..7748ff6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,6 +24,7 @@ repositories { dependencies { implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' + implementation 'androidx.test.uiautomator:uiautomator:2.2.0' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' @@ -235,6 +236,9 @@ android { } debug { debuggable true + buildConfigField 'String', 'PIA_VALID_USERNAME', "\"" + System.getenv("PIA_VALID_USERNAME") + "\"" + buildConfigField 'String', 'PIA_VALID_PASSWORD', "\"" + System.getenv("PIA_VALID_PASSWORD") + "\"" + buildConfigField 'String', 'PIA_VALID_DIP_TOKEN', "\"" + System.getenv("PIA_VALID_DIP_TOKEN") + "\"" } } ndkVersion '21.1.6352462' diff --git a/app/src/androidTest/java/core/BaseUiAutomatorClass.kt b/app/src/androidTest/java/core/BaseUiAutomatorClass.kt new file mode 100644 index 0000000..c0f5284 --- /dev/null +++ b/app/src/androidTest/java/core/BaseUiAutomatorClass.kt @@ -0,0 +1,32 @@ +package com.privateinternetaccess.android.core + +import android.content.Context +import android.content.Intent +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import org.junit.Before + +open class BaseUiAutomatorClass { + + private lateinit var device: UiDevice + private lateinit var context: Context + + private fun startApp(packageName: String, activityName: String? = null) { + context = InstrumentationRegistry.getInstrumentation().targetContext + val intent = if (activityName == null) { + context.packageManager.getLaunchIntentForPackage(packageName) + } else { + Intent().setClassName(packageName, activityName) + } + intent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) // Clear out any previous instances + context.startActivity(intent) + } + + @Before + fun setUp() { + device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.pressHome() + startApp("com.privateinternetaccess.android") + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/helpers/ActionHelpers.kt b/app/src/androidTest/java/helpers/ActionHelpers.kt new file mode 100644 index 0000000..1507759 --- /dev/null +++ b/app/src/androidTest/java/helpers/ActionHelpers.kt @@ -0,0 +1,18 @@ +package com.privateinternetaccess.android.helpers + +import androidx.test.uiautomator.UiObject + +object ActionHelpers { + + fun clickIfExists(primaryUiObject : UiObject, secondaryUiObj: UiObject? = null) { + if (primaryUiObject.exists()) { + (secondaryUiObj ?: primaryUiObject).click() + } + } + + fun inputTextInField(field: UiObject, data: T? = null) { + field.clearTextField() + field.click() + field.text = data?.toString() ?: "" + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/helpers/LocatorHelper.kt b/app/src/androidTest/java/helpers/LocatorHelper.kt new file mode 100644 index 0000000..d51b7ac --- /dev/null +++ b/app/src/androidTest/java/helpers/LocatorHelper.kt @@ -0,0 +1,15 @@ +package com.privateinternetaccess.android.helpers + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiObject +import androidx.test.uiautomator.UiSelector + +object LocatorHelper { + + private val device: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + + fun findByResourceId(id: String, instance: Int = 0): UiObject { + return device.findObject(UiSelector().resourceId(id).instance(instance)) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/screens/objects/MainScreenPageObjects.kt b/app/src/androidTest/java/screens/objects/MainScreenPageObjects.kt new file mode 100644 index 0000000..510b35c --- /dev/null +++ b/app/src/androidTest/java/screens/objects/MainScreenPageObjects.kt @@ -0,0 +1,9 @@ +package com.privateinternetaccess.android.screens.objects + +import com.privateinternetaccess.android.helpers.LocatorHelper + +class MainScreenPageObjects { + + val connectButton = LocatorHelper.findByResourceId("com.privateinternetaccess.android:id/connection_background") + +} \ No newline at end of file diff --git a/app/src/androidTest/java/screens/objects/SignInPageObjects.kt b/app/src/androidTest/java/screens/objects/SignInPageObjects.kt new file mode 100644 index 0000000..9c62ec2 --- /dev/null +++ b/app/src/androidTest/java/screens/objects/SignInPageObjects.kt @@ -0,0 +1,20 @@ +package com.privateinternetaccess.android.screens.objects + +import com.privateinternetaccess.android.helpers.LocatorHelper + +class SignInPageObjects { + + val notificationPrompt = LocatorHelper.findByResourceId("com.android.permissioncontroller:id/permission_message") + val allowNotifications = LocatorHelper.findByResourceId("com.android.permissioncontroller:id/permission_allow_button") + val denyNotifications = LocatorHelper.findByResourceId("com.android.permissioncontroller:id/permission_deny_button") + val reachLoginScreenButton = LocatorHelper.findByResourceId("com.privateinternetaccess.android:id/login") + val usernameField = LocatorHelper.findByResourceId("com.privateinternetaccess.android:id/piaxEditText") + val passwordField = LocatorHelper.findByResourceId("com.privateinternetaccess.android:id/piaxEditText", instance = 1) + val loginButton = LocatorHelper.findByResourceId("com.privateinternetaccess.android:id/fragment_login_button") + val vpnProfileOkButton = LocatorHelper.findByResourceId("com.privateinternetaccess.android:id/activity_vpn_permissions_button") + val androidOkButton = LocatorHelper.findByResourceId("android:id/button1") + + val loginWithReceipt = LocatorHelper.findByResourceId("com.privateinternetaccess.android:id/fragment_login_receipt") + + val noUsernameOrPasswordError = LocatorHelper.findByResourceId("com.privateinternetaccess.android:id/piaxEditTextError") +} \ No newline at end of file diff --git a/app/src/androidTest/java/screens/steps/SignInStepObjects.kt b/app/src/androidTest/java/screens/steps/SignInStepObjects.kt new file mode 100644 index 0000000..104e4af --- /dev/null +++ b/app/src/androidTest/java/screens/steps/SignInStepObjects.kt @@ -0,0 +1,35 @@ +package com.privateinternetaccess.android.screens.steps + +import com.privateinternetaccess.android.helpers.ActionHelpers.clickIfExists +import com.privateinternetaccess.android.helpers.ActionHelpers.inputTextInField +import com.privateinternetaccess.android.screens.objects.SignInPageObjects + +class SignInStepObjects { + + private val signInPageObjects = SignInPageObjects() + + fun allowNotifications() { + clickIfExists(signInPageObjects.notificationPrompt, signInPageObjects.allowNotifications) + } + + fun reachSignInScreen() { + signInPageObjects.reachLoginScreenButton.clickAndWaitForNewWindow(5000) + } + + fun enterUsername(username : String?) { + inputTextInField(signInPageObjects.usernameField, username) + } + + fun enterPassword(password : String?) { + inputTextInField(signInPageObjects.passwordField, password) + } + + fun clickOnLoginButton() { + signInPageObjects.loginButton.clickAndWaitForNewWindow(5000) + } + + fun allowVpnProfileCreation() { + clickIfExists(signInPageObjects.vpnProfileOkButton) + clickIfExists(signInPageObjects.androidOkButton) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/tests/SignInTests.kt b/app/src/androidTest/java/tests/SignInTests.kt new file mode 100644 index 0000000..2cc4490 --- /dev/null +++ b/app/src/androidTest/java/tests/SignInTests.kt @@ -0,0 +1,42 @@ +package com.privateinternetaccess.android.tests + +import com.privateinternetaccess.android.BuildConfig +import com.privateinternetaccess.android.core.BaseUiAutomatorClass +import com.privateinternetaccess.android.screens.objects.MainScreenPageObjects +import com.privateinternetaccess.android.screens.objects.SignInPageObjects +import com.privateinternetaccess.android.screens.steps.SignInStepObjects +import org.junit.Test + +class SignInTests : BaseUiAutomatorClass() { + + private val stepObjects = SignInStepObjects() + + @Test + fun successfulLoginWithValidCredentials() { + stepObjects.allowNotifications() + stepObjects.reachSignInScreen() + stepObjects.enterUsername(BuildConfig.PIA_VALID_USERNAME) + stepObjects.enterPassword(BuildConfig.PIA_VALID_PASSWORD) + stepObjects.clickOnLoginButton() + stepObjects.allowVpnProfileCreation() + assert(MainScreenPageObjects().connectButton.exists()) + } + + @Test + fun incorrectCredentialsReturnToSplashScreen() { + stepObjects.allowNotifications() + stepObjects.reachSignInScreen() + stepObjects.enterUsername("PLACEHOLDER") + stepObjects.enterPassword("PLACEHOLDER") + stepObjects.clickOnLoginButton() + assert(SignInPageObjects().reachLoginScreenButton.exists()) + } + + @Test + fun errorMessageIfNoCredentialsAreProvided() { + stepObjects.allowNotifications() + stepObjects.reachSignInScreen() + stepObjects.clickOnLoginButton() + assert(SignInPageObjects().noUsernameOrPasswordError.exists()) + } +} \ No newline at end of file