@@ -19,21 +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
30+ import androidx.compose.ui.test.filterToOne
2831import androidx.compose.ui.test.hasAnyAncestor
2932import androidx.compose.ui.test.hasText
3033import androidx.compose.ui.test.isDialog
3134import androidx.compose.ui.test.junit4.createEmptyComposeRule
35+ import androidx.compose.ui.test.onChildren
3236import androidx.compose.ui.test.onNodeWithContentDescription
3337import androidx.compose.ui.test.onNodeWithTag
3438import androidx.compose.ui.test.onNodeWithText
3539import androidx.compose.ui.test.performClick
3640import androidx.compose.ui.test.performTextInput
41+ import androidx.compose.ui.test.performTextReplacement
3742import androidx.fragment.app.commitNow
3843import androidx.recyclerview.widget.RecyclerView
3944import androidx.recyclerview.widget.RecyclerView.ViewHolder
@@ -58,16 +63,15 @@ import com.google.android.fhir.datacapture.QuestionnaireFragment
5863import com.google.android.fhir.datacapture.R
5964import com.google.android.fhir.datacapture.extensions.localDate
6065import com.google.android.fhir.datacapture.extensions.localDateTime
61- import com.google.android.fhir.datacapture.test.utilities.clickIcon
6266import com.google.android.fhir.datacapture.test.utilities.clickOnText
6367import com.google.android.fhir.datacapture.validation.Invalid
6468import com.google.android.fhir.datacapture.validation.QuestionnaireResponseValidator
6569import com.google.android.fhir.datacapture.validation.Valid
6670import com.google.android.fhir.datacapture.views.compose.DATE_TEXT_INPUT_FIELD
6771import com.google.android.fhir.datacapture.views.compose.EDIT_TEXT_FIELD_TEST_TAG
6872import com.google.android.fhir.datacapture.views.compose.HANDLE_INPUT_DEBOUNCE_TIME
73+ import com.google.android.fhir.datacapture.views.compose.TIME_PICKER_INPUT_FIELD
6974import com.google.android.material.progressindicator.LinearProgressIndicator
70- import com.google.android.material.textfield.TextInputLayout
7175import com.google.common.truth.Truth.assertThat
7276import java.math.BigDecimal
7377import java.time.LocalDate
@@ -233,57 +237,70 @@ class QuestionnaireUiEspressoTest {
233237 buildFragmentFromQuestionnaire(" /component_date_time_picker.json" )
234238
235239 // Add month and day. No need to add slashes as they are added automatically
236- onView(withId(R .id.date_input_edit_text))
237- .perform(ViewActions .click())
238- .perform(ViewActions .typeTextIntoFocusedView(" 0105" ))
240+ composeTestRule.onNodeWithTag(DATE_TEXT_INPUT_FIELD ).performTextReplacement(" 0105" )
239241
240- onView(withId(R .id.date_input_layout)).check { view, _ ->
241- val actualError = (view as TextInputLayout ).error
242- assertThat(actualError).isEqualTo(" Date format needs to be mm/dd/yyyy (e.g. 01/31/2023)" )
243- }
244- onView(withId(R .id.time_input_layout)).check { view, _ -> assertThat(view.isEnabled).isFalse() }
242+ composeTestRule
243+ .onNodeWithTag(DATE_TEXT_INPUT_FIELD )
244+ .assert (
245+ SemanticsMatcher .expectValue(
246+ SemanticsProperties .Error ,
247+ " Date format needs to be mm/dd/yyyy (e.g. 01/31/2023)" ,
248+ ),
249+ )
250+ composeTestRule.onNodeWithTag(TIME_PICKER_INPUT_FIELD ).assertIsNotEnabled()
245251 }
246252
247253 @Test
248254 fun dateTimePicker_shouldEnableTimePickerWithCorrectDate_butNotSaveInQuestionnaireResponse () {
249255 buildFragmentFromQuestionnaire(" /component_date_time_picker.json" )
250256
251- onView(withId(R .id.date_input_edit_text))
252- .perform(ViewActions .click())
253- .perform(ViewActions .typeTextIntoFocusedView(" 01052005" ))
254-
255- onView(withId(R .id.date_input_layout)).check { view, _ ->
256- val actualError = (view as TextInputLayout ).error
257- assertThat(actualError).isEqualTo(null )
258- }
257+ composeTestRule.onNodeWithTag(DATE_TEXT_INPUT_FIELD ).performTextReplacement(" 01052005" )
259258
260- onView(withId(R .id.time_input_layout)).check { view, _ -> assertThat(view.isEnabled).isTrue() }
259+ composeTestRule
260+ .onNodeWithTag(DATE_TEXT_INPUT_FIELD )
261+ .assert (
262+ SemanticsMatcher .keyNotDefined(
263+ SemanticsProperties .Error ,
264+ ),
265+ )
266+ composeTestRule.onNodeWithTag(TIME_PICKER_INPUT_FIELD ).assertIsEnabled()
261267
262- runBlocking {
263- assertThat(getQuestionnaireResponse().item.size).isEqualTo(1 )
264- assertThat(getQuestionnaireResponse().item.first().answer.size).isEqualTo(0 )
265- }
268+ val questionnaireResponse = runBlocking { getQuestionnaireResponse() }
269+ assertThat(questionnaireResponse.item.size).isEqualTo(1 )
270+ assertThat(questionnaireResponse.item.first().answer.size).isEqualTo(1 )
271+ val answer = questionnaireResponse.item.first().answer.first().valueDateTimeType
272+ assertThat(answer.localDateTime).isEqualTo(LocalDateTime .of(2005 , 1 , 5 , 0 , 0 ))
266273 }
267274
268275 @Test
269276 fun dateTimePicker_shouldSetAnswerWhenDateAndTimeAreFilled () {
270277 buildFragmentFromQuestionnaire(" /component_date_time_picker.json" )
271278
272- onView(withId(R .id.date_input_edit_text))
273- .perform(ViewActions .click())
274- .perform(ViewActions .typeTextIntoFocusedView(" 01052005" ))
279+ composeTestRule.onNodeWithTag(DATE_TEXT_INPUT_FIELD ).performTextReplacement(" 01052005" )
275280
276- onView(withId(R .id.time_input_layout)).perform(clickIcon(true ))
277- clickOnText(" AM" )
278- clickOnText(" 6" )
279- clickOnText(" 10" )
280- clickOnText(" OK" )
281+ composeTestRule
282+ .onNodeWithTag(TIME_PICKER_INPUT_FIELD )
283+ .onChildren()
284+ .filterToOne(
285+ SemanticsMatcher .expectValue(SemanticsProperties .Role , Role .Button ),
286+ )
287+ .performClick()
281288
282- runBlocking {
283- val answer = getQuestionnaireResponse().item.first().answer.first().valueDateTimeType
284- // check Locale
285- assertThat(answer.localDateTime).isEqualTo(LocalDateTime .of(2005 , 1 , 5 , 6 , 10 ))
286- }
289+ composeTestRule.onNodeWithText(" AM" ).performClick()
290+ composeTestRule.onNodeWithContentDescription(" Select hour" , substring = true ).performClick()
291+ composeTestRule.onNodeWithContentDescription(" 6 o'clock" , substring = true ).performClick()
292+
293+ composeTestRule.onNodeWithContentDescription(" Select minutes" , substring = true ).performClick()
294+ composeTestRule.onNodeWithContentDescription(" 10 minutes" , substring = true ).performClick()
295+
296+ composeTestRule.onNodeWithText(" OK" ).performClick()
297+ // Synchronize
298+ composeTestRule.waitForIdle()
299+
300+ val questionnaireResponse = runBlocking { getQuestionnaireResponse() }
301+ val answer = questionnaireResponse.item.first().answer.first().valueDateTimeType
302+ // check Locale
303+ assertThat(answer.localDateTime).isEqualTo(LocalDateTime .of(2005 , 1 , 5 , 6 , 10 ))
287304 }
288305
289306 @Test
0 commit comments