@@ -19,22 +19,26 @@ package com.google.android.fhir.datacapture.test
1919import android.view.View
2020import android.widget.FrameLayout
2121import android.widget.TextView
22+ import androidx.compose.ui.semantics.Role
2223import androidx.compose.ui.semantics.SemanticsProperties
2324import androidx.compose.ui.test.SemanticsMatcher
2425import androidx.compose.ui.test.assert
2526import androidx.compose.ui.test.assertIsDisplayed
27+ import androidx.compose.ui.test.assertIsEnabled
2628import androidx.compose.ui.test.assertIsNotEnabled
2729import androidx.compose.ui.test.assertTextEquals
28- import androidx.compose.ui.test.junit4.createAndroidComposeRule
30+ import androidx.compose.ui.test.filterToOne
2931import androidx.compose.ui.test.hasAnyAncestor
3032import androidx.compose.ui.test.hasText
3133import androidx.compose.ui.test.isDialog
3234import androidx.compose.ui.test.junit4.createEmptyComposeRule
35+ import androidx.compose.ui.test.onChildren
3336import androidx.compose.ui.test.onNodeWithContentDescription
3437import androidx.compose.ui.test.onNodeWithTag
3538import androidx.compose.ui.test.onNodeWithText
3639import androidx.compose.ui.test.performClick
3740import androidx.compose.ui.test.performTextInput
41+ import androidx.compose.ui.test.performTextReplacement
3842import androidx.fragment.app.commitNow
3943import androidx.test.espresso.Espresso.onView
4044import androidx.test.espresso.action.ViewActions
@@ -55,16 +59,15 @@ import com.google.android.fhir.datacapture.QuestionnaireFragment
5559import com.google.android.fhir.datacapture.R
5660import com.google.android.fhir.datacapture.extensions.localDate
5761import com.google.android.fhir.datacapture.extensions.localDateTime
58- import com.google.android.fhir.datacapture.test.utilities.clickIcon
5962import com.google.android.fhir.datacapture.test.utilities.clickOnText
6063import com.google.android.fhir.datacapture.validation.Invalid
6164import com.google.android.fhir.datacapture.validation.QuestionnaireResponseValidator
6265import com.google.android.fhir.datacapture.validation.Valid
6366import com.google.android.fhir.datacapture.views.compose.DATE_TEXT_INPUT_FIELD
6467import com.google.android.fhir.datacapture.views.compose.EDIT_TEXT_FIELD_TEST_TAG
6568import com.google.android.fhir.datacapture.views.compose.HANDLE_INPUT_DEBOUNCE_TIME
69+ import com.google.android.fhir.datacapture.views.compose.TIME_PICKER_INPUT_FIELD
6670import com.google.android.material.progressindicator.LinearProgressIndicator
67- import com.google.android.material.textfield.TextInputLayout
6871import com.google.common.truth.Truth.assertThat
6972import java.math.BigDecimal
7073import java.time.LocalDate
@@ -231,57 +234,70 @@ class QuestionnaireUiEspressoTest {
231234 buildFragmentFromQuestionnaire(" /component_date_time_picker.json" )
232235
233236 // Add month and day. No need to add slashes as they are added automatically
234- onView(withId(R .id.date_input_edit_text))
235- .perform(ViewActions .click())
236- .perform(ViewActions .typeTextIntoFocusedView(" 0105" ))
237+ composeTestRule.onNodeWithTag(DATE_TEXT_INPUT_FIELD ).performTextReplacement(" 0105" )
237238
238- onView(withId(R .id.date_input_layout)).check { view, _ ->
239- val actualError = (view as TextInputLayout ).error
240- assertThat(actualError).isEqualTo(" Date format needs to be mm/dd/yyyy (e.g. 01/31/2023)" )
241- }
242- onView(withId(R .id.time_input_layout)).check { view, _ -> assertThat(view.isEnabled).isFalse() }
239+ composeTestRule
240+ .onNodeWithTag(DATE_TEXT_INPUT_FIELD )
241+ .assert (
242+ SemanticsMatcher .expectValue(
243+ SemanticsProperties .Error ,
244+ " Date format needs to be mm/dd/yyyy (e.g. 01/31/2023)" ,
245+ ),
246+ )
247+ composeTestRule.onNodeWithTag(TIME_PICKER_INPUT_FIELD ).assertIsNotEnabled()
243248 }
244249
245250 @Test
246251 fun dateTimePicker_shouldEnableTimePickerWithCorrectDate_butNotSaveInQuestionnaireResponse () {
247252 buildFragmentFromQuestionnaire(" /component_date_time_picker.json" )
248253
249- onView(withId(R .id.date_input_edit_text))
250- .perform(ViewActions .click())
251- .perform(ViewActions .typeTextIntoFocusedView(" 01052005" ))
254+ composeTestRule.onNodeWithTag(DATE_TEXT_INPUT_FIELD ).performTextReplacement(" 01052005" )
252255
253- onView(withId(R .id.date_input_layout)).check { view, _ ->
254- val actualError = (view as TextInputLayout ).error
255- assertThat(actualError).isEqualTo(null )
256- }
257-
258- onView(withId(R .id.time_input_layout)).check { view, _ -> assertThat(view.isEnabled).isTrue() }
256+ composeTestRule
257+ .onNodeWithTag(DATE_TEXT_INPUT_FIELD )
258+ .assert (
259+ SemanticsMatcher .keyNotDefined(
260+ SemanticsProperties .Error ,
261+ ),
262+ )
263+ composeTestRule.onNodeWithTag(TIME_PICKER_INPUT_FIELD ).assertIsEnabled()
259264
260- runBlocking {
261- assertThat(getQuestionnaireResponse().item.size).isEqualTo(1 )
262- assertThat(getQuestionnaireResponse().item.first().answer.size).isEqualTo(0 )
263- }
265+ val questionnaireResponse = runBlocking { getQuestionnaireResponse() }
266+ assertThat(questionnaireResponse.item.size).isEqualTo(1 )
267+ assertThat(questionnaireResponse.item.first().answer.size).isEqualTo(1 )
268+ val answer = questionnaireResponse.item.first().answer.first().valueDateTimeType
269+ assertThat(answer.localDateTime).isEqualTo(LocalDateTime .of(2005 , 1 , 5 , 0 , 0 ))
264270 }
265271
266272 @Test
267273 fun dateTimePicker_shouldSetAnswerWhenDateAndTimeAreFilled () {
268274 buildFragmentFromQuestionnaire(" /component_date_time_picker.json" )
269275
270- onView(withId(R .id.date_input_edit_text))
271- .perform(ViewActions .click())
272- .perform(ViewActions .typeTextIntoFocusedView(" 01052005" ))
276+ composeTestRule.onNodeWithTag(DATE_TEXT_INPUT_FIELD ).performTextReplacement(" 01052005" )
273277
274- onView(withId(R .id.time_input_layout)).perform(clickIcon(true ))
275- clickOnText(" AM" )
276- clickOnText(" 6" )
277- clickOnText(" 10" )
278- clickOnText(" OK" )
278+ composeTestRule
279+ .onNodeWithTag(TIME_PICKER_INPUT_FIELD )
280+ .onChildren()
281+ .filterToOne(
282+ SemanticsMatcher .expectValue(SemanticsProperties .Role , Role .Button ),
283+ )
284+ .performClick()
279285
280- runBlocking {
281- val answer = getQuestionnaireResponse().item.first().answer.first().valueDateTimeType
282- // check Locale
283- assertThat(answer.localDateTime).isEqualTo(LocalDateTime .of(2005 , 1 , 5 , 6 , 10 ))
284- }
286+ composeTestRule.onNodeWithText(" AM" ).performClick()
287+ composeTestRule.onNodeWithContentDescription(" Select hour" , substring = true ).performClick()
288+ composeTestRule.onNodeWithContentDescription(" 6 o'clock" , substring = true ).performClick()
289+
290+ composeTestRule.onNodeWithContentDescription(" Select minutes" , substring = true ).performClick()
291+ composeTestRule.onNodeWithContentDescription(" 10 minutes" , substring = true ).performClick()
292+
293+ composeTestRule.onNodeWithText(" OK" ).performClick()
294+ // Synchronize
295+ composeTestRule.waitForIdle()
296+
297+ val questionnaireResponse = runBlocking { getQuestionnaireResponse() }
298+ val answer = questionnaireResponse.item.first().answer.first().valueDateTimeType
299+ // check Locale
300+ assertThat(answer.localDateTime).isEqualTo(LocalDateTime .of(2005 , 1 , 5 , 6 , 10 ))
285301 }
286302
287303 @Test
0 commit comments