mirror of
https://github.com/hmalik144/Driver.git
synced 2026-03-18 07:26:03 +00:00
- mid commit
This commit is contained in:
@@ -5,7 +5,6 @@ import android.app.Instrumentation
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import android.widget.DatePicker
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.test.espresso.Espresso.onData
|
||||
@@ -19,12 +18,12 @@ import androidx.test.espresso.intent.Intents
|
||||
import androidx.test.espresso.intent.Intents.intending
|
||||
import androidx.test.espresso.intent.matcher.IntentMatchers
|
||||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
|
||||
import androidx.test.espresso.intent.matcher.IntentMatchers.isInternal
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import h_mal.appttude.com.driver.helpers.DataHelper
|
||||
import h_mal.appttude.com.driver.helpers.DataHelper.addFilePaths
|
||||
import org.hamcrest.CoreMatchers.*
|
||||
import h_mal.appttude.com.driver.helpers.EspressoHelper.waitForView
|
||||
import org.hamcrest.CoreMatchers.allOf
|
||||
import org.hamcrest.CoreMatchers.anything
|
||||
import org.hamcrest.Matchers
|
||||
import java.io.File
|
||||
|
||||
@@ -41,6 +40,8 @@ open class BaseTestRobot {
|
||||
|
||||
fun matchView(resId: Int): ViewInteraction = onView(withId(resId))
|
||||
|
||||
fun matchViewWaitFor(resId: Int): ViewInteraction = waitForView(withId(resId))
|
||||
|
||||
fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction
|
||||
.check(matches(ViewMatchers.withText(text)))
|
||||
|
||||
@@ -55,6 +56,9 @@ open class BaseTestRobot {
|
||||
fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction =
|
||||
onView(withId(resId)).check(matches(checkErrorMessage(errorMessage)))
|
||||
|
||||
fun checkImageViewHasImage(resId: Int): ViewInteraction =
|
||||
onView(withId(resId)).check(matches(checkImage()))
|
||||
|
||||
fun swipeDown(resId: Int): ViewInteraction =
|
||||
onView(withId(resId)).perform(swipeDown())
|
||||
|
||||
@@ -71,12 +75,12 @@ open class BaseTestRobot {
|
||||
)
|
||||
}
|
||||
|
||||
fun selectSingleImageFromGallery(filePath: String, openSelector: () -> Unit) {
|
||||
fun selectSingleImageFromGallery(filePath: FormRobot.FilePath, openSelector: () -> Unit) {
|
||||
Intents.init()
|
||||
// Build the result to return when the activity is launched.
|
||||
val resultData = Intent()
|
||||
resultData.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
resultData.data = Uri.fromFile(File(filePath))
|
||||
resultData.data = Uri.fromFile(File(FormRobot.FilePath.getFilePath(filePath)))
|
||||
val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)
|
||||
// Set up result stubbing when an intent sent to image picker is seen.
|
||||
intending(hasAction(Intent.ACTION_GET_CONTENT)).respondWith(result)
|
||||
@@ -87,17 +91,15 @@ open class BaseTestRobot {
|
||||
|
||||
fun selectMultipleImageFromGallery(filePaths: Array<String>, openSelector: () -> Unit) {
|
||||
Intents.init()
|
||||
openSelector()
|
||||
// Build the result to return when the activity is launched.
|
||||
val resultData = Intent()
|
||||
val clipData = DataHelper.createClipData(filePaths[0])
|
||||
val remainingFiles = filePaths.copyOfRange(1, filePaths.size-1)
|
||||
clipData.addFilePaths(remainingFiles)
|
||||
val clipData = DataHelper.createClipData(filePaths)
|
||||
resultData.clipData = clipData
|
||||
val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)
|
||||
|
||||
// Set up result stubbing when an intent sent to "contacts" is seen.
|
||||
Intents.intending(IntentMatchers.toPackage("android.intent.action.PICK")).respondWith(result)
|
||||
intending(IntentMatchers.toPackage("android.intent.action.PICK")).respondWith(result)
|
||||
|
||||
openSelector()
|
||||
Intents.release()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package h_mal.appttude.com.driver
|
||||
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.Matcher
|
||||
@@ -11,7 +13,7 @@ import org.hamcrest.TypeSafeMatcher
|
||||
/**
|
||||
* Matcher for testing error of TextInputLayout
|
||||
*/
|
||||
fun checkErrorMessage(expectedErrorText: String): Matcher<View?>? {
|
||||
fun checkErrorMessage(expectedErrorText: String): Matcher<View?> {
|
||||
return object : TypeSafeMatcher<View?>() {
|
||||
override fun matchesSafely(view: View?): Boolean {
|
||||
if (view is EditText) {
|
||||
@@ -28,3 +30,25 @@ fun checkErrorMessage(expectedErrorText: String): Matcher<View?>? {
|
||||
}
|
||||
}
|
||||
|
||||
fun checkImage(): Matcher<View?> {
|
||||
return object : TypeSafeMatcher<View?>() {
|
||||
override fun matchesSafely(view: View?): Boolean {
|
||||
if (view is ImageView) {
|
||||
return hasImage(view)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun describeTo(d: Description?) {}
|
||||
|
||||
private fun hasImage(view: ImageView): Boolean {
|
||||
val drawable = view.drawable
|
||||
var hasImage = drawable != null
|
||||
if (hasImage && drawable is BitmapDrawable) {
|
||||
hasImage = drawable.bitmap != null
|
||||
}
|
||||
return hasImage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package h_mal.appttude.com.driver
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import h_mal.appttude.com.driver.helpers.getImagePath
|
||||
|
||||
|
||||
open class FormRobot : BaseTestRobot() {
|
||||
@@ -15,7 +15,7 @@ open class FormRobot : BaseTestRobot() {
|
||||
onView(withId(android.R.id.button1)).perform(click())
|
||||
}
|
||||
|
||||
fun selectSingleImage(imagePickerLauncherViewId: Int, filePath: String) {
|
||||
fun selectSingleImage(imagePickerLauncherViewId: Int, filePath: FilePath) {
|
||||
selectSingleImageFromGallery(filePath) {
|
||||
onView(withId(imagePickerLauncherViewId)).perform(click())
|
||||
}
|
||||
@@ -27,4 +27,20 @@ open class FormRobot : BaseTestRobot() {
|
||||
onView(withId(imagePickerLauncherViewId)).perform(click())
|
||||
}
|
||||
}
|
||||
|
||||
enum class FilePath(val path: String) {
|
||||
PROFILE_PIC("driver_profile_pic.jpg"),
|
||||
INSURANCE("driver_insurance.jpg"),
|
||||
PRIVATE_HIRE("driver_license_private_hire.jpg"),
|
||||
PRIVATE_HIRE_CAR("driver_license_private_hire_car.jpg"),
|
||||
LOGBOOK("driver_logbook.jpg"),
|
||||
MOT("driver_mot.jpg"),
|
||||
LICENSE("driver_license_driver.jpg");
|
||||
|
||||
companion object {
|
||||
fun getFilePath(filePath: FilePath): String {
|
||||
return getImagePath(filePath.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,9 @@ import java.io.File
|
||||
/**
|
||||
* File paths for images on device
|
||||
*/
|
||||
private const val BASE = "/Camera/images/"
|
||||
const val PROFILE_PIC = "${BASE}driver_profile_pic.jpg"
|
||||
const val INSURANCE = "${BASE}driver_insurance.jpg"
|
||||
const val PRIVATE_HIRE = "${BASE}driver_license_private_hire.jpg"
|
||||
const val PRIVATE_HIRE_CAR = "${BASE}driver_license_private_hire_car.jpg"
|
||||
const val LOGBOOK = "${BASE}driver_logbook.jpg"
|
||||
const val MOT = "${BASE}driver_mot.jpg"
|
||||
const val LICENSE = "${BASE}driver_license_driver.jpg"
|
||||
|
||||
fun getImagePath(imageConst: String): String {
|
||||
return File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), imageConst).absolutePath
|
||||
return File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
|
||||
"/Camera/images/$imageConst"
|
||||
).absolutePath
|
||||
}
|
||||
@@ -2,20 +2,29 @@ package h_mal.appttude.com.driver.helpers
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipData.Item
|
||||
import android.content.ClipDescription
|
||||
import android.net.Uri
|
||||
import java.io.File
|
||||
|
||||
object DataHelper {
|
||||
|
||||
fun createClipItem(filePath: String) = Item(
|
||||
Uri.fromFile(File(filePath)
|
||||
))
|
||||
Uri.fromFile(
|
||||
File(filePath)
|
||||
)
|
||||
)
|
||||
|
||||
fun createClipData(item: Item, mimeType: String = "text/uri-list") = ClipData(null, arrayOf(mimeType), item)
|
||||
fun createClipData(item: Item, mimeType: String = "text/uri-list") =
|
||||
ClipData(null, arrayOf(mimeType), item)
|
||||
|
||||
fun createClipData(filePath: String) = createClipData(createClipItem(filePath))
|
||||
|
||||
fun createClipData(filePaths: Array<String>): ClipData {
|
||||
val clipData = createClipData(filePaths[0])
|
||||
val remainingFiles = filePaths.copyOfRange(1, filePaths.size - 1)
|
||||
clipData.addFilePaths(remainingFiles)
|
||||
return clipData
|
||||
}
|
||||
|
||||
fun createClipData(uri: Uri) = createClipData(Item(uri))
|
||||
|
||||
fun ClipData.addFilePaths(filePaths: Array<String>) {
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package h_mal.appttude.com.driver.helpers
|
||||
|
||||
import android.os.SystemClock.sleep
|
||||
import android.view.View
|
||||
import android.widget.CheckBox
|
||||
import android.widget.Checkable
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.NoMatchingViewException
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.ViewInteraction
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
||||
import androidx.test.espresso.util.TreeIterables
|
||||
import org.hamcrest.BaseMatcher
|
||||
import org.hamcrest.CoreMatchers.isA
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.Matcher
|
||||
|
||||
|
||||
object EspressoHelper {
|
||||
|
||||
/**
|
||||
* Perform action of waiting for a certain view within a single root view
|
||||
* @param viewMatcher Generic Matcher used to find our view
|
||||
*/
|
||||
fun searchFor(viewMatcher: Matcher<View>): ViewAction {
|
||||
|
||||
return object : ViewAction {
|
||||
|
||||
override fun getConstraints(): Matcher<View> = isRoot()
|
||||
override fun getDescription(): String {
|
||||
return "searching for view $this in the root view"
|
||||
}
|
||||
|
||||
override fun perform(uiController: UiController, view: View) {
|
||||
var tries = 0
|
||||
val childViews: Iterable<View> = TreeIterables.breadthFirstViewTraversal(view)
|
||||
|
||||
// Look for the match in the tree of childviews
|
||||
childViews.forEach {
|
||||
tries++
|
||||
if (viewMatcher.matches(it)) {
|
||||
// found the view
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw NoMatchingViewException.Builder()
|
||||
.withRootView(view)
|
||||
.withViewMatcher(viewMatcher)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an action to check/uncheck a checkbox
|
||||
*
|
||||
*/
|
||||
fun setChecked(checked: Boolean): ViewAction {
|
||||
return object : ViewAction {
|
||||
override fun getConstraints(): BaseMatcher<View> {
|
||||
return object : BaseMatcher<View>() {
|
||||
override fun describeTo(description: Description?) {}
|
||||
|
||||
override fun matches(actual: Any?): Boolean {
|
||||
return isA(CheckBox::class.java).matches(actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDescription(): String {
|
||||
return ""
|
||||
}
|
||||
|
||||
override fun perform(uiController: UiController, view: View) {
|
||||
val checkableView = view as Checkable
|
||||
checkableView.isChecked = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform action of implicitly waiting for a certain view.
|
||||
* This differs from EspressoExtensions.searchFor in that,
|
||||
* upon failure to locate an element, it will fetch a new root view
|
||||
* in which to traverse searching for our @param match
|
||||
*
|
||||
* @param viewMatcher ViewMatcher used to find our view
|
||||
*/
|
||||
fun waitForView(
|
||||
viewMatcher: Matcher<View>,
|
||||
waitMillis: Int = 5000,
|
||||
waitMillisPerTry: Long = 100
|
||||
): ViewInteraction {
|
||||
|
||||
// Derive the max tries
|
||||
val maxTries = waitMillis / waitMillisPerTry.toInt()
|
||||
|
||||
var tries = 0
|
||||
|
||||
for (i in 0..maxTries)
|
||||
try {
|
||||
// Track the amount of times we've tried
|
||||
tries++
|
||||
|
||||
// Search the root for the view
|
||||
onView(isRoot()).perform(searchFor(viewMatcher))
|
||||
|
||||
// If we're here, we found our view. Now return it
|
||||
return onView(viewMatcher)
|
||||
|
||||
} catch (e: Exception) {
|
||||
|
||||
if (tries == maxTries) {
|
||||
throw e
|
||||
}
|
||||
sleep(waitMillisPerTry)
|
||||
}
|
||||
|
||||
throw Exception("Error finding a view matching $viewMatcher")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user