Skip to content

Commit

Permalink
Merge pull request #1 from wojta/auth-test
Browse files Browse the repository at this point in the history
Aerogear Android SDK Login and logout flow
  • Loading branch information
wojta committed Mar 7, 2018
2 parents a0c37e1 + 76f69a1 commit 276895b
Show file tree
Hide file tree
Showing 17 changed files with 282 additions and 36 deletions.
3 changes: 0 additions & 3 deletions build.gradle
Expand Up @@ -29,9 +29,6 @@ allprojects {
}
}




task clean(type: Delete) {
delete rootProject.buildDir
}
11 changes: 10 additions & 1 deletion sdk-e2e/build.gradle
Expand Up @@ -26,11 +26,18 @@ apply plugin: 'de.fuerstenau.buildconfig'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testCompile "org.jetbrains.kotlin:kotlin-test"
testCompile "cz.sazel:akow-lib:+"
testCompile "cz.sazel:akow-lib:0.0.6"
testCompile "io.appium:java-client:$appium_version"
testCompile "junit:junit:$junit4_version"
}

compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
javaParameters = true // Useful for reflection.
}
}

compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8"
Expand All @@ -46,6 +53,8 @@ buildConfig {
packageName = "org.aerogear.sdk_e2e_tests"
buildConfigField 'String', 'TEST_APK', "${androidExampleApk}"
buildConfigField 'String', 'APPIUM_SERVER_URL', "http://localhost:4723/wd/hub"
buildConfigField 'String', 'ADB_EXECUTABLE', "/usr/bin/adb"
buildConfigField 'String', 'BROWSER_PACKAGE', 'com.android.chrome'
}

sourceCompatibility = "1.8"
Expand Down
32 changes: 32 additions & 0 deletions sdk-e2e/src/test/kotlin/org/aerogear/sdk_e2e_tests/Utils.kt
@@ -0,0 +1,32 @@
package org.aerogear.sdk_e2e_tests

import java.io.BufferedReader

/**
* Created on 1/19/18.
*/

/**
* Kills android process with [packageName] on connected ADB device.
*/
fun killAndroidProcess(packageName: String) {
execWithoutOutput(BuildConfig.ADB_EXECUTABLE, "shell", "am", "force-stop", packageName)
}

/**
* Clears android package data of application with [packageName] on connected ADB device.
*/
fun clearPackage(packageName: String) {
execWithoutOutput(BuildConfig.ADB_EXECUTABLE, "shell", "pm", "clear", packageName)
}

/**
* Executes shell command and ignores output.
* @param cmd shell command
* @param args command arguments
*/
private fun execWithoutOutput(vararg args: String) {
val p = Runtime.getRuntime().exec(args)
val out = p.inputStream.bufferedReader().use(BufferedReader::readText) //there is actually no output expected, so read it all and ignore to prevent hanging
println(out)
}
@@ -1,11 +1,11 @@
package org.aerogear.sdk_e2e_tests.base

import org.aerogear.akow.example.test.appium
import org.aerogear.akow.test.AkowTest
import org.aerogear.sdk_e2e_tests.appium
import org.junit.runners.Parameterized

/**
* Created on 2/26/18.
* Base test for all tests, extend your tests from this.
*/
abstract class BaseTest : AkowTest(appium) {

Expand Down
13 changes: 11 additions & 2 deletions sdk-e2e/src/test/kotlin/org/aerogear/sdk_e2e_tests/init.kt
@@ -1,8 +1,12 @@
package org.aerogear.akow.example.test
package org.aerogear.sdk_e2e_tests

import org.aerogear.akow.dsl.base.appium
import org.aerogear.akow.example.test.pageobjects.android.MainAndroidScreen
import org.aerogear.sdk_e2e_tests.BuildConfig
import org.aerogear.sdk_e2e_tests.pageobjects.android.AuthStartAndroidScreen
import org.aerogear.sdk_e2e_tests.pageobjects.android.AuthenticatedAndroidScreen
import org.aerogear.sdk_e2e_tests.pageobjects.android.KeycloakLoginAndroidScreen
import org.aerogear.sdk_e2e_tests.pageobjects.unimportant.ChromeIntroAndroidScreen
import org.aerogear.sdk_e2e_tests.pageobjects.unimportant.SetPINDialogAndroidScreen

val appium = appium(BuildConfig.APPIUM_SERVER_URL) {
applications {
Expand All @@ -11,6 +15,11 @@ val appium = appium(BuildConfig.APPIUM_SERVER_URL) {
}
screens {
+MainAndroidScreen()
+AuthStartAndroidScreen()
+SetPINDialogAndroidScreen()
+ChromeIntroAndroidScreen()
+KeycloakLoginAndroidScreen()
+AuthenticatedAndroidScreen()
}
}

Expand Down
@@ -0,0 +1,19 @@
package org.aerogear.sdk_e2e_tests.pageobjects

import org.aerogear.akow.pageobject.PageObject
import org.openqa.selenium.WebElement

/**
* Authentication functionality screen
*/
interface AuthStartScreen : PageObject {
val loginButton: WebElement


/**
* Starts login flow.
*/
fun startLogin() {
loginButton.click()
}
}
@@ -0,0 +1,12 @@
package org.aerogear.sdk_e2e_tests.pageobjects

import org.aerogear.akow.pageobject.PageObject
import org.openqa.selenium.WebElement

/**
* Screen representing authenticated user.
*/
interface AuthenticatedScreen : PageObject {
val logoutButton: WebElement
val userNameTextBox:WebElement
}
@@ -0,0 +1,29 @@
package org.aerogear.sdk_e2e_tests.pageobjects

import org.aerogear.akow.pageobject.PageObject
import org.openqa.selenium.WebElement

/**
* Keycloak login screen.
*/
interface KeycloakLoginScreen : PageObject {
val usernameInput: WebElement
val passwordInput: WebElement
val loginButton: WebElement

/**
* Logs in with [username] and [password].
*/
fun login(username: String, password: String) {
usernameInput.apply {
click()
sendKeys(username)
}
passwordInput.apply {
click()
sendKeys(password)
}
loginButton.click()

}
}
Expand Up @@ -4,14 +4,15 @@ import org.aerogear.akow.pageobject.PageObject
import org.openqa.selenium.WebElement

/**
* Created on 2/27/18.
* Main screen.
*/
interface MainScreen : PageObject {

val navDrawer: WebElement
val mnuTextFieldsItem: WebElement
val mnuHome: WebElement
val mnuAuth: WebElement

fun selectInNavDrawer(item: WebElement) {
fun selectNavigationItem(item: WebElement) {
navDrawer.click()
item.click()
}
Expand Down
@@ -0,0 +1,11 @@
package org.aerogear.sdk_e2e_tests.pageobjects.android

import org.aerogear.akow.pageobject.AndroidScreen
import org.aerogear.sdk_e2e_tests.pageobjects.AuthStartScreen

/**
* Authentication start screen for Android
*/
class AuthStartAndroidScreen : AuthStartScreen, AndroidScreen() {
override val loginButton by id("org.aerogear.mobile.example:id/keycloak_login")
}
@@ -0,0 +1,12 @@
package org.aerogear.sdk_e2e_tests.pageobjects.android

import org.aerogear.akow.pageobject.AndroidScreen
import org.aerogear.sdk_e2e_tests.pageobjects.AuthenticatedScreen

/**
* Created on 3/7/18.
*/
class AuthenticatedAndroidScreen : AuthenticatedScreen,AndroidScreen() {
override val logoutButton by id ("org.aerogear.mobile.example:id/keycloak_logout")
override val userNameTextBox by id("org.aerogear.mobile.example:id/user_name")
}
@@ -0,0 +1,13 @@
package org.aerogear.sdk_e2e_tests.pageobjects.android

import org.aerogear.akow.pageobject.AndroidScreen
import org.aerogear.sdk_e2e_tests.pageobjects.KeycloakLoginScreen

/**
* Created on 3/7/18.
*/
class KeycloakLoginAndroidScreen : KeycloakLoginScreen,AndroidScreen() {
override val usernameInput by id("username")
override val passwordInput by id("password")
override val loginButton by id("kc-login")
}
Expand Up @@ -4,9 +4,11 @@ import org.aerogear.akow.example.test.pageobjects.MainScreen
import org.aerogear.akow.pageobject.AndroidScreen

/**
* Created on 2/27/18.
* Main screen with navigation drawer.
*/
class MainAndroidScreen : AndroidScreen(), MainScreen {
override val navDrawer by accessibilityId("Open navigation drawer")
override val mnuTextFieldsItem by id("org.aerogear.akow.example:id/design_menu_item_text")
override val mnuHome by xpath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.support.v4.widget.DrawerLayout/android.widget.FrameLayout/android.support.v7.widget.RecyclerView/android.support.v7.widget.LinearLayoutCompat[1]")
override val mnuAuth by xpath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.support.v4.widget.DrawerLayout/android.widget.FrameLayout/android.support.v7.widget.RecyclerView/android.support.v7.widget.LinearLayoutCompat[3]")

}
@@ -0,0 +1,31 @@
package org.aerogear.sdk_e2e_tests.pageobjects.unimportant

import io.appium.java_client.MobileElement
import io.appium.java_client.android.AndroidDriver
import org.aerogear.akow.pageobject.AndroidScreen
import org.aerogear.akow.pageobject.PageObject
import org.openqa.selenium.WebElement

/**
* Chrome intro screen that pops up on Android.
*/
interface ChromeIntroScreen : PageObject {
val title: WebElement
val acceptButton: WebElement
val noThanksButton: WebElement

fun acceptNoThanks() {
val oldContext=(driver as AndroidDriver<MobileElement>).context
acceptButton.click()
(driver as AndroidDriver<MobileElement>).context(oldContext)
noThanksButton.click()
}

override fun checkScreen() = title.text.isNotEmpty()
}

class ChromeIntroAndroidScreen : ChromeIntroScreen, AndroidScreen() {
override val title by id("com.android.chrome:id/title")
override val acceptButton by id("com.android.chrome:id/terms_accept")
override val noThanksButton by id("com.android.chrome:id/negative_button")
}
@@ -0,0 +1,23 @@
package org.aerogear.sdk_e2e_tests.pageobjects.unimportant

import org.aerogear.akow.pageobject.AndroidScreen
import org.aerogear.akow.pageobject.PageObject
import org.openqa.selenium.WebElement

/**
* Fingerprint dialog shown in Chrome on Android.
*/
interface SetPINDialogScreen : PageObject {
val alertTitle: WebElement
val cancelButton: WebElement

override fun checkScreen() = alertTitle.text.isNotEmpty()

fun cancel() = cancelButton.click()
}

class SetPINDialogAndroidScreen : SetPINDialogScreen, AndroidScreen() {
override val alertTitle by id("android:id/alertTitle")
override val cancelButton by id("android:id/button2")

}
@@ -0,0 +1,69 @@
package org.aerogear.sdk_e2e_tests.tests

import org.aerogear.akow.example.test.pageobjects.MainScreen
import org.aerogear.sdk_e2e_tests.BuildConfig
import org.aerogear.sdk_e2e_tests.base.BaseTest
import org.aerogear.sdk_e2e_tests.clearPackage
import org.aerogear.sdk_e2e_tests.pageobjects.AuthStartScreen
import org.aerogear.sdk_e2e_tests.pageobjects.AuthenticatedScreen
import org.aerogear.sdk_e2e_tests.pageobjects.KeycloakLoginScreen
import org.aerogear.sdk_e2e_tests.pageobjects.unimportant.ChromeIntroScreen
import org.aerogear.sdk_e2e_tests.pageobjects.unimportant.SetPINDialogScreen
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import kotlin.test.assertEquals

/**
* Test functionality of Auth module through Example app.
*/
@RunWith(Parameterized::class)
class AuthTest : BaseTest() {

private val USERNAME = "user1"
private val PASSWORD = "123"

/**
* Required to prevent reauthentication with remembered session.
*/
@Before
fun killBrowserBeforehand() {
clearPackage(BuildConfig.BROWSER_PACKAGE)
}

@Test
fun testLoginAndLogout() {
akow {
on<MainScreen> {
selectNavigationItem(mnuAuth)

on<AuthStartScreen> {
startLogin()
}

androidOnly {
maybeOn<ChromeIntroScreen> { acceptNoThanks() }
maybeOn<SetPINDialogScreen> { cancel() }
}

on<KeycloakLoginScreen> {
login(USERNAME, PASSWORD)
}

on<AuthenticatedScreen> {
assertEquals("User 1", userNameTextBox.text)
}

selectNavigationItem(mnuHome)

selectNavigationItem(mnuAuth)

on<AuthenticatedScreen> {
assertEquals("User 1", userNameTextBox.text)
logoutButton.click()
}
}
}
}
}

0 comments on commit 276895b

Please sign in to comment.