Skip to content

Commit 7308b70

Browse files
committed
Fix tests for QuantityViewHolderFactory
1 parent 8bc8ef1 commit 7308b70

File tree

5 files changed

+331
-440
lines changed

5 files changed

+331
-440
lines changed
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/*
2+
* Copyright 2023-2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.android.fhir.datacapture.test.views
18+
19+
import android.view.View
20+
import android.widget.FrameLayout
21+
import androidx.compose.ui.test.assertIsDisplayed
22+
import androidx.compose.ui.test.assertTextEquals
23+
import androidx.compose.ui.test.hasAnyAncestor
24+
import androidx.compose.ui.test.hasText
25+
import androidx.compose.ui.test.isPopup
26+
import androidx.compose.ui.test.junit4.createEmptyComposeRule
27+
import androidx.compose.ui.test.onNodeWithTag
28+
import androidx.compose.ui.test.performClick
29+
import androidx.compose.ui.test.performTextInput
30+
import androidx.test.ext.junit.rules.ActivityScenarioRule
31+
import androidx.test.platform.app.InstrumentationRegistry
32+
import com.google.android.fhir.datacapture.test.TestActivity
33+
import com.google.android.fhir.datacapture.validation.NotValidated
34+
import com.google.android.fhir.datacapture.views.QuestionnaireViewItem
35+
import com.google.android.fhir.datacapture.views.compose.DROP_DOWN_TEXT_FIELD_TAG
36+
import com.google.android.fhir.datacapture.views.compose.EDIT_TEXT_FIELD_TEST_TAG
37+
import com.google.android.fhir.datacapture.views.factories.QuantityViewHolderFactory
38+
import com.google.android.fhir.datacapture.views.factories.QuestionnaireItemViewHolder
39+
import com.google.common.truth.Truth.assertThat
40+
import java.math.BigDecimal
41+
import org.hl7.fhir.r4.model.Coding
42+
import org.hl7.fhir.r4.model.Extension
43+
import org.hl7.fhir.r4.model.Questionnaire
44+
import org.hl7.fhir.r4.model.QuestionnaireResponse
45+
import org.junit.Before
46+
import org.junit.Rule
47+
import org.junit.Test
48+
49+
class QuantityViewHolderFactoryEspressoTest {
50+
@get:Rule
51+
val activityScenarioRule: ActivityScenarioRule<TestActivity> =
52+
ActivityScenarioRule(TestActivity::class.java)
53+
54+
@get:Rule val composeTestRule = createEmptyComposeRule()
55+
56+
private lateinit var parent: FrameLayout
57+
private lateinit var viewHolder: QuestionnaireItemViewHolder
58+
59+
@Before
60+
fun setup() {
61+
activityScenarioRule.scenario.onActivity { activity -> parent = FrameLayout(activity) }
62+
viewHolder = QuantityViewHolderFactory.create(parent)
63+
setTestLayout(viewHolder.itemView)
64+
}
65+
66+
@Test
67+
fun shouldSetDraftWithUnit() {
68+
var answerHolder: List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>? = null
69+
var draftHolder: Any? = null
70+
71+
val questionnaireViewItem = createQuestionnaireViewItem { answers, draft ->
72+
answerHolder = answers
73+
draftHolder = draft
74+
}
75+
76+
runOnUI { viewHolder.bind(questionnaireViewItem) }
77+
composeTestRule.onNodeWithTag(DROP_DOWN_TEXT_FIELD_TAG).performClick()
78+
composeTestRule
79+
.onNode(hasText("centimeter") and hasAnyAncestor(isPopup()))
80+
.assertIsDisplayed()
81+
.performClick()
82+
composeTestRule.onNodeWithTag(DROP_DOWN_TEXT_FIELD_TAG).assertTextEquals("centimeter")
83+
84+
composeTestRule.waitUntil { draftHolder != null }
85+
86+
with(draftHolder as Coding) {
87+
assertThat(system).isEqualTo("http://unitofmeasure.com")
88+
assertThat(code).isEqualTo("cm")
89+
assertThat(display).isEqualTo("centimeter")
90+
}
91+
assertThat(answerHolder).isEmpty()
92+
}
93+
94+
@Test
95+
fun shouldSetDraftWithDecimalValue() {
96+
var answerHolder: List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>? = null
97+
var draftHolder: Any? = null
98+
99+
val questionnaireViewItem = createQuestionnaireViewItem { answers, draft ->
100+
answerHolder = answers
101+
draftHolder = draft
102+
}
103+
104+
runOnUI { viewHolder.bind(questionnaireViewItem) }
105+
106+
composeTestRule.onNodeWithTag(EDIT_TEXT_FIELD_TEST_TAG).performClick().performTextInput("22")
107+
composeTestRule.waitUntil { draftHolder != null }
108+
composeTestRule.onNodeWithTag(EDIT_TEXT_FIELD_TEST_TAG).assertTextEquals("22")
109+
110+
assertThat(draftHolder as BigDecimal).isEqualTo(BigDecimal(22))
111+
assertThat(answerHolder).isEmpty()
112+
}
113+
114+
@Test
115+
fun draftWithUnit_shouldCompleteQuantity() {
116+
var answerHolder: List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>? = null
117+
var draftHolder: Any? = null
118+
119+
val questionnaireViewItem =
120+
createQuestionnaireViewItem(Coding("http://unitofmeasure.com", "cm", "centimeter")) {
121+
answers,
122+
draft,
123+
->
124+
answerHolder = answers
125+
draftHolder = draft
126+
}
127+
128+
runOnUI { viewHolder.bind(questionnaireViewItem) }
129+
composeTestRule.onNodeWithTag(DROP_DOWN_TEXT_FIELD_TAG).performClick()
130+
composeTestRule.onNodeWithTag(EDIT_TEXT_FIELD_TEST_TAG).performClick().performTextInput("22")
131+
132+
composeTestRule.waitUntil { !answerHolder.isNullOrEmpty() }
133+
134+
composeTestRule.onNodeWithTag(EDIT_TEXT_FIELD_TEST_TAG).assertTextEquals("22")
135+
136+
with(answerHolder!!.single().valueQuantity) {
137+
assertThat(system).isEqualTo("http://unitofmeasure.com")
138+
assertThat(code).isEqualTo("cm")
139+
assertThat(unit).isEqualTo("centimeter")
140+
assertThat(value).isEqualTo(BigDecimal("22.0"))
141+
}
142+
assertThat(draftHolder).isNull()
143+
}
144+
145+
@Test
146+
fun draftWithDecimalValue_shouldCompleteQuantity() {
147+
var answerHolder: List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>? = null
148+
var draftHolder: Any? = null
149+
150+
val questionnaireViewItem =
151+
createQuestionnaireViewItem(BigDecimal(22)) { answers, draft ->
152+
answerHolder = answers
153+
draftHolder = draft
154+
}
155+
156+
runOnUI { viewHolder.bind(questionnaireViewItem) }
157+
composeTestRule.onNodeWithTag(DROP_DOWN_TEXT_FIELD_TAG).performClick()
158+
composeTestRule
159+
.onNode(hasText("centimeter") and hasAnyAncestor(isPopup()))
160+
.assertIsDisplayed()
161+
.performClick()
162+
composeTestRule.onNodeWithTag(DROP_DOWN_TEXT_FIELD_TAG).assertTextEquals("centimeter")
163+
164+
composeTestRule.waitUntil { !answerHolder.isNullOrEmpty() }
165+
166+
with(answerHolder!!.single().valueQuantity) {
167+
assertThat(system).isEqualTo("http://unitofmeasure.com")
168+
assertThat(code).isEqualTo("cm")
169+
assertThat(unit).isEqualTo("centimeter")
170+
assertThat(value).isEqualTo(BigDecimal("22.0"))
171+
}
172+
assertThat(draftHolder).isNull()
173+
}
174+
175+
private fun createQuestionnaireViewItem(
176+
draftAnswer: Any? = null,
177+
answersChangedCallback:
178+
(List<QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent>, Any?) -> Unit,
179+
): QuestionnaireViewItem {
180+
return QuestionnaireViewItem(
181+
Questionnaire.QuestionnaireItemComponent().apply {
182+
required = true
183+
addExtension(
184+
Extension().apply {
185+
url = "http://hl7.org/fhir/StructureDefinition/questionnaire-unitOption"
186+
setValue(
187+
Coding().apply {
188+
code = "cm"
189+
system = "http://unitofmeasure.com"
190+
display = "centimeter"
191+
},
192+
)
193+
},
194+
)
195+
addExtension(
196+
Extension().apply {
197+
url = "http://hl7.org/fhir/StructureDefinition/questionnaire-unitOption"
198+
setValue(
199+
Coding().apply {
200+
code = "[in_i]"
201+
system = "http://unitofmeasure.com"
202+
display = "inch"
203+
},
204+
)
205+
},
206+
)
207+
},
208+
QuestionnaireResponse.QuestionnaireResponseItemComponent(),
209+
validationResult = NotValidated,
210+
answersChangedCallback = { _, _, answers, draft -> answersChangedCallback(answers, draft) },
211+
draftAnswer = draftAnswer,
212+
)
213+
}
214+
215+
/** Method to run code snippet on UI/main thread */
216+
private fun runOnUI(action: () -> Unit) {
217+
activityScenarioRule.scenario.onActivity { action() }
218+
}
219+
220+
/** Method to set content view for test activity */
221+
private fun setTestLayout(view: View) {
222+
activityScenarioRule.scenario.onActivity { activity -> activity.setContentView(view) }
223+
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
224+
}
225+
}

0 commit comments

Comments
 (0)