@@ -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
@@ -57,16 +62,15 @@ import com.google.android.fhir.datacapture.QuestionnaireFragment
5762import com.google.android.fhir.datacapture.R
5863import com.google.android.fhir.datacapture.extensions.localDate
5964import com.google.android.fhir.datacapture.extensions.localDateTime
60- import com.google.android.fhir.datacapture.test.utilities.clickIcon
6165import com.google.android.fhir.datacapture.test.utilities.clickOnText
6266import com.google.android.fhir.datacapture.validation.Invalid
6367import com.google.android.fhir.datacapture.validation.QuestionnaireResponseValidator
6468import com.google.android.fhir.datacapture.validation.Valid
6569import com.google.android.fhir.datacapture.views.compose.DATE_TEXT_INPUT_FIELD
6670import com.google.android.fhir.datacapture.views.compose.EDIT_TEXT_FIELD_TEST_TAG
6771import com.google.android.fhir.datacapture.views.compose.HANDLE_INPUT_DEBOUNCE_TIME
72+ import com.google.android.fhir.datacapture.views.compose.TIME_PICKER_INPUT_FIELD
6873import com.google.android.material.progressindicator.LinearProgressIndicator
69- import com.google.android.material.textfield.TextInputLayout
7074import com.google.common.truth.Truth.assertThat
7175import java.math.BigDecimal
7276import java.time.LocalDate
@@ -232,57 +236,70 @@ class QuestionnaireUiEspressoTest {
232236 buildFragmentFromQuestionnaire(" /component_date_time_picker.json" )
233237
234238 // Add month and day. No need to add slashes as they are added automatically
235- onView(withId(R .id.date_input_edit_text))
236- .perform(ViewActions .click())
237- .perform(ViewActions .typeTextIntoFocusedView(" 0105" ))
239+ composeTestRule.onNodeWithTag(DATE_TEXT_INPUT_FIELD ).performTextReplacement(" 0105" )
238240
239- onView(withId(R .id.date_input_layout)).check { view, _ ->
240- val actualError = (view as TextInputLayout ).error
241- assertThat(actualError).isEqualTo(" Date format needs to be mm/dd/yyyy (e.g. 01/31/2023)" )
242- }
243- onView(withId(R .id.time_input_layout)).check { view, _ -> assertThat(view.isEnabled).isFalse() }
241+ composeTestRule
242+ .onNodeWithTag(DATE_TEXT_INPUT_FIELD )
243+ .assert (
244+ SemanticsMatcher .expectValue(
245+ SemanticsProperties .Error ,
246+ " Date format needs to be mm/dd/yyyy (e.g. 01/31/2023)" ,
247+ ),
248+ )
249+ composeTestRule.onNodeWithTag(TIME_PICKER_INPUT_FIELD ).assertIsNotEnabled()
244250 }
245251
246252 @Test
247253 fun dateTimePicker_shouldEnableTimePickerWithCorrectDate_butNotSaveInQuestionnaireResponse () {
248254 buildFragmentFromQuestionnaire(" /component_date_time_picker.json" )
249255
250- onView(withId(R .id.date_input_edit_text))
251- .perform(ViewActions .click())
252- .perform(ViewActions .typeTextIntoFocusedView(" 01052005" ))
253-
254- onView(withId(R .id.date_input_layout)).check { view, _ ->
255- val actualError = (view as TextInputLayout ).error
256- assertThat(actualError).isEqualTo(null )
257- }
256+ composeTestRule.onNodeWithTag(DATE_TEXT_INPUT_FIELD ).performTextReplacement(" 01052005" )
258257
259- onView(withId(R .id.time_input_layout)).check { view, _ -> assertThat(view.isEnabled).isTrue() }
258+ composeTestRule
259+ .onNodeWithTag(DATE_TEXT_INPUT_FIELD )
260+ .assert (
261+ SemanticsMatcher .keyNotDefined(
262+ SemanticsProperties .Error ,
263+ ),
264+ )
265+ composeTestRule.onNodeWithTag(TIME_PICKER_INPUT_FIELD ).assertIsEnabled()
260266
261- runBlocking {
262- assertThat(getQuestionnaireResponse().item.size).isEqualTo(1 )
263- assertThat(getQuestionnaireResponse().item.first().answer.size).isEqualTo(0 )
264- }
267+ val questionnaireResponse = runBlocking { getQuestionnaireResponse() }
268+ assertThat(questionnaireResponse.item.size).isEqualTo(1 )
269+ assertThat(questionnaireResponse.item.first().answer.size).isEqualTo(1 )
270+ val answer = questionnaireResponse.item.first().answer.first().valueDateTimeType
271+ assertThat(answer.localDateTime).isEqualTo(LocalDateTime .of(2005 , 1 , 5 , 0 , 0 ))
265272 }
266273
267274 @Test
268275 fun dateTimePicker_shouldSetAnswerWhenDateAndTimeAreFilled () {
269276 buildFragmentFromQuestionnaire(" /component_date_time_picker.json" )
270277
271- onView(withId(R .id.date_input_edit_text))
272- .perform(ViewActions .click())
273- .perform(ViewActions .typeTextIntoFocusedView(" 01052005" ))
278+ composeTestRule.onNodeWithTag(DATE_TEXT_INPUT_FIELD ).performTextReplacement(" 01052005" )
274279
275- onView(withId(R .id.time_input_layout)).perform(clickIcon(true ))
276- clickOnText(" AM" )
277- clickOnText(" 6" )
278- clickOnText(" 10" )
279- clickOnText(" OK" )
280+ composeTestRule
281+ .onNodeWithTag(TIME_PICKER_INPUT_FIELD )
282+ .onChildren()
283+ .filterToOne(
284+ SemanticsMatcher .expectValue(SemanticsProperties .Role , Role .Button ),
285+ )
286+ .performClick()
280287
281- runBlocking {
282- val answer = getQuestionnaireResponse().item.first().answer.first().valueDateTimeType
283- // check Locale
284- assertThat(answer.localDateTime).isEqualTo(LocalDateTime .of(2005 , 1 , 5 , 6 , 10 ))
285- }
288+ composeTestRule.onNodeWithText(" AM" ).performClick()
289+ composeTestRule.onNodeWithContentDescription(" Select hour" , substring = true ).performClick()
290+ composeTestRule.onNodeWithContentDescription(" 6 o'clock" , substring = true ).performClick()
291+
292+ composeTestRule.onNodeWithContentDescription(" Select minutes" , substring = true ).performClick()
293+ composeTestRule.onNodeWithContentDescription(" 10 minutes" , substring = true ).performClick()
294+
295+ composeTestRule.onNodeWithText(" OK" ).performClick()
296+ // Synchronize
297+ composeTestRule.waitForIdle()
298+
299+ val questionnaireResponse = runBlocking { getQuestionnaireResponse() }
300+ val answer = questionnaireResponse.item.first().answer.first().valueDateTimeType
301+ // check Locale
302+ assertThat(answer.localDateTime).isEqualTo(LocalDateTime .of(2005 , 1 , 5 , 6 , 10 ))
286303 }
287304
288305 @Test
0 commit comments