mirror of
https://github.com/hmalik144/Driver.git
synced 2025-12-10 02:45:20 +00:00
- storage permissions request updated
- test suite expanded
This commit is contained in:
@@ -20,16 +20,10 @@ commands:
|
||||
command: |
|
||||
echo "$GOOGLE_SERVICES_KEY" > "app/google-services.json"
|
||||
- android/restore-gradle-cache
|
||||
build_gradle:
|
||||
description: Build the gradle
|
||||
steps:
|
||||
- android/restore-gradle-cache
|
||||
- run:
|
||||
name: Download Dependencies
|
||||
name: allow gradle
|
||||
command: |
|
||||
sudo chmod +x ./gradlew
|
||||
./gradlew androidDependencies
|
||||
- android/save-gradle-cache
|
||||
run_tests:
|
||||
description: run non-instrumentation tests for flavour specified
|
||||
parameters:
|
||||
@@ -38,11 +32,11 @@ commands:
|
||||
default: "Driver"
|
||||
steps:
|
||||
# The next step will run the unit tests
|
||||
- build_gradle
|
||||
- run:
|
||||
name: Run non-instrumentation unit tests
|
||||
command: |
|
||||
./gradlew test<< parameters.flavour >>DebugUnitTest --continue
|
||||
./gradlew test<< parameters.flavour >>DebugUnitTest
|
||||
- android/save-gradle-cache
|
||||
- store_artifacts:
|
||||
path: app/build/reports
|
||||
destination: reports
|
||||
@@ -53,10 +47,9 @@ commands:
|
||||
parameters:
|
||||
flavour:
|
||||
type: string
|
||||
default: "AtlasWeather"
|
||||
default: "Driver"
|
||||
steps:
|
||||
# Download and cache dependencies
|
||||
- build_gradle
|
||||
- run:
|
||||
name: Setup subtree for test data
|
||||
command: |
|
||||
@@ -78,9 +71,7 @@ commands:
|
||||
post-emulator-launch-assemble-command: ./gradlew assemble<< parameters.flavour >>DebugAndroidTest
|
||||
test-command: ./gradlew connected<< parameters.flavour >>DebugAndroidTest
|
||||
system-image: system-images;android-25;google_apis;x86
|
||||
pull-data: true
|
||||
pull-data-path: /storage/emulated/0/Android/data/
|
||||
pull-data-target: ~/app-data
|
||||
pre-test-command: adb push driver_app_data/images /sdcard/Camera
|
||||
pre-emulator-wait-steps:
|
||||
# Start firebase emulator in the background while waiting to start testing
|
||||
- run:
|
||||
@@ -94,6 +85,13 @@ commands:
|
||||
paths:
|
||||
- ~/.cache/firebase/emulators/
|
||||
key: emulator-cache-v1-{{ epoch }}
|
||||
# store screenshots for failed ui tests
|
||||
- when:
|
||||
condition: on_fail
|
||||
steps:
|
||||
- store_artifacts:
|
||||
path: app/build/outputs/connected_android_test_additional_output/
|
||||
destination: connected_android_test
|
||||
# store test reports
|
||||
- store_artifacts:
|
||||
path: app/build/reports/androidTests/connected
|
||||
@@ -128,7 +126,6 @@ commands:
|
||||
name: Setup playstore key
|
||||
command: |
|
||||
echo "$GOOGLE_PLAY_KEY" > "google-play-key.json"
|
||||
- build_gradle
|
||||
- run:
|
||||
name: Run fastlane command to deploy to playstore
|
||||
command: |
|
||||
@@ -156,8 +153,23 @@ jobs:
|
||||
steps:
|
||||
# Checkout the code and its submodule as the first step.
|
||||
- setup_repo
|
||||
# - run_tests:
|
||||
# flavour: << parameters.flavour >>
|
||||
- run_tests:
|
||||
flavour: << parameters.flavour >>
|
||||
run_instrumentation_test:
|
||||
# Parameters used for determining
|
||||
parameters:
|
||||
flavour:
|
||||
type: string
|
||||
default: "Driver"
|
||||
# These next lines define the Android machine image executor.
|
||||
# See: https://circleci.com/docs/2.0/executor-types/
|
||||
executor:
|
||||
name: android/android-machine
|
||||
tag: 2023.05.1
|
||||
# Add steps to the job
|
||||
# See: https://circleci.com/docs/2.0/configuration-reference/#steps
|
||||
steps:
|
||||
- setup_repo
|
||||
- run_ui_tests:
|
||||
flavour: << parameters.flavour >>
|
||||
deploy-to-playstore:
|
||||
@@ -187,6 +199,14 @@ workflows:
|
||||
branches:
|
||||
ignore:
|
||||
- main_admin
|
||||
- run_instrumentation_test:
|
||||
context: appttude
|
||||
flavour: "Driver"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- main_driver
|
||||
- deploy-to-playstore:
|
||||
context: appttude
|
||||
flavour: "Driver"
|
||||
@@ -195,7 +215,7 @@ workflows:
|
||||
only:
|
||||
- main_driver
|
||||
requires:
|
||||
- build-and-test
|
||||
- run_instrumentation_test
|
||||
build-release-admin:
|
||||
jobs:
|
||||
- build-and-test:
|
||||
@@ -205,12 +225,20 @@ workflows:
|
||||
branches:
|
||||
ignore:
|
||||
- main_driver
|
||||
- deploy-to-playstore:
|
||||
- run_instrumentation_test:
|
||||
context: appttude
|
||||
flavour: "Admin"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- main_admin
|
||||
- deploy-to-playstore:
|
||||
context: appttude
|
||||
flavour: "Driver"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- main_admin
|
||||
requires:
|
||||
- build-and-test
|
||||
- run_instrumentation_test
|
||||
@@ -170,4 +170,6 @@ dependencies {
|
||||
def dispatcher_ver = "4.9.2"
|
||||
implementation "com.github.permissions-dispatcher:permissionsdispatcher:${dispatcher_ver}"
|
||||
kapt "com.github.permissions-dispatcher:permissionsdispatcher-processor:${dispatcher_ver}"
|
||||
/ * Date utils * /
|
||||
implementation 'net.danlew:android.joda:2.12.5'
|
||||
}
|
||||
|
||||
9
app/src/androidTest/assets/driver_details.json
Normal file
9
app/src/androidTest/assets/driver_details.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"address": "123 test street update",
|
||||
"dateFirst": "26/01/2019",
|
||||
"dob": "26/01/1979",
|
||||
"forenames": "Alex Smith",
|
||||
"driverPic": "driver_profile_pic.jpg",
|
||||
"ni": "NI 12 34 56 A",
|
||||
"postcode": "EC1V 2AL"
|
||||
}
|
||||
5
app/src/androidTest/assets/drivers_license.json
Normal file
5
app/src/androidTest/assets/drivers_license.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"licenseExpiry": "27/04/2019",
|
||||
"licenseImageString": "driver_license_driver.jpg",
|
||||
"licenseNumber": "FARME100165AB5EW"
|
||||
}
|
||||
7
app/src/androidTest/assets/insurance_details.json
Normal file
7
app/src/androidTest/assets/insurance_details.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"expiryDate": "03/02/2019",
|
||||
"insurerName": "Insurer",
|
||||
"photoStrings": [
|
||||
"driver_insurance.jpg"
|
||||
]
|
||||
}
|
||||
4
app/src/androidTest/assets/log_book.json
Normal file
4
app/src/androidTest/assets/log_book.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"photoString": "driver_logbook.jpg",
|
||||
"v5cnumber": "NJ59NTV"
|
||||
}
|
||||
4
app/src/androidTest/assets/mot_details.json
Normal file
4
app/src/androidTest/assets/mot_details.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"motExpiry": "11/06/2019",
|
||||
"motImageString": "driver_mot.jpg"
|
||||
}
|
||||
5
app/src/androidTest/assets/private_hire_license.json
Normal file
5
app/src/androidTest/assets/private_hire_license.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"phExpiry": "27/04/2019",
|
||||
"phImageString": "driver_license_private_hire.jpg",
|
||||
"phNumber": "987651"
|
||||
}
|
||||
5
app/src/androidTest/assets/private_hire_vehicle.json
Normal file
5
app/src/androidTest/assets/private_hire_vehicle.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"phCarExpiry": "28/01/2019",
|
||||
"phCarImageString": "driver_license_private_hire_car.jpg",
|
||||
"phCarNumber": "4602060501"
|
||||
}
|
||||
11
app/src/androidTest/assets/vehicle_details.json
Normal file
11
app/src/androidTest/assets/vehicle_details.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"colour": "Black",
|
||||
"keeperAddress": "483 Green lanes London",
|
||||
"keeperName": "Adam Cars Ltd",
|
||||
"keeperPostCode": "N13 4BS",
|
||||
"make": "Toyota",
|
||||
"model": "Prius",
|
||||
"reg": "NG59ERY",
|
||||
"seized": false,
|
||||
"startDate": "04/02/2019"
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import android.content.res.Resources
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.widget.DatePicker
|
||||
import android.widget.ListView
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import androidx.test.espresso.Espresso.onData
|
||||
@@ -17,13 +17,13 @@ import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.ViewInteraction
|
||||
import androidx.test.espresso.action.ViewActions
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.action.ViewActions.scrollTo
|
||||
import androidx.test.espresso.action.ViewActions.swipeDown
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.contrib.PickerActions
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||
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.matcher.ViewMatchers.hasDescendant
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
||||
@@ -41,34 +41,40 @@ import java.io.File
|
||||
@SuppressWarnings("unused")
|
||||
open class BaseTestRobot {
|
||||
|
||||
fun fillEditText(resId: Int, text: String?): ViewInteraction =
|
||||
fun fillEditText(@IdRes resId: Int, text: String?): ViewInteraction =
|
||||
onView(withId(resId)).perform(
|
||||
ViewActions.replaceText(text),
|
||||
ViewActions.closeSoftKeyboard()
|
||||
)
|
||||
|
||||
fun clickButton(resId: Int): ViewInteraction =
|
||||
fun scrollAndFillEditText(@IdRes resId: Int, text: String?): ViewInteraction =
|
||||
onView(withId(resId)).perform(
|
||||
scrollTo(),
|
||||
ViewActions.replaceText(text),
|
||||
ViewActions.closeSoftKeyboard()
|
||||
)
|
||||
|
||||
fun clickButton(@IdRes resId: Int): ViewInteraction =
|
||||
onView((withId(resId))).perform(click())
|
||||
|
||||
fun matchView(resId: Int): ViewInteraction = onView(withId(resId))
|
||||
fun matchView(@IdRes resId: Int): ViewInteraction = onView(withId(resId))
|
||||
|
||||
fun matchViewWaitFor(resId: Int): ViewInteraction = waitForView(withId(resId))
|
||||
fun matchViewWaitFor(@IdRes resId: Int): ViewInteraction = waitForView(withId(resId))
|
||||
|
||||
fun matchText(viewInteraction: ViewInteraction, text: String): ViewInteraction = viewInteraction
|
||||
.check(matches(withText(text)))
|
||||
|
||||
fun matchText(viewId: Int, textId: Int): ViewInteraction = onView(withId(viewId))
|
||||
.check(matches(withText(textId)))
|
||||
fun matchText(@StringRes stringId:Int): ViewInteraction = onView(withText(stringId))
|
||||
|
||||
fun matchText(resId: Int, text: String): ViewInteraction = matchText(matchView(resId), text)
|
||||
fun matchText(@IdRes resId: Int, text: String): ViewInteraction = matchText(matchView(resId), text)
|
||||
|
||||
fun clickListItem(listRes: Int, position: Int) {
|
||||
fun clickListItem(@IdRes listRes: Int, position: Int) {
|
||||
onData(anything())
|
||||
.inAdapterView(allOf(withId(listRes)))
|
||||
.atPosition(position).perform(click())
|
||||
}
|
||||
|
||||
fun <VH : ViewHolder> scrollToRecyclerItem(recyclerId: Int, text: String): ViewInteraction? {
|
||||
fun <VH : ViewHolder> scrollToRecyclerItem(@IdRes recyclerId: Int, text: String): ViewInteraction? {
|
||||
return matchView(recyclerId)
|
||||
.perform(
|
||||
// scrollTo will fail the test if no item matches.
|
||||
@@ -78,7 +84,7 @@ open class BaseTestRobot {
|
||||
)
|
||||
}
|
||||
|
||||
fun <VH : ViewHolder> scrollToRecyclerItem(recyclerId: Int, resIdForString: Int): ViewInteraction? {
|
||||
fun <VH : ViewHolder> scrollToRecyclerItem(@IdRes recyclerId: Int, resIdForString: Int): ViewInteraction? {
|
||||
return matchView(recyclerId)
|
||||
.perform(
|
||||
// scrollTo will fail the test if no item matches.
|
||||
@@ -88,7 +94,7 @@ open class BaseTestRobot {
|
||||
)
|
||||
}
|
||||
|
||||
fun <VH : ViewHolder> scrollToRecyclerItemByPosition(recyclerId: Int, position: Int): ViewInteraction? {
|
||||
fun <VH : ViewHolder> scrollToRecyclerItemByPosition(@IdRes recyclerId: Int, position: Int): ViewInteraction? {
|
||||
return matchView(recyclerId)
|
||||
.perform(
|
||||
// scrollTo will fail the test if no item matches.
|
||||
@@ -96,7 +102,7 @@ open class BaseTestRobot {
|
||||
)
|
||||
}
|
||||
|
||||
fun <VH : ViewHolder> clickViewInRecycler(recyclerId: Int, text: String) {
|
||||
fun <VH : ViewHolder> clickViewInRecycler(@IdRes recyclerId: Int, text: String) {
|
||||
matchView(recyclerId)
|
||||
.perform(
|
||||
// scrollTo will fail the test if no item matches.
|
||||
@@ -104,7 +110,7 @@ open class BaseTestRobot {
|
||||
)
|
||||
}
|
||||
|
||||
fun <VH : ViewHolder> clickViewInRecycler(recyclerId: Int, resIdForString: Int) {
|
||||
fun <VH : ViewHolder> clickViewInRecycler(@IdRes recyclerId: Int, resIdForString: Int) {
|
||||
matchView(recyclerId)
|
||||
.perform(
|
||||
// scrollTo will fail the test if no item matches.
|
||||
@@ -112,7 +118,7 @@ open class BaseTestRobot {
|
||||
)
|
||||
}
|
||||
|
||||
fun <VH : ViewHolder> clickSubViewInRecycler(recyclerId: Int, text: String, subView: Int) {
|
||||
fun <VH : ViewHolder> clickSubViewInRecycler(@IdRes recyclerId: Int, text: String, subView: Int) {
|
||||
scrollToRecyclerItem<VH>(recyclerId, text)
|
||||
?.perform(
|
||||
// scrollTo will fail the test if no item matches.
|
||||
@@ -128,13 +134,13 @@ open class BaseTestRobot {
|
||||
)
|
||||
}
|
||||
|
||||
fun checkErrorOnTextEntry(resId: Int, errorMessage: String): ViewInteraction =
|
||||
fun checkErrorOnTextEntry(@IdRes resId: Int, errorMessage: String): ViewInteraction =
|
||||
onView(withId(resId)).check(matches(checkErrorMessage(errorMessage)))
|
||||
|
||||
fun checkImageViewHasImage(resId: Int): ViewInteraction =
|
||||
fun checkImageViewDoesNotHaveDefaultImage(@IdRes resId: Int): ViewInteraction =
|
||||
onView(withId(resId)).check(matches(checkImage()))
|
||||
|
||||
fun swipeDown(resId: Int): ViewInteraction =
|
||||
fun swipeDown(@IdRes resId: Int): ViewInteraction =
|
||||
onView(withId(resId)).perform(swipeDown())
|
||||
|
||||
fun getStringFromResource(@StringRes resId: Int): String =
|
||||
@@ -150,12 +156,12 @@ open class BaseTestRobot {
|
||||
)
|
||||
}
|
||||
|
||||
fun selectSingleImageFromGallery(filePath: FormRobot.FilePath, openSelector: () -> Unit) {
|
||||
fun selectSingleImageFromGallery(filePath: String, 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(FormRobot.FilePath.getFilePath(filePath)))
|
||||
resultData.data = Uri.fromFile(File("/sdcard/Camera/", 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)
|
||||
@@ -164,7 +170,7 @@ open class BaseTestRobot {
|
||||
Intents.release()
|
||||
}
|
||||
|
||||
fun selectMultipleImageFromGallery(filePaths: Array<String>, openSelector: () -> Unit) {
|
||||
fun selectMultipleImageFromGallery(filePaths: List<String>, openSelector: () -> Unit) {
|
||||
Intents.init()
|
||||
// Build the result to return when the activity is launched.
|
||||
val resultData = Intent()
|
||||
@@ -172,7 +178,7 @@ open class BaseTestRobot {
|
||||
resultData.clipData = clipData
|
||||
val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)
|
||||
// Set up result stubbing when an intent sent to "contacts" is seen.
|
||||
intending(IntentMatchers.toPackage("android.intent.action.PICK")).respondWith(result)
|
||||
intending(hasAction(Intent.ACTION_GET_CONTENT)).respondWith(result)
|
||||
|
||||
openSelector()
|
||||
Intents.release()
|
||||
|
||||
@@ -3,25 +3,27 @@ package h_mal.appttude.com.driver
|
||||
import android.Manifest
|
||||
import android.R
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.espresso.*
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.IdlingRegistry
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
||||
import androidx.test.rule.GrantPermissionRule
|
||||
import com.google.gson.Gson
|
||||
import h_mal.appttude.com.driver.base.BaseActivity
|
||||
import h_mal.appttude.com.driver.helpers.BaseViewAction
|
||||
import h_mal.appttude.com.driver.helpers.SnapshotRule
|
||||
import org.hamcrest.CoreMatchers
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.Matcher
|
||||
import org.hamcrest.TypeSafeMatcher
|
||||
import org.hamcrest.core.AllOf
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@@ -29,11 +31,13 @@ import org.junit.Rule
|
||||
import tools.fastlane.screengrab.Screengrab
|
||||
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy
|
||||
import tools.fastlane.screengrab.locale.LocaleTestRule
|
||||
import java.io.BufferedReader
|
||||
|
||||
|
||||
open class BaseUiTest<T : BaseActivity<*, *>>(
|
||||
private val activity: Class<T>
|
||||
) {
|
||||
val gson by lazy { Gson() }
|
||||
|
||||
private lateinit var mActivityScenarioRule: ActivityScenario<T>
|
||||
private var mIdlingResource: IdlingResource? = null
|
||||
@@ -41,7 +45,7 @@ open class BaseUiTest<T : BaseActivity<*, *>>(
|
||||
private lateinit var currentActivity: Activity
|
||||
|
||||
@get:Rule
|
||||
var permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
var permissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
|
||||
@get:Rule
|
||||
var snapshotRule: SnapshotRule = SnapshotRule()
|
||||
@@ -58,8 +62,8 @@ open class BaseUiTest<T : BaseActivity<*, *>>(
|
||||
mActivityScenarioRule.onActivity {
|
||||
mIdlingResource = it.getIdlingResource()!!
|
||||
IdlingRegistry.getInstance().register(mIdlingResource)
|
||||
afterLaunch(it)
|
||||
}
|
||||
afterLaunch()
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -86,7 +90,7 @@ open class BaseUiTest<T : BaseActivity<*, *>>(
|
||||
}
|
||||
|
||||
open fun beforeLaunch() {}
|
||||
open fun afterLaunch(context: Context) {}
|
||||
open fun afterLaunch() {}
|
||||
|
||||
fun checkSnackBarDisplayedByMessage(message: String) {
|
||||
onView(
|
||||
@@ -108,4 +112,22 @@ open class BaseUiTest<T : BaseActivity<*, *>>(
|
||||
})
|
||||
return currentActivity
|
||||
}
|
||||
|
||||
fun <T: Any> readDataFromAsset(fileName: String, clazz: Class<T>): T {
|
||||
val iStream =
|
||||
getInstrumentation().context.assets.open("$fileName.json")
|
||||
val data = iStream.bufferedReader().use(BufferedReader::readText)
|
||||
return gson.fromJson(data, clazz)
|
||||
}
|
||||
|
||||
inline fun <reified M: Any> readDataFromAsset(fileName: String): M {
|
||||
val iStream =
|
||||
getInstrumentation().context.assets.open("$fileName.json")
|
||||
val data = iStream.bufferedReader().use(BufferedReader::readText)
|
||||
return fromJson<M>(data)
|
||||
}
|
||||
|
||||
inline fun <reified M> fromJson(json: String)
|
||||
= gson.fromJson<M>(json, M::class.java)
|
||||
|
||||
}
|
||||
@@ -5,41 +5,32 @@ import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import org.hamcrest.Description
|
||||
import h_mal.appttude.com.driver.helpers.BaseMatcher
|
||||
import org.hamcrest.Matcher
|
||||
import org.hamcrest.TypeSafeMatcher
|
||||
|
||||
|
||||
/**
|
||||
* Matcher for testing error of TextInputLayout
|
||||
*/
|
||||
fun checkErrorMessage(expectedErrorText: String): Matcher<View?> {
|
||||
return object : TypeSafeMatcher<View?>() {
|
||||
override fun matchesSafely(view: View?): Boolean {
|
||||
if (view is EditText) {
|
||||
return view.error.toString() == expectedErrorText
|
||||
fun checkErrorMessage(expectedErrorText: String): Matcher<View> {
|
||||
return object : BaseMatcher<View>() {
|
||||
override fun match(item: View): Boolean {
|
||||
if (item is EditText) {
|
||||
return item.error.toString() == expectedErrorText
|
||||
}
|
||||
|
||||
if (view !is TextInputLayout) return false
|
||||
if (item !is TextInputLayout) return false
|
||||
|
||||
val error = view.error ?: return false
|
||||
val error = item.error ?: return false
|
||||
return expectedErrorText == error.toString()
|
||||
}
|
||||
|
||||
override fun describeTo(d: Description?) {}
|
||||
}
|
||||
}
|
||||
|
||||
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?) {}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun checkImage(): Matcher<View> {
|
||||
return object: BaseMatcher<ImageView>() {
|
||||
override fun match(item: ImageView): Boolean = hasImage(item)
|
||||
|
||||
private fun hasImage(view: ImageView): Boolean {
|
||||
val drawable = view.drawable
|
||||
@@ -49,6 +40,6 @@ fun checkImage(): Matcher<View?> {
|
||||
}
|
||||
return hasImage
|
||||
}
|
||||
}
|
||||
} as Matcher<View>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
package h_mal.appttude.com.driver
|
||||
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.ViewInteraction
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.action.ViewActions.scrollTo
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import h_mal.appttude.com.driver.helpers.getImagePath
|
||||
import h_mal.appttude.com.driver.helpers.EspressoHelper.trying
|
||||
import h_mal.appttude.com.driver.model.Model
|
||||
import org.hamcrest.CoreMatchers.allOf
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
|
||||
open class FormRobot : BaseTestRobot() {
|
||||
fun submit() = clickButton(R.id.submit)
|
||||
open class FormRobot<T : Model> : BaseTestRobot() {
|
||||
|
||||
fun submit() = onView(
|
||||
allOf(
|
||||
withId(R.id.submit),
|
||||
isAssignableFrom(com.google.android.material.button.MaterialButton::class.java)
|
||||
)
|
||||
).perform(click())
|
||||
|
||||
fun setDate(datePickerLaunchViewId: Int, year: Int, monthOfYear: Int, dayOfMonth: Int) {
|
||||
onView(withId(datePickerLaunchViewId)).perform(click())
|
||||
selectDateInPicker(year, monthOfYear, dayOfMonth)
|
||||
@@ -15,32 +29,50 @@ open class FormRobot : BaseTestRobot() {
|
||||
onView(withId(android.R.id.button1)).perform(click())
|
||||
}
|
||||
|
||||
fun selectSingleImage(imagePickerLauncherViewId: Int, filePath: FilePath) {
|
||||
selectSingleImageFromGallery(filePath) {
|
||||
onView(withId(imagePickerLauncherViewId)).perform(click())
|
||||
}
|
||||
fun setDate(datePickerLaunchViewId: Int, dateString: String) {
|
||||
onView(withId(datePickerLaunchViewId)).perform(click())
|
||||
val date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("dd/MM/yyyy"))
|
||||
selectDateInPicker(date.year, date.monthValue, date.dayOfMonth)
|
||||
// click ok in date picker
|
||||
onView(withId(android.R.id.button1)).perform(click())
|
||||
}
|
||||
|
||||
fun selectMultipleImage(imagePickerLauncherViewId: Int, filePaths: Array<String>) {
|
||||
selectMultipleImageFromGallery(filePaths) {
|
||||
fun scrollAndSetDate(datePickerLaunchViewId: Int, dateString: String) {
|
||||
onView(withId(datePickerLaunchViewId)).perform(scrollTo(), click())
|
||||
val date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("dd/MM/yyyy"))
|
||||
selectDateInPicker(date.year, date.monthValue, date.dayOfMonth)
|
||||
// click ok in date picker
|
||||
onView(withId(android.R.id.button1)).perform(click())
|
||||
}
|
||||
|
||||
fun selectSingleImage(imagePickerLauncherViewId: Int, fileName: String) {
|
||||
selectSingleImageFromGallery(fileName) {
|
||||
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)
|
||||
}
|
||||
fun selectSingleImage(imagePickerViewInteraction: ViewInteraction, fileName: String) {
|
||||
selectSingleImageFromGallery(fileName) {
|
||||
imagePickerViewInteraction.perform(click())
|
||||
}
|
||||
}
|
||||
|
||||
fun selectMultipleImage(imagePickerLauncherViewId: Int, filePaths: List<String>) {
|
||||
selectMultipleImageFromGallery(filePaths.map { "/sdcard/Camera/$it" }) {
|
||||
onView(withId(imagePickerLauncherViewId)).perform(click())
|
||||
}
|
||||
}
|
||||
|
||||
open fun submitForm(data: T) {
|
||||
(trying {
|
||||
onView(withId(R.id.submit)).perform(scrollTo())
|
||||
} ?: onView(withId(R.id.submit))).perform(click())
|
||||
}
|
||||
|
||||
open fun validateSubmission(data: T) {}
|
||||
|
||||
open fun submitAndValidate(data: T) {
|
||||
submitForm(data)
|
||||
validateSubmission(data)
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,22 @@
|
||||
package h_mal.appttude.com.driver.helpers
|
||||
|
||||
import android.view.View
|
||||
import org.hamcrest.BaseMatcher
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.TypeSafeMatcher
|
||||
|
||||
class BaseMatcher: BaseMatcher<View>() {
|
||||
override fun describeTo(description: Description?) {
|
||||
TODO("Not yet implemented")
|
||||
open class BaseMatcher<T: Any>: TypeSafeMatcher<T>() {
|
||||
override fun describeTo(description: Description?) { }
|
||||
|
||||
override fun describeMismatchSafely(item: T, mismatchDescription: Description?) {
|
||||
describe(item, mismatchDescription)
|
||||
}
|
||||
|
||||
override fun matches(actual: Any?): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun matchesSafely(item: T): Boolean = match(item)
|
||||
|
||||
open fun match(item: T): Boolean { return false }
|
||||
|
||||
open fun describe(item: T, mismatchDescription: Description?) {
|
||||
super.describeMismatchSafely(item, mismatchDescription)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +1 @@
|
||||
package h_mal.appttude.com.driver.helpers
|
||||
|
||||
import android.os.Environment
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* File paths for images on device
|
||||
*/
|
||||
fun getImagePath(imageConst: String): String {
|
||||
return File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
|
||||
"/Camera/images/$imageConst"
|
||||
).absolutePath
|
||||
}
|
||||
package h_mal.appttude.com.driver.helpers
|
||||
@@ -18,10 +18,9 @@ object DataHelper {
|
||||
|
||||
fun createClipData(filePath: String) = createClipData(createClipItem(filePath))
|
||||
|
||||
fun createClipData(filePaths: Array<String>): ClipData {
|
||||
fun createClipData(filePaths: List<String>): ClipData {
|
||||
val clipData = createClipData(filePaths[0])
|
||||
val remainingFiles = filePaths.copyOfRange(1, filePaths.size - 1)
|
||||
clipData.addFilePaths(remainingFiles)
|
||||
filePaths.filterIndexed { i, _ -> i > 0 }.let { clipData.addFilePaths(it.toTypedArray()) }
|
||||
return clipData
|
||||
}
|
||||
|
||||
|
||||
@@ -120,4 +120,50 @@ object EspressoHelper {
|
||||
|
||||
throw Exception("Error finding a view matching $viewMatcher")
|
||||
}
|
||||
|
||||
/**
|
||||
* try and perform a view interaction for
|
||||
* @param waitMillis at intervals of
|
||||
* @param waitMillisPerTry,
|
||||
* upon failure to locate an element, it will return null
|
||||
*
|
||||
*/
|
||||
fun ViewInteraction.tryPerform(
|
||||
vararg viewActions: ViewAction,
|
||||
waitMillis: Int = 1000,
|
||||
waitMillisPerTry: Long = 200,
|
||||
): 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
|
||||
return perform(*viewActions)
|
||||
|
||||
} catch (e: Exception) {
|
||||
|
||||
if (tries == maxTries) {
|
||||
throw e
|
||||
}
|
||||
sleep(waitMillisPerTry)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun <T: Any> trying(action: () -> T): T? {
|
||||
return try {
|
||||
val result = action.invoke()
|
||||
result
|
||||
}catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,24 @@
|
||||
package h_mal.appttude.com.driver.utils
|
||||
package h_mal.appttude.com.driver.untiTests
|
||||
|
||||
import androidx.startup.AppInitializer
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import h_mal.appttude.com.driver.utils.DateUtils
|
||||
import h_mal.appttude.com.driver.utils.DateUtils.convertDateStringDatePattern
|
||||
import org.junit.Assert.*
|
||||
import net.danlew.android.joda.JodaTimeInitializer
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class DateUtilsTest {
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
AppInitializer.getInstance(InstrumentationRegistry.getInstrumentation().context.applicationContext)
|
||||
.initializeComponent(JodaTimeInitializer::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_getDateTimeStamp() {
|
||||
val regex1 = "[0-9]{8}_[0-9]{6}".toRegex()
|
||||
@@ -31,6 +44,8 @@ class DateUtilsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_parseCalenderIntoDateString() {
|
||||
fun test_getDateString() {
|
||||
val date = DateUtils.getDateString(2019, 8, 1)
|
||||
assertEquals(date, "01/08/2019")
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
package h_mal.appttude.com.driver.robots
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.BaseTestRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
|
||||
fun delete(func: DeleteRobot.() -> Unit) = DeleteRobot().apply { func() }
|
||||
class DeleteRobot : FormRobot() {
|
||||
class DeleteRobot : BaseTestRobot() {
|
||||
|
||||
fun submit() = clickButton(R.id.submit)
|
||||
fun enterEmail(email: String) = fillEditText(R.id.email_update, email)
|
||||
fun enterPassword(password: String) = fillEditText(R.id.password_top, password)
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package h_mal.appttude.com.driver.robots
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.BaseTestRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
|
||||
fun updateEmail(func: UpdateEmailRobot.() -> Unit) = UpdateEmailRobot().apply { func() }
|
||||
class UpdateEmailRobot : FormRobot() {
|
||||
class UpdateEmailRobot : BaseTestRobot() {
|
||||
|
||||
fun submit() = clickButton(R.id.submit)
|
||||
fun enterEmail(email: String) = fillEditText(R.id.email_update, email)
|
||||
fun enterPassword(password: String) = fillEditText(R.id.password_top, password)
|
||||
fun enterNewEmail(email: String) = fillEditText(R.id.new_email, email)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package h_mal.appttude.com.driver.robots
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.BaseTestRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
|
||||
fun updatePassword(func: UpdatePasswordRobot.() -> Unit) = UpdatePasswordRobot().apply { func() }
|
||||
class UpdatePasswordRobot : FormRobot() {
|
||||
class UpdatePasswordRobot : BaseTestRobot() {
|
||||
|
||||
fun submit() = clickButton(R.id.submit)
|
||||
fun enterEmail(email: String) = fillEditText(R.id.email_update, email)
|
||||
fun enterPassword(password: String) = fillEditText(R.id.password_top, password)
|
||||
fun enterNewPassword(email: String) = fillEditText(R.id.password_bottom, email)
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
package h_mal.appttude.com.driver.robots
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.BaseTestRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
|
||||
fun updateProfile(func: UpdateProfileRobot.() -> Unit) = UpdateProfileRobot().apply { func() }
|
||||
class UpdateProfileRobot : FormRobot() {
|
||||
class UpdateProfileRobot : BaseTestRobot() {
|
||||
|
||||
fun submit() = clickButton(R.id.submit)
|
||||
fun enterName(name: String) = fillEditText(R.id.update_name, name)
|
||||
fun selectImage() = selectSingleImage(R.id.profile_img, FilePath.PROFILE_PIC)
|
||||
|
||||
fun submitForm(name: String) {
|
||||
// selectImage()
|
||||
selectSingleImageFromGallery("driver_profile_pic") {
|
||||
clickButton(R.id.profile_img)
|
||||
}
|
||||
enterName(name)
|
||||
submit()
|
||||
}
|
||||
|
||||
@@ -2,26 +2,23 @@ package h_mal.appttude.com.driver.robots.driver
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.model.DriversLicense
|
||||
|
||||
fun driversLicense(func: DriversLicenseRobot.() -> Unit) = DriversLicenseRobot().apply { func() }
|
||||
class DriversLicenseRobot : FormRobot() {
|
||||
class DriversLicenseRobot : FormRobot<DriversLicense>() {
|
||||
|
||||
fun enterLicenseNumber(text: String) = fillEditText(R.id.lic_no, text)
|
||||
fun enterLicenseExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) =
|
||||
setDate(R.id.lic_expiry, year, monthOfYear, dayOfMonth)
|
||||
fun enterLicenseExpiry(data: String) = setDate(R.id.lic_expiry, data)
|
||||
|
||||
fun selectImage() = selectSingleImage(R.id.search_image, FilePath.LICENSE)
|
||||
|
||||
fun submitForm(licenseNumber: String, year: Int, monthOfYear: Int, dayOfMonth: Int) {
|
||||
selectImage()
|
||||
enterLicenseNumber(licenseNumber)
|
||||
enterLicenseExpiry(year, monthOfYear, dayOfMonth)
|
||||
submit()
|
||||
override fun submitForm(data: DriversLicense) {
|
||||
selectSingleImage(R.id.search_image, data.licenseImageString!!)
|
||||
enterLicenseExpiry(data.licenseExpiry!!)
|
||||
enterLicenseNumber(data.licenseNumber!!)
|
||||
super.submitForm(data)
|
||||
}
|
||||
|
||||
fun validate() {
|
||||
checkImageViewHasImage(R.id.driversli_img)
|
||||
|
||||
override fun validateSubmission(data: DriversLicense) {
|
||||
checkImageViewDoesNotHaveDefaultImage(R.id.driversli_img)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +1,39 @@
|
||||
package h_mal.appttude.com.driver.robots.driver
|
||||
|
||||
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
|
||||
import androidx.test.espresso.action.ViewActions.scrollTo
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.model.DriverProfile
|
||||
|
||||
fun driversProfile(func: DriversProfileRobot.() -> Unit) = DriversProfileRobot().apply { func() }
|
||||
class DriversProfileRobot : FormRobot() {
|
||||
class DriversProfileRobot : FormRobot<DriverProfile>() {
|
||||
|
||||
fun enterName(name: String) = fillEditText(R.id.names_input, name)
|
||||
fun enterAddress(address: String) = fillEditText(R.id.address_input, address)
|
||||
fun enterPostcode(postcode: String) = fillEditText(R.id.postcode_input, postcode)
|
||||
fun enterDateOfBirth(dob: String) = fillEditText(R.id.dob_input, dob)
|
||||
fun enterDateOfBirth(date: String) = setDate(R.id.dob_input, date)
|
||||
|
||||
fun enterNINumber(niNumber: String) = fillEditText(R.id.ni_number, niNumber)
|
||||
fun enterDateFirstAvailable(year: Int, monthOfYear: Int, dayOfMonth: Int) =
|
||||
setDate(R.id.date_first, year, monthOfYear, dayOfMonth)
|
||||
fun enterDateFirstAvailable(date: String) {
|
||||
closeSoftKeyboard()
|
||||
matchView(R.id.date_first).perform(scrollTo())
|
||||
setDate(R.id.date_first, date)
|
||||
}
|
||||
|
||||
fun selectImage() = selectSingleImage(R.id.add_photo, FilePath.PROFILE_PIC)
|
||||
override fun validateSubmission(data: DriverProfile) {
|
||||
checkImageViewDoesNotHaveDefaultImage(R.id.driver_pic)
|
||||
matchText(R.id.names_input, data.forenames!!)
|
||||
}
|
||||
|
||||
fun submitForm(
|
||||
name: String,
|
||||
address: String,
|
||||
postcode: String,
|
||||
dob: String,
|
||||
niNumber: String,
|
||||
year: Int,
|
||||
monthOfYear: Int,
|
||||
dayOfMonth: Int
|
||||
) {
|
||||
selectImage()
|
||||
enterName(name)
|
||||
enterAddress(address)
|
||||
enterPostcode(postcode)
|
||||
enterDateOfBirth(dob)
|
||||
enterNINumber(niNumber)
|
||||
enterDateFirstAvailable(year, monthOfYear, dayOfMonth)
|
||||
submit()
|
||||
override fun submitForm(data: DriverProfile) = data.run {
|
||||
selectSingleImage(R.id.add_photo, driverPic!!)
|
||||
enterName(forenames!!)
|
||||
enterAddress(address!!)
|
||||
enterPostcode(postcode!!)
|
||||
enterDateOfBirth(dob!!)
|
||||
enterNINumber(ni!!)
|
||||
enterDateFirstAvailable(dateFirst!!)
|
||||
super.submitForm(data)
|
||||
}
|
||||
}
|
||||
@@ -2,22 +2,29 @@ package h_mal.appttude.com.driver.robots.driver
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.model.PrivateHireLicense
|
||||
|
||||
fun privateHireLicenseRobot(func: PrivateHireLicenseRobot.() -> Unit) =
|
||||
PrivateHireLicenseRobot().apply { func() }
|
||||
|
||||
class PrivateHireLicenseRobot : FormRobot() {
|
||||
class PrivateHireLicenseRobot : FormRobot<PrivateHireLicense>() {
|
||||
|
||||
fun enterLicenseNumber(text: String) = fillEditText(R.id.ph_no, text)
|
||||
fun enterLicenseExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) =
|
||||
setDate(R.id.ph_expiry, year, monthOfYear, dayOfMonth)
|
||||
fun enterLicenseExpiry(date: String) = setDate(R.id.ph_expiry, date)
|
||||
|
||||
fun selectImage() = selectSingleImage(R.id.uploadphlic, FilePath.PRIVATE_HIRE)
|
||||
fun selectImage(fileName: String) = selectSingleImage(R.id.uploadphlic, fileName)
|
||||
|
||||
fun submitForm(licenseNumber: String, year: Int, monthOfYear: Int, dayOfMonth: Int) {
|
||||
selectImage()
|
||||
enterLicenseNumber(licenseNumber)
|
||||
enterLicenseExpiry(year, monthOfYear, dayOfMonth)
|
||||
submit()
|
||||
override fun submitForm(data: PrivateHireLicense) {
|
||||
selectImage(data.phImageString!!)
|
||||
enterLicenseNumber(data.phNumber!!)
|
||||
enterLicenseExpiry(data.phExpiry!!)
|
||||
super.submitForm(data)
|
||||
}
|
||||
|
||||
fun validate(data: PrivateHireLicense) {
|
||||
checkImageViewDoesNotHaveDefaultImage(R.id.imageView2)
|
||||
matchText(R.id.ph_expiry, data.phExpiry!!)
|
||||
matchText(R.id.ph_no, data.phNumber!!)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +1,24 @@
|
||||
package h_mal.appttude.com.driver.robots.vehicle
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.FormRobot.FilePath.Companion.getFilePath
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.model.Insurance
|
||||
|
||||
fun insurance(func: InsuranceRobot.() -> Unit) = InsuranceRobot().apply { func() }
|
||||
class InsuranceRobot : FormRobot() {
|
||||
class InsuranceRobot : FormRobot<Insurance>() {
|
||||
|
||||
fun enterInsurance(text: String) = fillEditText(R.id.insurer, text)
|
||||
fun enterInsuranceExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) =
|
||||
setDate(R.id.insurance_exp, year, monthOfYear, dayOfMonth)
|
||||
fun enterInsuranceExpiry(date: String) = setDate(R.id.insurance_exp, date)
|
||||
|
||||
fun selectImages() =
|
||||
selectMultipleImage(R.id.uploadInsurance, arrayOf(getFilePath(FilePath.INSURANCE)))
|
||||
override fun submitForm(data: Insurance) {
|
||||
selectMultipleImage(R.id.uploadInsurance, data.photoStrings!!.map { it!! })
|
||||
enterInsurance(data.insurerName!!)
|
||||
enterInsuranceExpiry(data.expiryDate!!)
|
||||
super.submitForm(data)
|
||||
}
|
||||
|
||||
fun submitForm(insurer: String, year: Int, monthOfYear: Int, dayOfMonth: Int) {
|
||||
selectImages()
|
||||
enterInsurance(insurer)
|
||||
enterInsuranceExpiry(year, monthOfYear, dayOfMonth)
|
||||
submit()
|
||||
override fun validateSubmission(data: Insurance) {
|
||||
matchText(R.id.insurer, data.insurerName!!)
|
||||
matchText(R.id.insurance_exp, data.expiryDate!!)
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,21 @@ package h_mal.appttude.com.driver.robots.vehicle
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.model.Logbook
|
||||
|
||||
fun logbook(func: LogbookRobot.() -> Unit) = LogbookRobot().apply { func() }
|
||||
class LogbookRobot : FormRobot() {
|
||||
class LogbookRobot : FormRobot<Logbook>() {
|
||||
|
||||
fun selectImages() = selectSingleImage(R.id.uploadmot, FilePath.MOT)
|
||||
fun enterExpiryDate(year: Int, monthOfYear: Int, dayOfMonth: Int) =
|
||||
setDate(R.id.mot_expiry, year, monthOfYear, dayOfMonth)
|
||||
fun enterV5c(v5c: String) = fillEditText(R.id.v5c_no, v5c)
|
||||
|
||||
fun submitForm(year: Int, monthOfYear: Int, dayOfMonth: Int) {
|
||||
selectImages()
|
||||
enterExpiryDate(year, monthOfYear, dayOfMonth)
|
||||
submit()
|
||||
override fun submitForm(data: Logbook) {
|
||||
selectSingleImage(R.id.upload_lb, data.photoString!!)
|
||||
enterV5c(data.v5cnumber!!)
|
||||
super.submitForm(data)
|
||||
}
|
||||
|
||||
override fun validateSubmission(data: Logbook) {
|
||||
checkImageViewDoesNotHaveDefaultImage(R.id.log_book_img)
|
||||
matchText(R.id.v5c_no, data.v5cnumber!!)
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,21 @@ package h_mal.appttude.com.driver.robots.vehicle
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.model.Mot
|
||||
|
||||
fun mot(func: MOTRobot.() -> Unit) = MOTRobot().apply { func() }
|
||||
class MOTRobot : FormRobot() {
|
||||
class MOTRobot : FormRobot<Mot>() {
|
||||
|
||||
fun enterV5cNumber(v5c: String) = fillEditText(R.id.mot_expiry, v5c)
|
||||
fun selectImages() = selectSingleImage(R.id.mot_expiry, FilePath.LOGBOOK)
|
||||
fun enterMotExpiry(expiry: String) = setDate(R.id.mot_expiry, expiry)
|
||||
|
||||
fun submitForm(v5c: String) {
|
||||
selectImages()
|
||||
enterV5cNumber(v5c)
|
||||
submit()
|
||||
override fun submitForm(data: Mot) {
|
||||
selectSingleImage(R.id.uploadmot, data.motImageString!!)
|
||||
enterMotExpiry(data.motExpiry!!)
|
||||
super.submitForm(data)
|
||||
}
|
||||
|
||||
override fun validateSubmission(data: Mot) {
|
||||
checkImageViewDoesNotHaveDefaultImage(R.id.mot_img)
|
||||
matchText(R.id.mot_expiry, data.motExpiry!!)
|
||||
}
|
||||
}
|
||||
@@ -2,22 +2,28 @@ package h_mal.appttude.com.driver.robots.vehicle
|
||||
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.model.PrivateHireVehicle
|
||||
|
||||
fun privateHireVehicleLicense(func: PrivateHireVehicleLicenseRobot.() -> Unit) =
|
||||
PrivateHireVehicleLicenseRobot().apply { func() }
|
||||
|
||||
class PrivateHireVehicleLicenseRobot : FormRobot() {
|
||||
class PrivateHireVehicleLicenseRobot : FormRobot<PrivateHireVehicle>() {
|
||||
|
||||
fun enterLicenseNumber(text: String) = fillEditText(R.id.ph_no, text)
|
||||
fun enterLicenseExpiry(year: Int, monthOfYear: Int, dayOfMonth: Int) =
|
||||
setDate(R.id.ph_expiry, year, monthOfYear, dayOfMonth)
|
||||
fun enterLicenseExpiry(date: String) = setDate(R.id.ph_expiry, date)
|
||||
|
||||
fun selectImage() = selectSingleImage(R.id.uploadphlic, FilePath.PRIVATE_HIRE)
|
||||
override fun submitForm(data: PrivateHireVehicle) {
|
||||
selectSingleImage(
|
||||
matchText(R.string.upload_private_hire_photo),
|
||||
data.phCarImageString!!
|
||||
)
|
||||
enterLicenseNumber(data.phCarNumber!!)
|
||||
enterLicenseExpiry(data.phCarExpiry!!)
|
||||
super.submitForm(data)
|
||||
}
|
||||
|
||||
fun submitForm(licenseNumber: String, year: Int, monthOfYear: Int, dayOfMonth: Int) {
|
||||
selectImage()
|
||||
enterLicenseNumber(licenseNumber)
|
||||
enterLicenseExpiry(year, monthOfYear, dayOfMonth)
|
||||
submit()
|
||||
override fun validateSubmission(data: PrivateHireVehicle) {
|
||||
checkImageViewDoesNotHaveDefaultImage(R.id.imageView2)
|
||||
matchText(R.id.ph_no, data.phCarNumber!!)
|
||||
matchText(R.id.ph_expiry, data.phCarExpiry!!)
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,51 @@
|
||||
package h_mal.appttude.com.driver.robots.vehicle
|
||||
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isChecked
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
|
||||
import h_mal.appttude.com.driver.FormRobot
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.helpers.EspressoHelper.setChecked
|
||||
import h_mal.appttude.com.driver.model.VehicleProfile
|
||||
|
||||
fun vehicleProfile(func: VehicleProfileRobot.() -> Unit) = VehicleProfileRobot().apply { func() }
|
||||
class VehicleProfileRobot : FormRobot() {
|
||||
|
||||
fun enterRegistration(reg: String) = fillEditText(R.id.reg, reg)
|
||||
fun enterMake(make: String) = fillEditText(R.id.make, make)
|
||||
fun enterModel(model: String) = fillEditText(R.id.car_model, model)
|
||||
fun enterColour(colour: String) = fillEditText(R.id.colour, colour)
|
||||
fun enterAddress(address: String) = fillEditText(R.id.address, address)
|
||||
fun enterPostcode(postCode: String) = fillEditText(R.id.postcode, postCode)
|
||||
fun enterKeeperName(name: String) = fillEditText(R.id.keeper_name, name)
|
||||
fun enterDateFirstAvailable(year: Int, monthOfYear: Int, dayOfMonth: Int) =
|
||||
setDate(R.id.start_date, year, monthOfYear, dayOfMonth)
|
||||
class VehicleProfileRobot : FormRobot<VehicleProfile>() {
|
||||
|
||||
fun enterRegistration(reg: String) = scrollAndFillEditText(R.id.reg, reg)
|
||||
fun enterMake(make: String) = scrollAndFillEditText(R.id.make, make)
|
||||
fun enterModel(model: String) = scrollAndFillEditText(R.id.car_model, model)
|
||||
fun enterColour(colour: String) = scrollAndFillEditText(R.id.colour, colour)
|
||||
fun enterAddress(address: String) = scrollAndFillEditText(R.id.address, address)
|
||||
fun enterPostcode(postCode: String) = scrollAndFillEditText(R.id.postcode, postCode)
|
||||
fun enterKeeperName(name: String) = scrollAndFillEditText(R.id.keeper_name, name)
|
||||
fun enterDateFirstAvailable(date: String) = scrollAndSetDate(R.id.start_date, date)
|
||||
fun isSeized(seized: Boolean) = matchView(R.id.seized_checkbox).perform(setChecked(seized))
|
||||
|
||||
fun submitForm(
|
||||
reg: String,
|
||||
make: String,
|
||||
model: String,
|
||||
colour: String,
|
||||
address: String,
|
||||
postCode: String,
|
||||
name: String,
|
||||
year: Int,
|
||||
monthOfYear: Int,
|
||||
dayOfMonth: Int,
|
||||
seized: Boolean = false
|
||||
) {
|
||||
enterRegistration(reg)
|
||||
enterMake(make)
|
||||
enterModel(model)
|
||||
enterColour(colour)
|
||||
enterAddress(address)
|
||||
enterPostcode(postCode)
|
||||
enterKeeperName(name)
|
||||
enterDateFirstAvailable(year, monthOfYear, dayOfMonth)
|
||||
isSeized(seized)
|
||||
submit()
|
||||
|
||||
override fun submitForm(data: VehicleProfile) {
|
||||
enterRegistration(data.reg!!)
|
||||
enterMake(data.make!!)
|
||||
enterModel(data.model!!)
|
||||
enterColour(data.colour!!)
|
||||
enterAddress(data.keeperAddress!!)
|
||||
enterPostcode(data.keeperPostCode!!)
|
||||
enterKeeperName(data.keeperName!!)
|
||||
enterDateFirstAvailable(data.startDate!!)
|
||||
isSeized(data.isSeized)
|
||||
super.submitForm(data)
|
||||
}
|
||||
|
||||
override fun validateSubmission(data: VehicleProfile) {
|
||||
matchText(R.id.reg, data.reg!!)
|
||||
matchText(R.id.make, data.make!!)
|
||||
matchText(R.id.car_model, data.model!!)
|
||||
matchText(R.id.colour, data.colour!!)
|
||||
matchText(R.id.address, data.keeperAddress!!)
|
||||
matchText(R.id.postcode, data.keeperPostCode!!)
|
||||
matchText(R.id.keeper_name, data.keeperName!!)
|
||||
matchText(R.id.start_date, data.startDate!!)
|
||||
val checking = if (data.isSeized) isChecked() else isNotChecked()
|
||||
matchView(R.id.seized_checkbox).check(matches(checking))
|
||||
super.validateSubmission(data)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package h_mal.appttude.com.driver.tests.newUser
|
||||
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
import h_mal.appttude.com.driver.FirebaseTest
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.helpers.EspressoHelper.trying
|
||||
import h_mal.appttude.com.driver.helpers.EspressoHelper.waitForView
|
||||
import h_mal.appttude.com.driver.model.DriverProfile
|
||||
import h_mal.appttude.com.driver.model.DriversLicense
|
||||
import h_mal.appttude.com.driver.model.Insurance
|
||||
import h_mal.appttude.com.driver.model.Logbook
|
||||
import h_mal.appttude.com.driver.model.Model
|
||||
import h_mal.appttude.com.driver.model.Mot
|
||||
import h_mal.appttude.com.driver.model.PrivateHireLicense
|
||||
import h_mal.appttude.com.driver.model.PrivateHireVehicle
|
||||
import h_mal.appttude.com.driver.model.VehicleProfile
|
||||
import h_mal.appttude.com.driver.robots.home
|
||||
import h_mal.appttude.com.driver.ui.MainActivity
|
||||
import java.io.IOException
|
||||
|
||||
open class DataSubmissionTest :
|
||||
FirebaseTest<MainActivity>(MainActivity::class.java, registered = true, signedIn = true) {
|
||||
|
||||
|
||||
override fun afterLaunch() {
|
||||
super.afterLaunch()
|
||||
home {
|
||||
waitForView(withText(getResourceString(R.string.welcome_title)), waitMillis = 10000)
|
||||
trying {
|
||||
requestProfile()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : Model> getAssetData(): T {
|
||||
val file = when (T::class) {
|
||||
DriverProfile::class -> "driver_details"
|
||||
DriversLicense::class -> "drivers_license"
|
||||
Insurance::class -> "insurance_details"
|
||||
Logbook::class -> "log_book"
|
||||
Mot::class -> "mot_details"
|
||||
PrivateHireLicense::class -> "private_hire_license"
|
||||
PrivateHireVehicle::class -> "private_hire_vehicle"
|
||||
VehicleProfile::class -> "vehicle_details"
|
||||
else -> {
|
||||
throw IOException("No file for ${T::class}")
|
||||
}
|
||||
}
|
||||
return readDataFromAsset(file)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package h_mal.appttude.com.driver.tests.newUser
|
||||
|
||||
import h_mal.appttude.com.driver.robots.home
|
||||
|
||||
open class DriverProfileTest : DataSubmissionTest() {
|
||||
|
||||
override fun afterLaunch() {
|
||||
super.afterLaunch()
|
||||
home {
|
||||
openDriverProfile()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package h_mal.appttude.com.driver.tests.newUser
|
||||
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.rule.GrantPermissionRule
|
||||
import h_mal.appttude.com.driver.FirebaseTest
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.robots.*
|
||||
import h_mal.appttude.com.driver.robots.driver.driversLicense
|
||||
import h_mal.appttude.com.driver.ui.MainActivity
|
||||
import org.junit.*
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SubmitNewDataActivityTest :
|
||||
FirebaseTest<MainActivity>(MainActivity::class.java, registered = true, signedIn = true) {
|
||||
|
||||
@Test
|
||||
fun verifyUserRegistration_validUsernameAndPassword_loggedIn() {
|
||||
home {
|
||||
waitFor(2500)
|
||||
checkTitleExists(getResourceString(R.string.welcome_title))
|
||||
requestProfile()
|
||||
openDriverProfile()
|
||||
}
|
||||
driverScreen {
|
||||
driverLicense()
|
||||
}
|
||||
driversLicense {
|
||||
submitForm("SAMPLE8456310LTU", 2022, 10, 2)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package h_mal.appttude.com.driver.tests.newUser
|
||||
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import h_mal.appttude.com.driver.model.DriverProfile
|
||||
import h_mal.appttude.com.driver.model.DriversLicense
|
||||
import h_mal.appttude.com.driver.model.PrivateHireLicense
|
||||
import h_mal.appttude.com.driver.robots.*
|
||||
import h_mal.appttude.com.driver.robots.driver.driversLicense
|
||||
import h_mal.appttude.com.driver.robots.driver.driversProfile
|
||||
import h_mal.appttude.com.driver.robots.driver.privateHireLicenseRobot
|
||||
import org.junit.*
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SubmitNewDriverDataTest : DriverProfileTest() {
|
||||
|
||||
@Test
|
||||
fun signedInUser_uploadsValidLicenseDetails_uploadSuccessful() {
|
||||
driverScreen {
|
||||
driverLicense()
|
||||
}
|
||||
driversLicense {
|
||||
val data = getAssetData<DriversLicense>()
|
||||
submitAndValidate(data)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun signedInUser_uploadsValidDriverDetails_uploadSuccessful() {
|
||||
driverScreen {
|
||||
driverProfile()
|
||||
}
|
||||
driversProfile {
|
||||
val data = getAssetData<DriverProfile>()
|
||||
submitAndValidate(data)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun signedInUser_uploadsValidPrivateHireDetails_uploadSuccessful() {
|
||||
driverScreen {
|
||||
privateHireLicense()
|
||||
}
|
||||
privateHireLicenseRobot {
|
||||
val data = getAssetData<PrivateHireLicense>()
|
||||
submitAndValidate(data)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package h_mal.appttude.com.driver.tests.newUser
|
||||
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.LargeTest
|
||||
import h_mal.appttude.com.driver.model.Insurance
|
||||
import h_mal.appttude.com.driver.model.Logbook
|
||||
import h_mal.appttude.com.driver.model.Mot
|
||||
import h_mal.appttude.com.driver.model.PrivateHireVehicle
|
||||
import h_mal.appttude.com.driver.model.VehicleProfile
|
||||
import h_mal.appttude.com.driver.robots.*
|
||||
import h_mal.appttude.com.driver.robots.vehicle.insurance
|
||||
import h_mal.appttude.com.driver.robots.vehicle.logbook
|
||||
import h_mal.appttude.com.driver.robots.vehicle.mot
|
||||
import h_mal.appttude.com.driver.robots.vehicle.privateHireVehicleLicense
|
||||
import h_mal.appttude.com.driver.robots.vehicle.vehicleProfile
|
||||
import org.junit.*
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SubmitNewVehicleDataTest : VehicleProfileTest() {
|
||||
|
||||
@Test
|
||||
fun signedInUser_uploadsValidVehicleProfile_uploadSuccessful() {
|
||||
vehicleScreen {
|
||||
vehicleProfile()
|
||||
}
|
||||
vehicleProfile {
|
||||
val data = getAssetData<VehicleProfile>()
|
||||
submitAndValidate(data)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun signedInUser_uploadsValidInsurance_uploadSuccessful() {
|
||||
vehicleScreen {
|
||||
insurance()
|
||||
}
|
||||
insurance {
|
||||
val data = getAssetData<Insurance>()
|
||||
submitAndValidate(data)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun signedInUser_uploadsValidMot_uploadSuccessful() {
|
||||
vehicleScreen {
|
||||
mot()
|
||||
}
|
||||
mot {
|
||||
val data = getAssetData<Mot>()
|
||||
submitAndValidate(data)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun signedInUser_uploadsValidLogbook_uploadSuccessful() {
|
||||
vehicleScreen {
|
||||
logbook()
|
||||
}
|
||||
logbook {
|
||||
val data = getAssetData<Logbook>()
|
||||
submitAndValidate(data)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun signedInUser_uploadsValidPrivateHireVehicleLicense_uploadSuccessful() {
|
||||
vehicleScreen {
|
||||
privateHireVehicleLicense()
|
||||
}
|
||||
privateHireVehicleLicense {
|
||||
val data = getAssetData<PrivateHireVehicle>()
|
||||
submitAndValidate(data)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package h_mal.appttude.com.driver.tests.newUser
|
||||
|
||||
import h_mal.appttude.com.driver.robots.home
|
||||
|
||||
open class VehicleProfileTest : DataSubmissionTest() {
|
||||
|
||||
override fun afterLaunch() {
|
||||
super.afterLaunch()
|
||||
home {
|
||||
openVehicleProfile()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import androidx.lifecycle.ViewModelProvider
|
||||
import h_mal.appttude.com.driver.data.FirebaseAuthSource
|
||||
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
|
||||
import h_mal.appttude.com.driver.data.FirebaseStorageSource
|
||||
import h_mal.appttude.com.driver.data.prefs.PreferenceProvider
|
||||
import h_mal.appttude.com.driver.viewmodels.*
|
||||
|
||||
class ApplicationViewModelFactory(
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
package h_mal.appttude.com.driver.application
|
||||
|
||||
import android.app.Application
|
||||
import androidx.startup.AppInitializer
|
||||
import h_mal.appttude.com.driver.data.FirebaseAuthSource
|
||||
import h_mal.appttude.com.driver.data.FirebaseDatabaseSource
|
||||
import h_mal.appttude.com.driver.data.FirebaseStorageSource
|
||||
import net.danlew.android.joda.JodaTimeInitializer
|
||||
import org.kodein.di.Kodein
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.android.x.androidXModule
|
||||
import org.kodein.di.generic.bind
|
||||
import org.kodein.di.generic.singleton
|
||||
|
||||
const val GLOBAL_FORMAT = "dd/MM/yyyy"
|
||||
open class BaseApplication : Application(), KodeinAware {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
AppInitializer.getInstance(this).initializeComponent(JodaTimeInitializer::class.java)
|
||||
}
|
||||
|
||||
// Kodein aware to initialise the classes used for DI
|
||||
override val kodein = Kodein.lazy {
|
||||
import(parentModule)
|
||||
|
||||
@@ -161,10 +161,12 @@ abstract class BaseActivity<V : BaseViewModel, VB : ViewBinding> : AppCompatActi
|
||||
mIdlingResource?.setIdleState(false)
|
||||
}
|
||||
})
|
||||
toast.show()
|
||||
} else {
|
||||
|
||||
mIdlingResource?.setIdleState(true)
|
||||
toast.show()
|
||||
mIdlingResource?.setIdleState(false)
|
||||
}
|
||||
toast.show()
|
||||
}
|
||||
|
||||
fun showSnackBar(message: String) {
|
||||
|
||||
@@ -3,14 +3,11 @@ package h_mal.appttude.com.driver.dialogs
|
||||
|
||||
import android.app.DatePickerDialog
|
||||
import android.app.DatePickerDialog.OnDateSetListener
|
||||
import android.icu.util.Calendar
|
||||
import android.widget.EditText
|
||||
import h_mal.appttude.com.driver.R
|
||||
import h_mal.appttude.com.driver.utils.DateUtils
|
||||
|
||||
|
||||
private const val DATE_FORMAT = "dd/MM/yyyy"
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
class DateDialog(
|
||||
private val editText: EditText,
|
||||
@@ -19,10 +16,7 @@ class DateDialog(
|
||||
|
||||
private val dateSetListener: OnDateSetListener =
|
||||
OnDateSetListener { _, year, month, dayOfMonth ->
|
||||
val cal = Calendar.getInstance()
|
||||
cal.set(year, month + 1, dayOfMonth)
|
||||
|
||||
val date = DateUtils.parseCalenderIntoDateString(cal, DATE_FORMAT)
|
||||
val date = DateUtils.getDateString(year, month, dayOfMonth)
|
||||
dateSelected(date)
|
||||
editText.setText(date)
|
||||
editText.error = null
|
||||
@@ -33,27 +27,17 @@ class DateDialog(
|
||||
spinnersShown = true
|
||||
calendarViewShown = false
|
||||
}
|
||||
val dateString = editText.text?.toString()
|
||||
val date = if (dateString.isNullOrBlank()) {
|
||||
// Set time to now
|
||||
Calendar.getInstance()
|
||||
} else {
|
||||
// Parse current edit text string and set value
|
||||
DateUtils.parseDateStringIntoCalender(dateString, DATE_FORMAT)
|
||||
?: Calendar.getInstance()
|
||||
}
|
||||
val dateString = editText.text.toString()
|
||||
val date = DateUtils.parseDateStringIntoCalender(dateString)
|
||||
|
||||
setDateFromCalender(date)
|
||||
setOnDateSetListener(dateSetListener)
|
||||
setTitle(context.getString(R.string.set_date))
|
||||
show()
|
||||
}
|
||||
|
||||
private fun setDateFromCalender(calendar: Calendar) {
|
||||
val mYear = calendar.get(Calendar.YEAR)
|
||||
val mMonth = calendar.get(Calendar.MONTH)
|
||||
val mDay = calendar.get(Calendar.DAY_OF_MONTH)
|
||||
|
||||
updateDate(mYear, mMonth, mDay)
|
||||
private fun setDateFromCalender(calendar: org.joda.time.LocalDate) {
|
||||
updateDate(calendar.year, calendar.monthOfYear, calendar.dayOfMonth)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package h_mal.appttude.com.driver.ui.update
|
||||
|
||||
import h_mal.appttude.com.driver.base.BaseActivity
|
||||
import h_mal.appttude.com.driver.data.FirebaseCompletion
|
||||
import h_mal.appttude.com.driver.data.FirebaseCompletion.Changed
|
||||
import h_mal.appttude.com.driver.data.FirebaseCompletion.ProfileDeleted
|
||||
import h_mal.appttude.com.driver.databinding.UpdateActivityBinding
|
||||
import h_mal.appttude.com.driver.viewmodels.UpdateUserViewModel
|
||||
|
||||
@@ -10,7 +11,8 @@ class UpdateActivity : BaseActivity<UpdateUserViewModel, UpdateActivityBinding>(
|
||||
override fun onSuccess(data: Any?) {
|
||||
super.onSuccess(data)
|
||||
when (data) {
|
||||
is FirebaseCompletion.Changed -> showToast(data.message)
|
||||
is Changed -> showSnackBar(data.message)
|
||||
is ProfileDeleted -> showToast(data.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
package h_mal.appttude.com.driver.utils
|
||||
|
||||
import android.icu.util.Calendar
|
||||
import h_mal.appttude.com.driver.application.GLOBAL_FORMAT
|
||||
import org.joda.time.LocalDate
|
||||
import org.joda.time.format.DateTimeFormat
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
object DateUtils {
|
||||
|
||||
fun getDateTimeStamp(): String {
|
||||
@@ -27,26 +30,19 @@ object DateUtils {
|
||||
|
||||
private fun getSimpleDateFormat(format: String) = SimpleDateFormat(format, Locale.getDefault())
|
||||
|
||||
fun parseDateStringIntoCalender(dateString: String, format: String): Calendar? {
|
||||
val dateFormat = getSimpleDateFormat(format)
|
||||
val calendar = Calendar.getInstance()
|
||||
return try {
|
||||
calendar.time = dateFormat.parse(dateString)
|
||||
calendar
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
fun parseDateStringIntoCalender(dateString: String, format: String = GLOBAL_FORMAT): LocalDate {
|
||||
if (dateString.isBlank()) {
|
||||
return LocalDate.now()
|
||||
}
|
||||
val dtf = DateTimeFormat.forPattern(format)
|
||||
return dtf.parseLocalDate(dateString)
|
||||
}
|
||||
|
||||
fun parseCalenderIntoDateString(calendar: Calendar, format: String): String? {
|
||||
val date = calendar.time
|
||||
val dateFormat = getSimpleDateFormat(format)
|
||||
|
||||
return try {
|
||||
dateFormat.format(date)
|
||||
} catch (e: ParseException) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
fun getDateString(year: Int, month: Int, dayOfMonth: Int): String {
|
||||
val date = LocalDate.now()
|
||||
.withYear(year)
|
||||
.withMonthOfYear(month + 1)
|
||||
.withDayOfMonth(dayOfMonth)
|
||||
return date.toString(GLOBAL_FORMAT)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
android:layout_alignParentStart="true"
|
||||
android:adjustViewBounds="true"
|
||||
android:contentDescription="@string/image_description"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@drawable/choice_img_round" />
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<com.mikhaellopez.circularimageview.CircularImageView
|
||||
android:id="@+id/search_image"
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/parent_constraint_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="@dimen/activity_vertical_margin"
|
||||
android:layout_marginStart="@dimen/activity_vertical_margin"
|
||||
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:orientation="vertical"
|
||||
tools:context=".ui.driverprofile.DriverProfileFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package driver;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ rules_version = '2';
|
||||
service firebase.storage {
|
||||
match /b/{bucket}/o {
|
||||
match /{allPaths=**} {
|
||||
allow read, write: if false;
|
||||
allow read, write: if request.auth != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user