Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

Added UI/Integration tests for creating Tellers, Teller list, teller details and Teller Task mgmt. features #193

Open
wants to merge 4 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ android:
- extra-google-m2repository
- extra-android-m2repository

script: "./gradlew build --stacktrace"
script: "./gradlew build --stacktrace"
"./gradlew build connectedAndroidTest --stacktrace"
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.apache.fineract.ui.online.tellers

import androidx.test.espresso.Espresso
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.contrib.NavigationViewActions
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import org.apache.fineract.R
import org.apache.fineract.couchbase.SynchronizationManager
import org.apache.fineract.data.models.teller.Teller
import org.apache.fineract.ui.adapters.TellerAdapter
import org.apache.fineract.ui.online.DashboardActivity
import org.apache.fineract.utils.toDataClass
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ChangeTellerStatusAndroidTest {

@get:Rule
val activityRule = ActivityTestRule<DashboardActivity>(DashboardActivity::class.java)

lateinit var synchronizationManager: SynchronizationManager

@Before
fun before() {
synchronizationManager =
SynchronizationManager(InstrumentationRegistry.getInstrumentation().context)
}

@Test
fun testTellerTaskMgmtFeature() {

//Open drawer
Espresso.onView(ViewMatchers.withId(R.id.drawer_layout))
.perform(DrawerActions.open())

// Navigate to Teller list fragment
Espresso.onView(ViewMatchers.withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.item_teller))

//Click on teller item
Espresso.onView(ViewMatchers.withId(R.id.rvTellers)).perform(
RecyclerViewActions.actionOnItem<TellerAdapter.ViewHolder>(
ViewMatchers.hasDescendant(ViewMatchers.withText("account identifier")),
ViewActions.click()
)
)

//Assert if thw item has been displayed correctly
Espresso.onView(ViewMatchers.withId(R.id.tellerDetailsAccountIdentifier))
.check(ViewAssertions.matches(ViewMatchers.withText("account identifier")))

// Launch the Bottom sheet and click on the change Task Icon
Espresso.onView(ViewMatchers.withId(R.id.llTellerDetailsTasks))
.perform(ViewActions.click())

// get current Teller model from the synchronization manager
val mapItem = synchronizationManager.getDocumentForTest(
"account identifier",
InstrumentationRegistry.getInstrumentation().context
)

val teller = mapItem.toDataClass<Teller>()
// click on the icon to change the teller status
Espresso.onView(ViewMatchers.withId(R.id.ivTellerTask))
.perform(ViewActions.click())

val prevStatus = teller.state

// confirm Task change operation
Espresso.onView(ViewMatchers.withId(R.id.btnTellerSubmitTask))
.perform(ViewActions.click())

// assert if the Teller status was changed successfully
when (prevStatus) {
Teller.State.OPEN -> {
Assert.assertEquals(teller.state, Teller.State.OPEN)
}
Teller.State.CLOSED -> {
Assert.assertEquals(teller.state, Teller.State.CLOSED)
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package org.apache.fineract.ui.online.tellers.create_teller

import android.content.Intent
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.*
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import org.apache.fineract.R
import org.apache.fineract.couchbase.SynchronizationManager
import org.apache.fineract.data.models.teller.Teller
import org.apache.fineract.ui.online.teller.TellerAction
import org.apache.fineract.ui.online.teller.createteller.CreateTellerActivity
import org.apache.fineract.utils.Constants
import org.apache.fineract.utils.toDataClass
import org.junit.*
import org.junit.runner.RunWith


/**
* Created by Varun Jain on 18/8/2021.
*/

@RunWith(AndroidJUnit4::class)
class CreateTellerActivityAndroidTest {

@get:Rule
var activityTestRule =
ActivityTestRule<CreateTellerActivity>(CreateTellerActivity::class.java, false, false)

lateinit var synchronizationManager: SynchronizationManager

@Before
fun before() {

val intent = Intent().apply {
putExtra(Constants.TELLER_ACTION, TellerAction.CREATE)
}
activityTestRule.launchActivity(intent)
synchronizationManager =
SynchronizationManager(InstrumentationRegistry.getInstrumentation().context)
}

@Test
fun isTellerListFragmentVisible() {
onView(withId(R.id.slCreateTeller))
.check(matches(isDisplayed()))
}

@Test
fun createTeller() {

// Filling all the details in Teller Details Step fragment
onView(withId(R.id.etTellerCode))
.perform(typeText("tellerCode"))
onView(withId(R.id.etTellerPassword))
.perform(typeText("teller Password"))
onView(withId(R.id.etTellerCashdrawlimit))
.perform(typeText("1000"))
onView(withId(R.id.etTellerAccountIdentifier))
.perform(typeText("teller Account Identifier"))
onView(withId(R.id.etTellerVaultIdentifier))
.perform(typeText("Teller Vault Identifier"))
.perform(closeSoftKeyboard())
onView(withId(R.id.cbTellerDenominationRequired))
.check(matches(isNotChecked()))
.perform(click())
onView(withId(R.id.etTellerCheaque))
.perform(typeText("Teller Cheques receivable amount"))
onView(withId(R.id.scrollViewTellerDetailsStep))
.perform(swipeUp())
onView(withId(R.id.etTellerCashOverShortAccount))
.perform(typeText("Cash over short Account"))
onView(withId(R.id.etTellerAssignedEmployee))
.perform(typeText("Assigned Employee"))
.perform(closeSoftKeyboard())

// Navigate to the next step
onView(withText("NEXT")).perform(click())

// Test if the Teller Review Step is populated with the correct values
onView(withId(R.id.tvTellerReviewCode)).check(matches(withText("tellerCode")))
onView(withId(R.id.tvTellerReviewPassword)).check(matches(withText("teller Password")))
onView(withId(R.id.tvTellerReviewCashdrawLimit)).check(matches(withText("1000")))
onView(withId(R.id.tvTellerReviewAccountIdentifier)).check(matches(withText("teller Account Identifier")))
onView(withId(R.id.tvTellerReviewVaultAccountIdentifier)).check(matches(withText("Teller Vault Identifier")))
onView(withId(R.id.tvTellerReviewDenomination)).check(matches(isChecked()))
onView(withId(R.id.tvTellerReviewCra)).check(matches(withText("Teller Cheques receivable amount")))
onView(withId(R.id.tvTellerReviewCashoverShortAccount)).check(matches(withText("Cash over short Account")))
onView(withId(R.id.tvTellerReviewAssignedEmployee)).check(matches(withText("Assigned Employee")))

// Complete creating the teller
onView(withText("COMPLETE")).perform(click())

// assert if the Teller has been created successfully
val mapItem = synchronizationManager.getDocumentForTest(
"teller Account Identifier",
InstrumentationRegistry.getInstrumentation().context
)

val teller = mapItem.toDataClass<Teller>()

Assert.assertEquals(teller.code, "tellerCode")
Assert.assertEquals(teller.password, "teller Password")
}

@After
fun after() {
//delete the created document in test
synchronizationManager.deleteDocument(
"testTeller"
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.apache.fineract.ui.online.tellers

import androidx.test.espresso.Espresso
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.contrib.NavigationViewActions
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.ActivityTestRule
import org.apache.fineract.R
import org.apache.fineract.ui.adapters.GroupsAdapter
import org.apache.fineract.ui.adapters.TellerAdapter
import org.apache.fineract.ui.online.DashboardActivity
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith


/**
* Created by Varun Jain on 18/8/2021.
*/

@RunWith(AndroidJUnit4::class)
class TellerListFragmentAndroidTest {

@get: Rule
val activityRule = ActivityTestRule<DashboardActivity>(DashboardActivity::class.java)

@Test
fun launchTellerListFragmentAndRvItemClickCheck() {

//Open drawer
Espresso.onView(ViewMatchers.withId(R.id.drawer_layout))
.perform(DrawerActions.open())

// Navigate to Teller list fragment
Espresso.onView(ViewMatchers.withId(R.id.nav_view))
.perform(NavigationViewActions.navigateTo(R.id.item_teller))

//Click on teller item
Espresso.onView(ViewMatchers.withId(R.id.rvTellers)).perform(
RecyclerViewActions.actionOnItem<TellerAdapter.ViewHolder>(
ViewMatchers.hasDescendant(ViewMatchers.withText("account identifier")),
ViewActions.click()
)
)

//Assert if thw item has been displayed correctly
Espresso.onView(ViewMatchers.withId(R.id.tellerDetailsAccountIdentifier))
.check(ViewAssertions.matches(ViewMatchers.withText("account identifier")))
}
}
6 changes: 6 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,16 @@

<activity android:name=".ui.online.groups.groupdetails.GroupDetailsActivity" />

<activity android:name=".ui.online.teller.tellerdetails.TellerDetailsActivity" />

<activity
android:name=".ui.online.groups.creategroup.CreateGroupActivity"
android:windowSoftInputMode="adjustResize|stateHidden" />

<activity
android:name=".ui.online.teller.createteller.CreateTellerActivity"
android:windowSoftInputMode="adjustResize|stateHidden" />

<receiver
android:name=".jobs.JobsReceiver"
android:exported="false">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ package org.apache.fineract.couchbase

enum class DocumentType(val value: String) {
GROUP("Group"),
CUSTOMER("customer")
CUSTOMER("customer"),
TELLER("Teller")
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.apache.fineract.data.datamanager

import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.ObservableSource
import io.reactivex.functions.Function
Expand All @@ -10,6 +11,7 @@ import javax.inject.Inject
import org.apache.fineract.FakeRemoteDataSource
import org.apache.fineract.data.datamanager.api.DataManagerAuth
import org.apache.fineract.data.datamanager.api.FineractBaseDataManager
import org.apache.fineract.data.models.teller.TellerCommand
import javax.inject.Singleton

@Singleton
Expand All @@ -18,13 +20,23 @@ class DataManagerTeller @Inject constructor(val baseManagerApi: BaseApiManager,
val preferencesHelper: PreferencesHelper)
: FineractBaseDataManager(dataManagerAuth, preferencesHelper) {

fun getTellers(): Observable<List<Teller>> =
baseManagerApi.tellerService.getTellerList(preferencesHelper.tenantIdentifier)
.onErrorResumeNext(Function<Throwable, ObservableSource<List<Teller>>>
{ Observable.just(FakeRemoteDataSource.getTeller()) })
fun getTellers(): Observable<List<Teller>> = baseManagerApi.tellerService
.getTellerList(preferencesHelper.tenantIdentifier)
.onErrorResumeNext(Function<Throwable, ObservableSource<List<Teller>>>
{ Observable.just(FakeRemoteDataSource.getTeller()) })

fun findTeller(tellerCode: String): Observable<Teller> = baseManagerApi.tellerService
.searchTeller(preferencesHelper.tenantIdentifier, tellerCode)
.onErrorResumeNext(Function<Throwable, ObservableSource<Teller>>
{ Observable.just(FakeRemoteDataSource.getTeller()[0]) })

fun createTeller(teller: Teller): Completable = baseManagerApi.tellerService
.createTeller(preferencesHelper.tenantIdentifier, teller)

fun updateTeller(teller: Teller): Completable = baseManagerApi.tellerService
.updateTeller(preferencesHelper.tenantIdentifier, teller.tellerAccountIdentifier!!, teller)

fun changeTellerStatus(teller: Teller, tellerCommand: TellerCommand): Completable = baseManagerApi.tellerService
.changeTellerStatus(preferencesHelper.tenantIdentifier, teller.tellerAccountIdentifier!!, tellerCommand)

}
35 changes: 18 additions & 17 deletions app/src/main/java/org/apache/fineract/data/models/teller/Teller.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,29 @@ package org.apache.fineract.data.models.teller
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize
import org.apache.fineract.couchbase.DocumentType
import java.math.BigDecimal

@Parcelize
data class Teller(

@SerializedName("code") val code: String? = null,
@SerializedName("password") val password: String? = null,
@SerializedName("cashdrawLimit") val cashdrawLimit: BigDecimal? = null,
@SerializedName("tellerAccountIdentifier") val tellerAccountIdentifier: String? = null,
@SerializedName("vaultAccountIdentifier") val vaultAccountIdentifier: String? = null,
@SerializedName("chequesReceivableAccount") val chequesReceivableAccount: String? = null,
@SerializedName("cashOverShortAccount") val cashOverShortAccount: String? = null,
@SerializedName("denominationRequired") val denominationRequired: Boolean = false,
@SerializedName("assignedEmployee") val assignedEmployee: String? = null,
@SerializedName("state") val state: State? = null,
@SerializedName("createdBy") val createdBy: String? = null,
@SerializedName("createdOn") val createdOn: String? = null,
@SerializedName("lastModifiedBy") val lastModifiedBy: String? = null,
@SerializedName("lastModifiedOn") val lastModifiedOn: String? = null,
@SerializedName("lastOpenedBy") val lastOpenedBy: String? = null,
@SerializedName("lastOpenedOn") val lastOpenedOn: String? = null

var code: String? = null,
var password: String? = null,
var cashdrawLimit: BigDecimal? = null,
var tellerAccountIdentifier: String? = null,
var vaultAccountIdentifier: String? = null,
var chequesReceivableAccount: String? = null,
var cashOverShortAccount: String? = null,
var denominationRequired: Boolean = false,
var assignedEmployee: String? = null,
var state: State? = State.OPEN,
var createdBy: String? = null,
var createdOn: String? = null,
var lastModifiedBy: String? = null,
var lastModifiedOn: String? = null,
var lastOpenedBy: String? = null,
var lastOpenedOn: String? = null,
var documentType: String = DocumentType.TELLER.value
) : Parcelable {

enum class State {
Expand Down
Loading