From c13c174d87df8215380bb1ff1a4fa708fa890f22 Mon Sep 17 00:00:00 2001 From: Matthew A Rockwell Date: Wed, 24 Jun 2026 10:13:48 -0600 Subject: [PATCH 1/2] Update compose text field assertion steps, add new steps to assert disabled status --- .../assertion/TextFieldAssertionSteps.kt | 40 +++++++++++++++---- .../tests/compose/TestTextFieldSteps.kt | 13 ++++++ .../compose/BasicComposeActivity.kt | 28 +++++++++++++ sampleapp/src/main/res/values/strings.xml | 1 + 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/compose/src/main/java/com/progressive/kherkin/compose/steps/assertion/TextFieldAssertionSteps.kt b/compose/src/main/java/com/progressive/kherkin/compose/steps/assertion/TextFieldAssertionSteps.kt index 580c726..948e370 100644 --- a/compose/src/main/java/com/progressive/kherkin/compose/steps/assertion/TextFieldAssertionSteps.kt +++ b/compose/src/main/java/com/progressive/kherkin/compose/steps/assertion/TextFieldAssertionSteps.kt @@ -1,29 +1,55 @@ package com.progressive.kherkin.compose.steps.assertion +import androidx.compose.ui.semantics.SemanticsProperties +import androidx.compose.ui.test.SemanticsMatcher import androidx.compose.ui.test.assert -import androidx.compose.ui.test.hasSetTextAction import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.hasText +import androidx.compose.ui.test.isNotEnabled import androidx.compose.ui.test.junit4.ComposeTestRule import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText import com.progressive.kherkin.common.testcore.ComposeTestLogger import com.progressive.kherkin.common.testcore.Gherkin -/** Finds a node [tag] and checks that it has text that is displayed. */ +/** Finds a node [tag] and checks that it has EditableText. */ fun Gherkin.IShouldSeeTextField(tag: String, composeTestRule: ComposeTestRule) { ComposeTestLogger().info("${::IShouldSeeTextField.name}: onNodeWithTag($tag).assert(hasSetTextAction())") - composeTestRule.onNodeWithTag(tag).assert(hasSetTextAction()) + composeTestRule.onNodeWithTag(tag).assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.EditableText)) } -/** Finds a node text field that contains [text] and checks that it is displayed. */ +/** Finds a node that contains [text] and checks that it has EditableText. */ fun Gherkin.IShouldSeeTextFieldWithText(text: String, composeTestRule: ComposeTestRule) { ComposeTestLogger().info("${::IShouldSeeTextFieldWithText.name}: onNodeWithText($text).assert(hasSetTextAction())") - composeTestRule.onNodeWithText(text).assert(hasSetTextAction()) + composeTestRule.onNodeWithText(text).assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.EditableText)) } -/** Finds a node [tag] that contains [text] and checks that it is displayed. */ +/** Finds a node [tag] that contains [text] and checks that it has EditableText. */ fun Gherkin.IShouldSeeTextFieldWithTagAndText(tag: String, text: String, composeTestRule: ComposeTestRule) { ComposeTestLogger().info("${::IShouldSeeTextFieldWithTagAndText.name}: onNode(hasTestTag($tag).and(hasText($text))).assert(hasSetTextAction())") - composeTestRule.onNode(hasTestTag(tag).and(hasText(text))).assert(hasSetTextAction()) + composeTestRule.onNode(hasTestTag(tag).and(hasText(text))).assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.EditableText)) +} + +/** Finds a node [tag] and checks that it has EditableText and is not enabled. */ +fun Gherkin.IShouldSeeDisabledTextField(tag: String, composeTestRule: ComposeTestRule) { + ComposeTestLogger().info("${::IShouldSeeDisabledTextField.name}: onNodeWithTag($tag).assert(keyIsDefined(EditableText)).assert(isNotEnabled())") + composeTestRule.onNodeWithTag(tag) + .assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.EditableText)) + .assert(isNotEnabled()) +} + +/** Finds a node that contains [text] and checks that it has EditableText and is not enabled. */ +fun Gherkin.IShouldSeeDisabledTextFieldWithText(text: String, composeTestRule: ComposeTestRule) { + ComposeTestLogger().info("${::IShouldSeeDisabledTextFieldWithText.name}: onNode(hasText($text)).assert(keyIsDefined(EditableText)).assert(isNotEnabled())") + composeTestRule.onNode(hasText(text)) + .assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.EditableText)) + .assert(isNotEnabled()) +} + +/** Finds a node [tag] that contains [text] and checks that it has EditableText and is not enabled. */ +fun Gherkin.IShouldSeeDisabledTextFieldWithTagAndText(tag: String, text: String, composeTestRule: ComposeTestRule) { + ComposeTestLogger().info("${::IShouldSeeDisabledTextFieldWithTagAndText.name}: onNode(hasTestTag($tag).and(hasText($text))).assert(keyIsDefined(EditableText)).assert(isNotEnabled())") + composeTestRule.onNode(hasTestTag(tag).and(hasText(text))) + .assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.EditableText)) + .assert(isNotEnabled()) } \ No newline at end of file diff --git a/sampleapp/src/androidTest/java/com/progressive/sampleapp/tests/compose/TestTextFieldSteps.kt b/sampleapp/src/androidTest/java/com/progressive/sampleapp/tests/compose/TestTextFieldSteps.kt index 8883a33..b1a8f32 100644 --- a/sampleapp/src/androidTest/java/com/progressive/sampleapp/tests/compose/TestTextFieldSteps.kt +++ b/sampleapp/src/androidTest/java/com/progressive/sampleapp/tests/compose/TestTextFieldSteps.kt @@ -7,6 +7,10 @@ import com.progressive.kherkin.common.testcore.When import com.progressive.kherkin.compose.steps.actions.IClearField import com.progressive.kherkin.compose.steps.actions.IEnterTextIntoField import com.progressive.kherkin.compose.steps.actions.ILeaveFieldEmpty +import com.progressive.kherkin.compose.steps.actions.IWaitToSeeScreen +import com.progressive.kherkin.compose.steps.assertion.IShouldSeeDisabledTextField +import com.progressive.kherkin.compose.steps.assertion.IShouldSeeDisabledTextFieldWithTagAndText +import com.progressive.kherkin.compose.steps.assertion.IShouldSeeDisabledTextFieldWithText import com.progressive.kherkin.compose.steps.assertion.IShouldSeeTextField import com.progressive.kherkin.compose.steps.assertion.IShouldSeeTextFieldWithTagAndText import com.progressive.kherkin.compose.steps.assertion.IShouldSeeTextFieldWithText @@ -41,4 +45,13 @@ class TestTextFieldSteps : SampleBaseIntegrationTestCase() { When.IClearField("Prefilled Field", composeTestRule) Then.IShouldSeeTextFieldWithTagAndText("Prefilled Field", "", composeTestRule) } + + @Test + fun testDisabledTextField() { + Given.IRenderScreen(BasicComposeScreen(), composeTestRule) + When.IWaitToSeeScreen(BasicComposeScreen(), composeTestRule) + Then.IShouldSeeDisabledTextField("Disabled Field", composeTestRule) + And.IShouldSeeDisabledTextFieldWithText("Disabled text field", composeTestRule) + And.IShouldSeeDisabledTextFieldWithTagAndText("Disabled Field", "Disabled text field", composeTestRule) + } } \ No newline at end of file diff --git a/sampleapp/src/main/java/com/progressive/sampleapp/activities/compose/BasicComposeActivity.kt b/sampleapp/src/main/java/com/progressive/sampleapp/activities/compose/BasicComposeActivity.kt index 85a0ada..10fc732 100644 --- a/sampleapp/src/main/java/com/progressive/sampleapp/activities/compose/BasicComposeActivity.kt +++ b/sampleapp/src/main/java/com/progressive/sampleapp/activities/compose/BasicComposeActivity.kt @@ -91,6 +91,7 @@ fun SmallTopAppBar() { HidingButton(buttonIsVisible = buttonVisibility, changeValue = { buttonVisibility = it } ) TextField() TextFieldPrefilled() + TextFieldPrefilledDisabled() ScrollBoxes() NavigateButton() Link() @@ -193,6 +194,33 @@ private fun TextFieldPrefilled() { ) } +@Composable +private fun TextFieldPrefilledDisabled() { + val focusManager = LocalFocusManager.current + val textFieldText = stringResource(id = R.string.disabled_text_field) + var text by remember { mutableStateOf(textFieldText) } + val keyboardController = LocalSoftwareKeyboardController.current + + TextField( + value = text, + onValueChange = { text = it }, + label = { Text(stringResource(id = R.string.label)) }, + placeholder = { Text(stringResource(id = R.string.placeholder)) }, + singleLine = true, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions( + onDone = { + keyboardController?.hide() + focusManager.clearFocus() + } + ), + enabled = false, + modifier = Modifier + .padding(10.dp) + .testTag("Disabled Field") + ) +} + @Composable private fun ScrollBoxes() { Column( diff --git a/sampleapp/src/main/res/values/strings.xml b/sampleapp/src/main/res/values/strings.xml index e5279df..f065384 100644 --- a/sampleapp/src/main/res/values/strings.xml +++ b/sampleapp/src/main/res/values/strings.xml @@ -109,6 +109,7 @@ Label Placeholder Default text + Disabled text field Second Compose Activity From 969e78cbf54cb7af4861b0be9fb4400b50ec53ae Mon Sep 17 00:00:00 2001 From: Matthew A Rockwell Date: Wed, 24 Jun 2026 12:09:57 -0600 Subject: [PATCH 2/2] Fix the deploy task, maybe. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9b616f3..a6798a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,7 +62,7 @@ jobs: - name: Deploy run: | if [[ '${{ github.ref }}' =~ 'refs/tags' ]]; then - ./gradlew jreleaserFullRelease + ./gradlew common:jreleaserFullRelease else ./gradlew common:jreleaserDeploy fi