Skip to content

Commit 3b45d77

Browse files
committed
[EKA-029] Add UI tests for consent request list screen
Co-authored by @AnusreeSajeevan
1 parent 48de064 commit 3b45d77

17 files changed

Lines changed: 358 additions & 116 deletions

File tree

app/src/androidTest/java/in/org/projecteka/jataayu/JataayuApp.kt

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package `in`.org.projecteka.jataayu.consent.ui.fragment
2+
3+
import `in`.org.projecteka.jataayu.R
4+
import org.junit.Assert.*
5+
6+
import `in`.org.projecteka.jataayu.R.id.tv_requested_date
7+
import `in`.org.projecteka.jataayu.consent.R.id.*
8+
import `in`.org.projecteka.jataayu.testUtil.MockServerDispatcher
9+
import `in`.org.projecteka.jataayu.ui.activity.TestsOnlyActivity
10+
import androidx.test.espresso.Espresso.onData
11+
import androidx.test.espresso.Espresso.onView
12+
import androidx.test.espresso.action.ViewActions.click
13+
import androidx.test.espresso.assertion.ViewAssertions.matches
14+
import androidx.test.espresso.intent.rule.IntentsTestRule
15+
import androidx.test.espresso.matcher.ViewMatchers.*
16+
import androidx.test.filters.LargeTest
17+
import androidx.test.runner.AndroidJUnit4
18+
import org.hamcrest.Matcher.*
19+
import br.com.concretesolutions.kappuccino.assertions.VisibilityAssertions.displayed
20+
import br.com.concretesolutions.kappuccino.custom.recyclerView.RecyclerViewInteractions.recyclerView
21+
import okhttp3.mockwebserver.MockWebServer
22+
import org.hamcrest.Matchers.allOf
23+
import org.junit.After
24+
import org.junit.Before
25+
import org.junit.Rule
26+
import org.junit.Test
27+
import org.junit.runner.RunWith
28+
import br.com.concretesolutions.kappuccino.actions.ClickActions.click
29+
import org.hamcrest.CoreMatchers.*
30+
31+
@LargeTest
32+
@RunWith(AndroidJUnit4::class)
33+
public class ConsentHostFragmentTest {
34+
@get:Rule
35+
var activityRule: IntentsTestRule<TestsOnlyActivity> =
36+
IntentsTestRule(TestsOnlyActivity::class.java, true, true)
37+
38+
private val consentHostFragment = ConsentHostFragment()
39+
40+
@Before
41+
@Throws(Exception::class)
42+
fun setup() {
43+
activityRule.activity.addFragment(consentHostFragment)
44+
}
45+
46+
@Test
47+
fun shouldShowRequestAndConsentsTab() {
48+
displayed {
49+
parent(R.id.tabs) {
50+
text("REQUESTS")
51+
text("CONSENTS")
52+
}
53+
allOf {
54+
id(R.id.lbl_no_new_requests)
55+
text(R.string.no_new_consent_requests)
56+
}
57+
}
58+
}
59+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package `in`.org.projecteka.jataayu.consent.ui.fragment
2+
3+
import `in`.org.projecteka.jataayu.R
4+
import `in`.org.projecteka.jataayu.R.id.tv_requested_date
5+
import `in`.org.projecteka.jataayu.consent.R.id.*
6+
import `in`.org.projecteka.jataayu.testUtil.MockServerDispatcher
7+
import `in`.org.projecteka.jataayu.ui.activity.TestsOnlyActivity
8+
import androidx.test.espresso.Espresso.onData
9+
import androidx.test.espresso.Espresso.onView
10+
import androidx.test.espresso.action.ViewActions.click
11+
import androidx.test.espresso.assertion.ViewAssertions.matches
12+
import androidx.test.espresso.intent.rule.IntentsTestRule
13+
import androidx.test.espresso.matcher.ViewMatchers.*
14+
import androidx.test.filters.LargeTest
15+
import androidx.test.runner.AndroidJUnit4
16+
import br.com.concretesolutions.kappuccino.assertions.VisibilityAssertions.displayed
17+
import br.com.concretesolutions.kappuccino.custom.recyclerView.RecyclerViewInteractions.recyclerView
18+
import okhttp3.mockwebserver.MockWebServer
19+
import org.hamcrest.Matchers.allOf
20+
import org.junit.After
21+
import org.junit.Before
22+
import org.junit.Rule
23+
import org.junit.Test
24+
import org.junit.runner.RunWith
25+
import br.com.concretesolutions.kappuccino.actions.ClickActions.click
26+
import org.hamcrest.CoreMatchers.*
27+
28+
@LargeTest
29+
@RunWith(AndroidJUnit4::class)
30+
public class RequestListFragmentTest {
31+
@get:Rule
32+
var activityRule: IntentsTestRule<TestsOnlyActivity> =
33+
IntentsTestRule(TestsOnlyActivity::class.java, true, true)
34+
35+
private lateinit var webServer: MockWebServer
36+
private lateinit var requestListFragment: RequestListFragment
37+
38+
@Before
39+
@Throws(Exception::class)
40+
fun setup() {
41+
webServer = MockWebServer()
42+
webServer.start(8080)
43+
44+
webServer.dispatcher = MockServerDispatcher().RequestDispatcher(activityRule.activity.applicationContext)
45+
46+
requestListFragment = RequestListFragment()
47+
activityRule.activity.addFragment(requestListFragment)
48+
}
49+
50+
@After
51+
@Throws(Exception::class)
52+
fun tearDown() {
53+
webServer.shutdown()
54+
}
55+
56+
@Test
57+
fun shouldShowNoRequestsScreenWhenThereAreNoRequests() {
58+
displayed {
59+
allOf {
60+
id(lbl_no_new_requests)
61+
text(R.string.no_new_consent_requests)
62+
}
63+
allOf {
64+
id(progressbar_text)
65+
text(R.string.loading_requests)
66+
}
67+
allOf {
68+
id(progressbar_container)
69+
background(R.color.progressbar_dimmed_bg)
70+
}
71+
id(progress_bar)
72+
}
73+
}
74+
75+
@Test
76+
fun shouldRenderConsentRequestItem() {
77+
Thread.sleep(1000)
78+
verifyAllRequestsRendered()
79+
}
80+
81+
@Test
82+
fun shouldRenderAllRequests() {
83+
Thread.sleep(1000)
84+
click { id(sp_request_filter) }
85+
onData(allOf(`is`(instanceOf(String::class.java)), `is`("All requests (2)"))).perform(click())
86+
onView(withId(sp_request_filter)).check(matches(withSpinnerText(containsString("All requests (2)"))))
87+
verifyAllRequestsRendered()
88+
}
89+
90+
private fun verifyAllRequestsRendered() {
91+
recyclerView(R.id.rvConsents) {
92+
sizeIs(2)
93+
atPosition(0) {
94+
displayed {
95+
allOf {
96+
id(tv_requested_date)
97+
text("Requested Jan 5, 2020")
98+
}
99+
allOf {
100+
id(tv_requester_name)
101+
text("Dr. Shruthi Nair")
102+
}
103+
allOf {
104+
id(tv_requester_organization)
105+
text("Max Health Care")
106+
}
107+
allOf {
108+
id(tv_purpose_of_request)
109+
text("General Consulting")
110+
}
111+
allOf {
112+
id(tv_requests_info_from)
113+
text("06/01/19")
114+
}
115+
allOf {
116+
id(tv_requests_info_to)
117+
text("06/01/20")
118+
}
119+
allOf {
120+
id(seperator)
121+
background(R.color.black)
122+
}
123+
image(R.drawable.ic_arrow_right)
124+
}
125+
}
126+
}
127+
}
128+
}

app/src/androidTest/java/in/org/projecteka/jataayu/provider/module/Modules.kt

Lines changed: 0 additions & 22 deletions
This file was deleted.

app/src/androidTest/java/in/org/projecteka/jataayu/provider/ui/fragment/ProviderSearchFragmentTest.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import org.junit.Rule
1919
import org.junit.Test
2020
import org.junit.runner.RunWith
2121

22-
2322
@LargeTest
2423
@RunWith(AndroidJUnit4::class)
2524
class ProviderSearchFragmentTest {

app/src/debug/assets/mockResponses/consent_list_response.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"requests": [
66
{
77
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
8-
"createdAt": "2020-01-08T04:08:33.317Z",
8+
"createdAt": "2020-01-05T04:08:33.317Z",
99
"purpose": {
1010
"text": "General Consulting",
1111
"code": "string",

app/src/debug/java/in/org/projecteka/jataayu/testUtil/MockServerDispatcher.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.Context
44
import okhttp3.mockwebserver.Dispatcher
55
import okhttp3.mockwebserver.MockResponse
66
import okhttp3.mockwebserver.RecordedRequest
7+
import java.util.concurrent.TimeUnit
78

89

910
class MockServerDispatcher {
@@ -18,6 +19,11 @@ class MockServerDispatcher {
1819
return when {
1920
request.path!!.startsWith("/providers?name=H") -> successResponse.setBody(
2021
AssetReaderUtil.asset(context, "health_insurance_providers.json"))
22+
23+
request.path!!.startsWith("/requests") -> successResponse.setBody(
24+
AssetReaderUtil.asset(context, "consent_list_response.json"))
25+
.setBodyDelay(300, TimeUnit.MILLISECONDS)
26+
2127
else -> successResponse.setBody(emptyProvidersResponse)
2228
}
2329
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package `in`.org.projecteka.jataayu.testUtil.espresso
2+
3+
import android.view.View
4+
import androidx.test.espresso.IdlingResource
5+
import androidx.test.espresso.IdlingResource.ResourceCallback
6+
import org.hamcrest.Matcher
7+
import java.lang.Thread.sleep
8+
9+
class MatcherIdlingResource(private val waitTimeInMillis: Int, private val viewMatcher: Matcher<in View?>?, val view: View?) :
10+
IdlingResource {
11+
private var resourceCallback: ResourceCallback? = null
12+
private var startTime: Long = 0
13+
private var thread: Thread? = null
14+
private var isIdleNowCallCount = 0
15+
private var matched = false
16+
17+
override fun getName(): String? = this.javaClass.name
18+
19+
override fun isIdleNow(): Boolean {
20+
val timeElapsed = now() - startTime >= waitTimeInMillis
21+
if (isMatched() || timeElapsed) {
22+
resourceCallback?.onTransitionToIdle()
23+
}
24+
isIdleNowCallCount++
25+
return isMatched() || timeElapsed
26+
}
27+
28+
override fun registerIdleTransitionCallback(resourceCallback: ResourceCallback?) {
29+
startTime = now()
30+
this.resourceCallback = resourceCallback
31+
pollViewUntilMatchesOrTimeout(resourceCallback)
32+
}
33+
34+
private fun pollViewUntilMatchesOrTimeout(resourceCallback: ResourceCallback?) {
35+
thread = Thread(Runnable {
36+
while (!viewMatcher?.matches(view)!! && (now() - startTime < waitTimeInMillis)) {
37+
try {
38+
sleep(50)
39+
} catch (ignored: InterruptedException) {
40+
}
41+
}
42+
matched = viewMatcher.matches(view)
43+
resourceCallback?.onTransitionToIdle()
44+
})
45+
thread!!.start()
46+
}
47+
48+
private fun now(): Long {
49+
return System.currentTimeMillis()
50+
}
51+
52+
fun isMatched(): Boolean {
53+
return matched
54+
}
55+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package `in`.org.projecteka.jataayu.testUtil.espresso
2+
3+
import android.view.View
4+
import androidx.test.espresso.IdlingRegistry
5+
import androidx.test.espresso.PerformException
6+
import androidx.test.espresso.UiController
7+
import androidx.test.espresso.ViewAction
8+
import androidx.test.espresso.util.HumanReadables
9+
import org.hamcrest.CustomMatcher
10+
import org.hamcrest.Matcher
11+
12+
class WaitForViewMatching(private val viewMatcher: Matcher<View?>, private val waitTimeout: Int) :
13+
ViewAction {
14+
override fun getConstraints(): CustomMatcher<View> {
15+
return anyView()!!
16+
}
17+
18+
override fun getDescription(): String {
19+
return "wait for $viewMatcher"
20+
}
21+
22+
override fun perform(
23+
uiController: UiController,
24+
view: View
25+
) {
26+
val matcherIdlingResource = MatcherIdlingResource(waitTimeout, viewMatcher, view)
27+
IdlingRegistry.getInstance().register(matcherIdlingResource)
28+
uiController.loopMainThreadUntilIdle()
29+
IdlingRegistry.getInstance().unregister(matcherIdlingResource)
30+
if (!matcherIdlingResource.isMatched()) {
31+
throw PerformException.Builder()
32+
.withActionDescription(description)
33+
.withViewDescription(
34+
HumanReadables.getViewHierarchyErrorMessage(
35+
view,
36+
null,
37+
"Action timed out : $description",
38+
null
39+
)
40+
)
41+
.build()
42+
}
43+
}
44+
45+
private fun anyView(): CustomMatcher<View>? {
46+
return object : CustomMatcher<View>("") {
47+
override fun matches(item: Any): Boolean {
48+
return true
49+
}
50+
}
51+
}
52+
53+
}

0 commit comments

Comments
 (0)