mirror of
https://github.com/hmalik144/Driver.git
synced 2026-03-18 15:36:03 +00:00
- Firebase emulator added
- Update to Espresso tests - Updated gradle dependencies for espresso Took 9 hours 56 minutes
This commit is contained in:
@@ -6,15 +6,15 @@ import androidx.test.espresso.Espresso.onData
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.ViewInteraction
|
||||
import androidx.test.espresso.action.ViewActions
|
||||
import androidx.test.espresso.assertion.ViewAssertions
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import org.hamcrest.CoreMatchers.*
|
||||
import org.hamcrest.CoreMatchers.allOf
|
||||
import org.hamcrest.CoreMatchers.anything
|
||||
|
||||
open class BaseTestRobot {
|
||||
|
||||
fun fillEditText(resId: Int, text: String): ViewInteraction =
|
||||
fun fillEditText(resId: Int, text: String?): ViewInteraction =
|
||||
onView(withId(resId)).perform(ViewActions.replaceText(text), ViewActions.closeSoftKeyboard())
|
||||
|
||||
fun clickButton(resId: Int): ViewInteraction = onView((withId(resId))).perform(ViewActions.click())
|
||||
@@ -22,7 +22,7 @@ open class BaseTestRobot {
|
||||
fun textView(resId: Int): ViewInteraction = onView(withId(resId))
|
||||
|
||||
fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction
|
||||
.check(ViewAssertions.matches(ViewMatchers.withText(text)))
|
||||
.check(matches(ViewMatchers.withText(text)))
|
||||
|
||||
fun matchText(resId: Int, text: String): ViewInteraction = matchText(textView(resId), text)
|
||||
|
||||
|
||||
@@ -1,38 +1,60 @@
|
||||
package h_mal.appttude.com
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.IdlingRegistry
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import h_mal.appttude.com.espresso.IdlingResourceClass
|
||||
import org.junit.AfterClass
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import h_mal.appttude.com.base.BaseActivity
|
||||
import org.hamcrest.Matcher
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
|
||||
abstract class BaseUiTest<T : AppCompatActivity> {
|
||||
|
||||
@Ignore
|
||||
abstract fun getApplicationClass(): Class<T>
|
||||
open class BaseUiTest<T : BaseActivity<*>>(
|
||||
private val activity: Class<T>
|
||||
) {
|
||||
|
||||
@get:Rule
|
||||
var mActivityTestRule = ActivityTestRule(getApplicationClass())
|
||||
private lateinit var mActivityScenarioRule: ActivityScenario<T>
|
||||
private var mIdlingResource: IdlingResource? = null
|
||||
|
||||
companion object {
|
||||
@BeforeClass
|
||||
@JvmStatic
|
||||
fun setUp() {
|
||||
IdlingRegistry.getInstance().register(IdlingResourceClass.countingIdlingResource)
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@JvmStatic
|
||||
fun tearDown() {
|
||||
IdlingRegistry.getInstance().unregister(IdlingResourceClass.countingIdlingResource)
|
||||
@Before
|
||||
fun setup() {
|
||||
beforeLaunch()
|
||||
mActivityScenarioRule = ActivityScenario.launch(activity)
|
||||
mActivityScenarioRule.onActivity {
|
||||
mIdlingResource = it.getIdlingResource()!!
|
||||
IdlingRegistry.getInstance().register(mIdlingResource)
|
||||
}
|
||||
}
|
||||
|
||||
fun getResourceString(@StringRes stringRes: Int): String {
|
||||
return mActivityTestRule.activity.getString(stringRes)
|
||||
@After
|
||||
fun tearDown() {
|
||||
mIdlingResource?.let {
|
||||
IdlingRegistry.getInstance().unregister(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun getResourceString(@StringRes stringRes: Int): String {
|
||||
return InstrumentationRegistry.getInstrumentation().targetContext.resources.getString(
|
||||
stringRes
|
||||
)
|
||||
}
|
||||
|
||||
fun waitFor(delay: Long) {
|
||||
onView(isRoot()).perform(object : ViewAction {
|
||||
override fun getConstraints(): Matcher<View> = isRoot()
|
||||
override fun getDescription(): String = "wait for $delay milliseconds"
|
||||
override fun perform(uiController: UiController, v: View?) {
|
||||
uiController.loopMainThreadForAtLeast(delay)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
open fun beforeLaunch() {}
|
||||
}
|
||||
9
app/src/androidTest/java/h_mal/appttude/com/Constants.kt
Normal file
9
app/src/androidTest/java/h_mal/appttude/com/Constants.kt
Normal file
@@ -0,0 +1,9 @@
|
||||
package h_mal.appttude.com
|
||||
|
||||
|
||||
private const val apiKey = "test_key"
|
||||
const val signUpFirebase = "http://identitytoolkit.googleapis.com/v1/accounts:signUp?key=$apiKey"
|
||||
const val deleteAccountFirebase = "http://10.0.2.2:9099/identitytoolkit.googleapis.com/v1/accounts:delete?key=$apiKey"
|
||||
|
||||
|
||||
const val USER_PASSWORD = "LetMeIn123!"
|
||||
78
app/src/androidTest/java/h_mal/appttude/com/FirebaseTest.kt
Normal file
78
app/src/androidTest/java/h_mal/appttude/com/FirebaseTest.kt
Normal file
@@ -0,0 +1,78 @@
|
||||
package h_mal.appttude.com
|
||||
|
||||
import com.google.firebase.auth.FirebaseAuth
|
||||
import com.google.firebase.database.FirebaseDatabase
|
||||
import com.google.firebase.storage.FirebaseStorage
|
||||
import h_mal.appttude.com.base.BaseActivity
|
||||
import h_mal.appttude.com.data.FirebaseAuthSource
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import org.junit.After
|
||||
import org.junit.BeforeClass
|
||||
|
||||
open class FirebaseTest<T : BaseActivity<*>>(
|
||||
activity: Class<T>,
|
||||
private val registered: Boolean = false,
|
||||
private val signedIn: Boolean = false
|
||||
) : BaseUiTest<T>(activity) {
|
||||
|
||||
private val firebaseAuthSource by lazy { FirebaseAuthSource() }
|
||||
|
||||
private var email: String? = null
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Setup firebase emulators before all tests
|
||||
*/
|
||||
@JvmStatic
|
||||
@BeforeClass
|
||||
fun setupFirebase() {
|
||||
FirebaseAuth.getInstance().useEmulator("10.0.2.2", 9099)
|
||||
FirebaseDatabase.getInstance().useEmulator("10.0.2.2", 9000)
|
||||
FirebaseStorage.getInstance().useEmulator("10.0.2.2", 9199)
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeLaunch() {
|
||||
if (registered) {
|
||||
runBlocking {
|
||||
setupUser()
|
||||
}
|
||||
if (!signedIn) firebaseAuthSource.logOut()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDownFirebase() = runBlocking {
|
||||
removeUser()
|
||||
firebaseAuthSource.logOut()
|
||||
}
|
||||
|
||||
suspend fun setupUser(
|
||||
signInEmail: String = generateEmailAddress(),
|
||||
password: String = USER_PASSWORD
|
||||
) {
|
||||
email = signInEmail
|
||||
firebaseAuthSource.registerUser(signInEmail, password).await().user
|
||||
}
|
||||
|
||||
// remove the user we created for testing
|
||||
suspend fun removeUser() {
|
||||
getEmail()?.let {
|
||||
firebaseAuthSource.reauthenticate(it, USER_PASSWORD).await()
|
||||
firebaseAuthSource.deleteProfile().await()
|
||||
}
|
||||
}
|
||||
|
||||
fun generateEmailAddress(): String {
|
||||
val suffix = (1000..50000).random()
|
||||
return "test-${suffix}@test-account.com"
|
||||
}
|
||||
|
||||
fun getEmail(): String? {
|
||||
firebaseAuthSource.getUser()?.email?.let {
|
||||
return it
|
||||
}
|
||||
return email
|
||||
}
|
||||
}
|
||||
62
app/src/androidTest/java/h_mal/appttude/com/WebUtils.kt
Normal file
62
app/src/androidTest/java/h_mal/appttude/com/WebUtils.kt
Normal file
@@ -0,0 +1,62 @@
|
||||
package h_mal.appttude.com
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import okhttp3.*
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.IOException
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
class WebUtils {
|
||||
private val okHttpClient by lazy { OkHttpClient() }
|
||||
|
||||
suspend fun <T : Any> post(url: String, body: String): T? {
|
||||
val requestBody = body.toRequestBody()
|
||||
val request = Request.Builder()
|
||||
.post(requestBody)
|
||||
.url(url)
|
||||
.build()
|
||||
|
||||
return okHttpClient.newCall(request).await()
|
||||
}
|
||||
|
||||
suspend fun get(url: String): String? {
|
||||
val request: Request = Request.Builder()
|
||||
.url(url)
|
||||
.build()
|
||||
return okHttpClient.newCall(request).await()
|
||||
}
|
||||
|
||||
private suspend fun <T> Call.await(): T? {
|
||||
val objectMapper = Gson()
|
||||
val typeToken: TypeToken<T> = object : TypeToken<T>() {}
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
enqueue(object : Callback {
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
continuation.resume(
|
||||
objectMapper.fromJson(
|
||||
response.body?.string(),
|
||||
typeToken.type
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
// Don't bother with resuming the continuation if it is already cancelled.
|
||||
if (continuation.isCancelled) return
|
||||
continuation.resumeWithException(e)
|
||||
}
|
||||
})
|
||||
|
||||
continuation.invokeOnCancellation {
|
||||
try {
|
||||
cancel()
|
||||
} catch (ex: Throwable) {
|
||||
//Ignore cancel exception
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package h_mal.appttude.com.firebase
|
||||
|
||||
data class SignUpResponse(
|
||||
val expiresIn: String? = null,
|
||||
val kind: String? = null,
|
||||
val idToken: String? = null,
|
||||
val localId: String? = null,
|
||||
val email: String? = null,
|
||||
val refreshToken: String? = null
|
||||
)
|
||||
@@ -1,17 +0,0 @@
|
||||
package h_mal.appttude.com.robots
|
||||
|
||||
import h_mal.appttude.com.BaseTestRobot
|
||||
import h_mal.appttude.com.R
|
||||
|
||||
fun home(func: HomeRobot.() -> Unit) = HomeRobot().apply { func() }
|
||||
class HomeRobot: BaseTestRobot() {
|
||||
|
||||
fun checkTitleExists(title: String) = matchText(R.id.prova_title_tv, title)
|
||||
|
||||
fun clickLogin() = clickButton(R.id.email_sign_in_button)
|
||||
|
||||
fun clickRegister() = clickButton(R.id.register_button)
|
||||
|
||||
fun clickForgotPassword() = clickButton(R.id.forgot)
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package h_mal.appttude.com.robots
|
||||
|
||||
import h_mal.appttude.com.BaseTestRobot
|
||||
import h_mal.appttude.com.R
|
||||
|
||||
|
||||
fun login(func: LoginRobot.() -> Unit) = LoginRobot().apply { func() }
|
||||
class LoginRobot: BaseTestRobot() {
|
||||
|
||||
fun setEmail(email: String) = fillEditText(R.id.email, email);
|
||||
|
||||
fun setPassword(pass: String) = fillEditText(R.id.password, pass)
|
||||
|
||||
fun clickLogin() = clickButton(R.id.email_sign_in_button)
|
||||
|
||||
fun clickRegister() = clickButton(R.id.register_button)
|
||||
|
||||
fun clickForgotPassword() = clickButton(R.id.forgot)
|
||||
|
||||
fun checkEmailError(err: String) = checkErrorOnTextEntry(R.id.email, err)
|
||||
|
||||
fun checkPasswordError(err: String) = checkErrorOnTextEntry(R.id.password, err)
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package h_mal.appttude.com.robots
|
||||
|
||||
import h_mal.appttude.com.BaseTestRobot
|
||||
import h_mal.appttude.com.R
|
||||
|
||||
fun register(func: RegisterRobot.() -> Unit) = RegisterRobot().apply { func() }
|
||||
class RegisterRobot: BaseTestRobot() {
|
||||
|
||||
fun setName(name: String) = fillEditText(R.id.name_register, name)
|
||||
|
||||
fun setEmail(email: String) = fillEditText(R.id.email_register, email)
|
||||
|
||||
fun setPassword(pass: String) = fillEditText(R.id.password_top, pass)
|
||||
|
||||
fun setPasswordConfirm(pass: String) = fillEditText(R.id.password_bottom, pass)
|
||||
|
||||
fun clickLogin() = clickButton(R.id.email_sign_up)
|
||||
|
||||
fun checkNameError(err: String) = checkErrorOnTextEntry(R.id.name_register, err)
|
||||
|
||||
fun checkEmailError(err: String) = checkErrorOnTextEntry(R.id.email_register, err)
|
||||
|
||||
fun checkPasswordError(err: String) = checkErrorOnTextEntry(R.id.password_top, err)
|
||||
|
||||
fun checkPasswordConfirmError(err: String) = checkErrorOnTextEntry(R.id.password_bottom, err)
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package h_mal.appttude.com.tests
|
||||
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import com.google.firebase.auth.FirebaseAuth
|
||||
import h_mal.appttude.com.BaseUiTest
|
||||
import h_mal.appttude.com.R
|
||||
import h_mal.appttude.com.robots.home
|
||||
import h_mal.appttude.com.ui.user.LoginActivity
|
||||
import h_mal.appttude.com.robots.login
|
||||
import h_mal.appttude.com.robots.register
|
||||
import org.junit.*
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class LoginActivityTest: BaseUiTest<LoginActivity>() {
|
||||
|
||||
@Ignore
|
||||
override fun getApplicationClass() = LoginActivity::class.java
|
||||
|
||||
@After
|
||||
fun afterTest(){
|
||||
FirebaseAuth.getInstance().signOut()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyUserLogin_validUsernameAndPassword_loggedIn() {
|
||||
login {
|
||||
setEmail("test-user@testuserdriver.com")
|
||||
setPassword("Password1234")
|
||||
clickLogin()
|
||||
}
|
||||
home {
|
||||
checkTitleExists(getResourceString(R.string.welcome_title))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user