From 7e9676dcc5d74a0e7efb2bb52343e54e28b62fa9 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Tue, 5 Mar 2024 14:03:51 -0700 Subject: [PATCH] add unit tests for navigate up and pin shortcut actions on ToolDetailsLayout --- .../ui/tooldetails/ToolDetailsLayout.kt | 16 ++++-- .../ui/tooldetails/ToolDetailsLayoutTest.kt | 49 +++++++++++++++++-- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/app/src/main/kotlin/org/cru/godtools/ui/tooldetails/ToolDetailsLayout.kt b/app/src/main/kotlin/org/cru/godtools/ui/tooldetails/ToolDetailsLayout.kt index ee1ba8b2d1..0cadb4708b 100644 --- a/app/src/main/kotlin/org/cru/godtools/ui/tooldetails/ToolDetailsLayout.kt +++ b/app/src/main/kotlin/org/cru/godtools/ui/tooldetails/ToolDetailsLayout.kt @@ -80,6 +80,9 @@ import org.cru.godtools.ui.tools.VariantToolCard private val TOOL_DETAILS_HORIZONTAL_MARGIN = 32.dp +internal const val TEST_TAG_ACTION_NAVIGATE_UP = "action_up" +internal const val TEST_TAG_ACTION_OVERFLOW = "action_overflow" +internal const val TEST_TAG_ACTION_PIN_SHORTCUT = "action_pin_shortcut" internal const val TEST_TAG_ACTION_TOOL_TRAINING = "action_tool_training" @Composable @@ -94,7 +97,10 @@ fun ToolDetailsLayout(state: State, modifier: Modifier = Modifier) = DrawerMenuL TopAppBar( title = {}, navigationIcon = { - IconButton(onClick = { eventSink(Event.NavigateUp) }) { + IconButton( + onClick = { eventSink(Event.NavigateUp) }, + modifier = Modifier.testTag(TEST_TAG_ACTION_NAVIGATE_UP), + ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, null) } }, @@ -102,13 +108,17 @@ fun ToolDetailsLayout(state: State, modifier: Modifier = Modifier) = DrawerMenuL if (hasShortcut) { var showOverflow by remember { mutableStateOf(false) } - IconButton(onClick = { showOverflow = !showOverflow }) { + IconButton( + onClick = { showOverflow = !showOverflow }, + modifier = Modifier.testTag(TEST_TAG_ACTION_OVERFLOW), + ) { Icon(Icons.Filled.MoreVert, null) } DropdownMenu(expanded = showOverflow, onDismissRequest = { showOverflow = false }) { DropdownMenuItem( text = { Text(stringResource(R.string.menu_add_to_home)) }, - onClick = { eventSink(Event.PinShortcut) } + onClick = { eventSink(Event.PinShortcut) }, + modifier = Modifier.testTag(TEST_TAG_ACTION_PIN_SHORTCUT), ) } } diff --git a/app/src/testDebug/kotlin/org/cru/godtools/ui/tooldetails/ToolDetailsLayoutTest.kt b/app/src/testDebug/kotlin/org/cru/godtools/ui/tooldetails/ToolDetailsLayoutTest.kt index 0f5eb7ed72..b1c2b034f0 100644 --- a/app/src/testDebug/kotlin/org/cru/godtools/ui/tooldetails/ToolDetailsLayoutTest.kt +++ b/app/src/testDebug/kotlin/org/cru/godtools/ui/tooldetails/ToolDetailsLayoutTest.kt @@ -7,10 +7,14 @@ import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onChildren import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.slack.circuit.test.TestEventSink import io.mockk.every import io.mockk.mockk import kotlinx.collections.immutable.persistentListOf +import org.cru.godtools.ui.tooldetails.ToolDetailsScreen.Event +import org.cru.godtools.ui.tooldetails.ToolDetailsScreen.State import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -22,10 +26,45 @@ class ToolDetailsLayoutTest { @get:Rule val composeTestRule = createComposeRule() + private val events = TestEventSink() + + // region Action - Navigate Up + fun `Action - Navigate Up`() { + val state = State(eventSink = events) + composeTestRule.setContent { ToolDetailsLayout(state) } + + composeTestRule.onNodeWithTag(TEST_TAG_ACTION_NAVIGATE_UP).assertExists().performClick() + events.assertEvent(Event.NavigateUp) + } + // endregion Action - Navigate Up + + // region Action - Pin Shortcut + fun `Action - Pin Shortcut`() { + val state = State(hasShortcut = true, eventSink = events) + composeTestRule.setContent { ToolDetailsLayout(state) } + + composeTestRule.onNodeWithTag(TEST_TAG_ACTION_PIN_SHORTCUT).assertDoesNotExist() + composeTestRule.onNodeWithTag(TEST_TAG_ACTION_OVERFLOW).assertExists().performClick() + events.assertNoEvents() + + composeTestRule.onNodeWithTag(TEST_TAG_ACTION_PIN_SHORTCUT).assertExists().performClick() + events.assertEvent(Event.PinShortcut) + } + + fun `Action - Pin Shortcut - hasShortcut=false`() { + val state = State(hasShortcut = false, eventSink = events) + composeTestRule.setContent { ToolDetailsLayout(state) } + + composeTestRule.onNodeWithTag(TEST_TAG_ACTION_PIN_SHORTCUT).assertDoesNotExist() + composeTestRule.onNodeWithTag(TEST_TAG_ACTION_OVERFLOW).assertDoesNotExist() + events.assertNoEvents() + } + // endregion Action - Pin Shortcut + // region ToolDetailsActions() @Test fun `ToolDetailsActions() - Tool Training Button - visible when manifest has tips`() { - val state = ToolDetailsScreen.State(manifest = mockk { every { hasTips } returns true }) + val state = State(manifest = mockk { every { hasTips } returns true }) composeTestRule.setContent { ToolDetailsActions(state) } composeTestRule.onNodeWithTag(TEST_TAG_ACTION_TOOL_TRAINING).assertExists() @@ -33,7 +72,7 @@ class ToolDetailsLayoutTest { @Test fun `ToolDetailsActions() - Tool Training Button - gone when manifest does not have tips`() { - val state = ToolDetailsScreen.State(manifest = mockk { every { hasTips } returns false }) + val state = State(manifest = mockk { every { hasTips } returns false }) composeTestRule.setContent { ToolDetailsActions(state) } composeTestRule.onNodeWithTag(TEST_TAG_ACTION_TOOL_TRAINING).assertDoesNotExist() @@ -41,7 +80,7 @@ class ToolDetailsLayoutTest { @Test fun `ToolDetailsActions() - Tool Training Button - gone when manifest does not exist`() { - val state = ToolDetailsScreen.State(manifest = null) + val state = State(manifest = null) composeTestRule.setContent { ToolDetailsActions(state) } composeTestRule.onNodeWithTag(TEST_TAG_ACTION_TOOL_TRAINING).assertDoesNotExist() @@ -51,7 +90,7 @@ class ToolDetailsLayoutTest { // region ToolDetailsLanguages() @Test fun `ToolDetailsLanguages() - No Languages`() { - val state = ToolDetailsScreen.State(availableLanguages = persistentListOf()) + val state = State(availableLanguages = persistentListOf()) composeTestRule.setContent { ToolDetailsLanguages(state, true, {}) } // The entire ToolDetailsLanguages() composable should be gone if there are no languages @@ -60,7 +99,7 @@ class ToolDetailsLayoutTest { @Test fun `ToolDetailsLanguages() - Sorted Languages`() { - val state = ToolDetailsScreen.State( + val state = State( availableLanguages = persistentListOf("Language 1", "Language 2") ) composeTestRule.setContent { ToolDetailsLanguages(state, true, {}) }