- Robots added for tests

- Tests added
 - view naming refactoring
 - Image selecting stubbing added

Took 3 hours 48 minutes
This commit is contained in:
2023-05-26 13:13:04 +01:00
parent 312d2ac677
commit 00c57726e3
11 changed files with 117 additions and 37 deletions

View File

@@ -131,6 +131,7 @@ class HomeSuperUserFragment : BaseFragment<SuperUserViewModel, FragmentHomeSuper
private fun showChangeNumberDialog(defaultNumber: String, uid: String) { private fun showChangeNumberDialog(defaultNumber: String, uid: String) {
val inputText = EditText(context).apply { val inputText = EditText(context).apply {
setTag(R.string.driver_identifier, "DriverIdentifierInput")
setText(defaultNumber) setText(defaultNumber)
setSelectAllOnFocus(true) setSelectAllOnFocus(true)
doOnTextChanged { _, _, count, _ -> if (count > 6) context.displayToast("Identifier cannot be larger than 6") } doOnTextChanged { _, _, count, _ -> if (count > 6) context.displayToast("Identifier cannot be larger than 6") }

View File

@@ -12,7 +12,7 @@ class DriverProfileFragment :
override fun setupView(binding: FragmentDriverProfileBinding) { override fun setupView(binding: FragmentDriverProfileBinding) {
super.setupView(binding) super.setupView(binding)
viewsToHide(binding.submitDriver, binding.addPhoto) viewsToHide(binding.submit, binding.addPhoto)
} }
override fun setFields(data: DriverProfile) { override fun setFields(data: DriverProfile) {

View File

@@ -5,13 +5,17 @@ import android.app.Instrumentation
import android.content.Intent import android.content.Intent
import android.content.res.Resources import android.content.res.Resources
import android.net.Uri import android.net.Uri
import android.view.View
import android.widget.DatePicker import android.widget.DatePicker
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.recyclerview.widget.RecyclerView.ViewHolder
import androidx.test.espresso.Espresso.onData import androidx.test.espresso.Espresso.onData
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import androidx.test.espresso.ViewInteraction import androidx.test.espresso.ViewInteraction
import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.swipeDown import androidx.test.espresso.action.ViewActions.swipeDown
import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.PickerActions import androidx.test.espresso.contrib.PickerActions
@@ -20,12 +24,12 @@ import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.intending import androidx.test.espresso.intent.Intents.intending
import androidx.test.espresso.intent.matcher.IntentMatchers import androidx.test.espresso.intent.matcher.IntentMatchers
import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import h_mal.appttude.com.driver.helpers.DataHelper import h_mal.appttude.com.driver.helpers.DataHelper
import h_mal.appttude.com.driver.helpers.EspressoHelper.waitForView import h_mal.appttude.com.driver.helpers.EspressoHelper.waitForView
import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.anything import org.hamcrest.CoreMatchers.anything
import org.hamcrest.Matcher
import org.hamcrest.Matchers import org.hamcrest.Matchers
import java.io.File import java.io.File
@@ -38,25 +42,25 @@ open class BaseTestRobot {
) )
fun clickButton(resId: Int): ViewInteraction = fun clickButton(resId: Int): ViewInteraction =
onView((withId(resId))).perform(ViewActions.click()) onView((withId(resId))).perform(click())
fun matchView(resId: Int): ViewInteraction = onView(withId(resId)) fun matchView(resId: Int): ViewInteraction = onView(withId(resId))
fun matchViewWaitFor(resId: Int): ViewInteraction = waitForView(withId(resId)) fun matchViewWaitFor(resId: Int): ViewInteraction = waitForView(withId(resId))
fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction
.check(matches(ViewMatchers.withText(text))) .check(matches(withText(text)))
fun matchText(resId: Int, text: String): ViewInteraction = matchText(matchView(resId), text) fun matchText(resId: Int, text: String): ViewInteraction = matchText(matchView(resId), text)
fun clickListItem(listRes: Int, position: Int) { fun clickListItem(listRes: Int, position: Int) {
onData(anything()) onData(anything())
.inAdapterView(allOf(withId(listRes))) .inAdapterView(allOf(withId(listRes)))
.atPosition(position).perform(ViewActions.click()) .atPosition(position).perform(click())
} }
fun <VH : ViewHolder> clickRecyclerItemWithText(recyclerId: Int, text: String) { fun <VH : ViewHolder> scrollToRecyclerItem(recyclerId: Int, text: String): ViewInteraction? {
onView(withId(recyclerId)) return onView(withId(recyclerId))
.perform( .perform(
// scrollTo will fail the test if no item matches. // scrollTo will fail the test if no item matches.
RecyclerViewActions.scrollTo<VH>( RecyclerViewActions.scrollTo<VH>(
@@ -65,6 +69,26 @@ open class BaseTestRobot {
) )
} }
fun <VH : ViewHolder> clickViewInRecycler(recyclerId: Int, text: String) {
scrollToRecyclerItem<VH>(recyclerId, text)?.perform(click())
}
fun <VH : ViewHolder> clickSubViewInRecycler(recyclerId: Int, text: String, subView: Int) {
scrollToRecyclerItem<VH>(recyclerId, text)
?.perform(
// scrollTo will fail the test if no item matches.
RecyclerViewActions.actionOnItem<VH>(
hasDescendant(withText(text)), object : ViewAction {
override fun getDescription(): String = "Matching recycler descendant"
override fun getConstraints(): Matcher<View>? = isRoot()
override fun perform(uiController: UiController?, view: View?) {
view?.findViewById<View>(subView)?.performClick()
}
}
)
)
}
fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction = fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction =
onView(withId(resId)).check(matches(checkErrorMessage(errorMessage))) onView(withId(resId)).check(matches(checkErrorMessage(errorMessage)))
@@ -78,7 +102,7 @@ open class BaseTestRobot {
Resources.getSystem().getString(resId) Resources.getSystem().getString(resId)
fun selectDateInPicker(year: Int, month: Int, day: Int) { fun selectDateInPicker(year: Int, month: Int, day: Int) {
onView(ViewMatchers.withClassName(Matchers.equalTo(DatePicker::class.java.name))).perform( onView(withClassName(Matchers.equalTo(DatePicker::class.java.name))).perform(
PickerActions.setDate( PickerActions.setDate(
year, year,
month, month,

View File

@@ -13,14 +13,10 @@ import org.junit.BeforeClass
open class FirebaseTest<T : BaseActivity<*, *>>( open class FirebaseTest<T : BaseActivity<*, *>>(
activity: Class<T>, activity: Class<T>,
private val registered: Boolean = false, private val registered: Boolean = false,
private val signedIn: Boolean = false private val signedIn: Boolean = false,
private val signOutAfterTest: Boolean = true
) : BaseUiTest<T>(activity) { ) : BaseUiTest<T>(activity) {
// @get:Rule
// val intentsRule = IntentsRule()
private val firebaseAuthSource by lazy { FirebaseAuthSource() } private val firebaseAuthSource by lazy { FirebaseAuthSource() }
private var email: String? = null private var email: String? = null
companion object { companion object {
@@ -48,9 +44,10 @@ open class FirebaseTest<T : BaseActivity<*, *>>(
} }
@After @After
fun tearDownFirebase() = runBlocking { fun tearDownFirebase() {
removeUser() if (signOutAfterTest) {
firebaseAuthSource.logOut() firebaseAuthSource.logOut()
}
} }
suspend fun setupUser( suspend fun setupUser(
@@ -85,9 +82,6 @@ open class FirebaseTest<T : BaseActivity<*, *>>(
} }
fun getEmail(): String? { fun getEmail(): String? {
firebaseAuthSource.getUser()?.email?.let { return firebaseAuthSource.getUser()?.email ?: email
return it
}
return email
} }
} }

View File

@@ -0,0 +1,26 @@
package h_mal.appttude.com.driver.firebase.api
import h_mal.appttude.com.driver.firebase.model.SignUpRequest
import h_mal.appttude.com.driver.firebase.model.SignUpResponse
import kotlinx.coroutines.runBlocking
class FirebaseApiModule {
private val firebaseApi = FirebaseApi()
fun signUp(email: String, password: String): SignUpResponse? {
return runBlocking {
val req = SignUpRequest(email = email, password = password)
val response = firebaseApi.signUp(req)
response.body()
}
}
fun signIn(email: String, password: String): SignUpResponse? {
return runBlocking {
val req = SignUpRequest(email = email, password = password)
val response = firebaseApi.signInWithPassword(req)
response.body()
}
}
}

View File

@@ -1,6 +1,7 @@
package h_mal.appttude.com.driver.robots package h_mal.appttude.com.driver.robots
import h_mal.appttude.com.driver.BaseTestRobot import h_mal.appttude.com.driver.BaseTestRobot
import h_mal.appttude.com.driver.PASSWORD
import h_mal.appttude.com.driver.R import h_mal.appttude.com.driver.R
@@ -21,4 +22,11 @@ class LoginRobot : BaseTestRobot() {
fun checkPasswordError(err: String) = checkErrorOnTextEntry(R.id.password, err) fun checkPasswordError(err: String) = checkErrorOnTextEntry(R.id.password, err)
fun attemptLogin(emailAddress: String, password: String = PASSWORD) {
matchViewWaitFor(R.id.email)
setEmail(emailAddress)
setPassword(password)
clickLogin()
}
} }

View File

@@ -1,14 +1,16 @@
package h_mal.appttude.com.driver.robots package h_mal.appttude.com.driver.robots
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.contrib.DrawerActions import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withTagKey
import h_mal.appttude.com.driver.BaseTestRobot import h_mal.appttude.com.driver.BaseTestRobot
import h_mal.appttude.com.driver.R import h_mal.appttude.com.driver.R
import h_mal.appttude.com.driver.base.CustomViewHolder import h_mal.appttude.com.driver.base.CustomViewHolder
fun home(func: HomeRobot.() -> Unit) = HomeRobot().apply { func() } fun homeAdmin(func: HomeAdminRobot.() -> Unit) = HomeAdminRobot().apply { func() }
class HomeRobot : BaseTestRobot() { class HomeAdminRobot : BaseTestRobot() {
fun openDrawer() { fun openDrawer() {
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open()) onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
@@ -23,6 +25,18 @@ class HomeRobot : BaseTestRobot() {
clickButton(R.id.nav_user_settings) clickButton(R.id.nav_user_settings)
} }
fun clickOnItem(text: String) = clickRecyclerItemWithText<CustomViewHolder<*>>(R.id.recycler_view, text) fun clickOnItem(anyText: String) =
clickViewInRecycler<CustomViewHolder<*>>(R.id.recycler_view, anyText)
fun clickOnDriverIdentifier(anyText: String) =
clickSubViewInRecycler<CustomViewHolder<*>>(R.id.recycler_view, anyText, R.id.driver_no)
fun submitDialog(text: String) {
onView(withTagKey(R.string.driver_identifier)).perform(
ViewActions.replaceText(text),
ViewActions.closeSoftKeyboard()
)
// Click OK
onView(withId(android.R.id.button1)).perform(ViewActions.click())
}
} }

View File

@@ -0,0 +1,25 @@
package h_mal.appttude.com.driver.tests
import h_mal.appttude.com.driver.ADMIN_EMAIL
import h_mal.appttude.com.driver.FirebaseTest
import h_mal.appttude.com.driver.robots.homeAdmin
import h_mal.appttude.com.driver.robots.login
import h_mal.appttude.com.driver.ui.user.LoginActivity
import org.junit.Test
class UserListTest : FirebaseTest<LoginActivity>(LoginActivity::class.java) {
@Test
fun loginAsAdmin_updateDriverIdentifier_loggedIn() {
login {
waitFor(1100)
attemptLogin(ADMIN_EMAIL)
}
homeAdmin {
clickOnDriverIdentifier("rsaif660@gmail.com")
submitDialog("ID45")
waitFor(5000)
}
}
}

View File

@@ -1,9 +1,6 @@
package h_mal.appttude.com.driver.application package h_mal.appttude.com.driver.application
import android.app.Application import android.app.Application
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.storage.FirebaseStorage
import h_mal.appttude.com.driver.data.FirebaseAuthSource import h_mal.appttude.com.driver.data.FirebaseAuthSource
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
import h_mal.appttude.com.driver.data.FirebaseStorageSource import h_mal.appttude.com.driver.data.FirebaseStorageSource
@@ -18,16 +15,6 @@ import org.kodein.di.generic.singleton
class DriverApplication : Application(), KodeinAware { class DriverApplication : Application(), KodeinAware {
// override fun onCreate() {
// super.onCreate()
//
// val localHost = "10.0.2.2"
//
// FirebaseAuth.getInstance().useEmulator(localHost, 9099)
// FirebaseDatabase.getInstance().useEmulator(localHost, 9000)
// FirebaseStorage.getInstance().useEmulator(localHost, 9199)
// }
// Kodein aware to initialise the classes used for DI // Kodein aware to initialise the classes used for DI
override val kodein = Kodein.lazy { override val kodein = Kodein.lazy {
import(androidXModule(this@DriverApplication)) import(androidXModule(this@DriverApplication))

View File

@@ -58,6 +58,7 @@
<string name="address_of_keeper">Address of Keeper</string> <string name="address_of_keeper">Address of Keeper</string>
<string name="postcode_of_keeper">Postcode of Keeper</string> <string name="postcode_of_keeper">Postcode of Keeper</string>
<string name="car_start_date">Start date</string> <string name="car_start_date">Start date</string>
<string name="driver_identifier">driver identifier</string>
<string name="vehicle_seized">Vehicle Seized</string> <string name="vehicle_seized">Vehicle Seized</string>
<string name="full_name">Full name</string> <string name="full_name">Full name</string>
<string name="address">Address</string> <string name="address">Address</string>