diff --git a/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/TestTags.kt b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/TestTags.kt index 6f0e6f4..9b3162b 100644 --- a/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/TestTags.kt +++ b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/TestTags.kt @@ -30,6 +30,13 @@ object TestTags { // --- Dice / roll buttons --- fun rollButton(name: String): String = "roll_button_${name.lowercase().replace(" ", "_")}" + // --- Dice roll result dialog --- + const val DICE_ROLL_DIALOG = "dice_roll_dialog" + const val DICE_ROLL_DICE_COUNT = "dice_roll_dice_count" + const val DICE_ROLL_SUCCESS_COUNT = "dice_roll_success_count" + const val DICE_ROLL_DISMISS_BUTTON = "dice_roll_dismiss_button" + fun dieChip(index: Int): String = "die_chip_$index" + // --- Top app bar --- const val TOP_APP_BAR = "top_app_bar" const val THEME_TOGGLE = "theme_toggle" diff --git a/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/DiceRollResultDialog.kt b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/DiceRollResultDialog.kt index eafbe88..6084c3b 100644 --- a/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/DiceRollResultDialog.kt +++ b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/DiceRollResultDialog.kt @@ -8,9 +8,11 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import org.shahondin1624.lib.components.TestTags import org.shahondin1624.lib.functions.DiceRoll /** @@ -29,6 +31,7 @@ fun DiceRollResultDialog( AlertDialog( onDismissRequest = onDismiss, + modifier = Modifier.testTag(TestTags.DICE_ROLL_DIALOG), title = { Text( text = rollLabel, @@ -46,10 +49,12 @@ fun DiceRollResultDialog( ) { Text( text = "${diceRoll.numberOfDice} dice rolled", + modifier = Modifier.testTag(TestTags.DICE_ROLL_DICE_COUNT), style = MaterialTheme.typography.bodyMedium ) Text( text = "${diceRoll.numberOfSuccesses} successes", + modifier = Modifier.testTag(TestTags.DICE_ROLL_SUCCESS_COUNT), style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Bold, color = if (diceRoll.numberOfSuccesses > 0) @@ -92,7 +97,10 @@ fun DiceRollResultDialog( } }, confirmButton = { - TextButton(onClick = onDismiss) { + TextButton( + onClick = onDismiss, + modifier = Modifier.testTag(TestTags.DICE_ROLL_DISMISS_BUTTON) + ) { Text("OK") } } @@ -106,14 +114,14 @@ private fun DiceResultGrid(results: List) { horizontalArrangement = Arrangement.spacedBy(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp) ) { - for (value in results) { - DieChip(value) + for ((index, value) in results.withIndex()) { + DieChip(value, index) } } } @Composable -private fun DieChip(value: Int) { +private fun DieChip(value: Int, index: Int) { val isSuccess = value >= 5 val isOne = value == 1 @@ -131,7 +139,8 @@ private fun DieChip(value: Int) { Box( modifier = Modifier .size(32.dp) - .background(backgroundColor, CircleShape), + .background(backgroundColor, CircleShape) + .testTag(TestTags.dieChip(index)), contentAlignment = Alignment.Center ) { Text( diff --git a/sharedUI/src/commonTest/kotlin/org/shahondin1624/DiceRollResultDialogTest.kt b/sharedUI/src/commonTest/kotlin/org/shahondin1624/DiceRollResultDialogTest.kt new file mode 100644 index 0000000..3afe336 --- /dev/null +++ b/sharedUI/src/commonTest/kotlin/org/shahondin1624/DiceRollResultDialogTest.kt @@ -0,0 +1,116 @@ +package org.shahondin1624 + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertTextContains +import androidx.compose.ui.test.onAllNodesWithTag +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.runComposeUiTest +import org.shahondin1624.lib.components.TestTags +import org.shahondin1624.lib.components.charactermodel.DiceRollResultDialog +import org.shahondin1624.lib.functions.DiceRoll +import kotlin.test.Test +import kotlin.test.assertTrue + +@OptIn(ExperimentalTestApi::class) +class DiceRollResultDialogTest { + + /** A deterministic DiceRoll with known results for testing. */ + private fun testDiceRoll() = DiceRoll( + numberOfDice = 6, + numberOfSides = 6, + numberForSuccessOrHigher = 5, + result = listOf(1, 2, 4, 5, 5, 6), + numberOfSuccesses = 3 + ) + + @Test + fun dialogShowsDiceCountAndSuccessCount() = runComposeUiTest { + setContent { + DiceRollResultDialog( + diceRoll = testDiceRoll(), + rollLabel = "Body", + onDismiss = {} + ) + } + + // Verify dialog is displayed + onNodeWithTag(TestTags.DICE_ROLL_DIALOG).assertIsDisplayed() + + // Verify dice count text + onNodeWithTag(TestTags.DICE_ROLL_DICE_COUNT).assertTextContains("6 dice rolled") + + // Verify success count text + onNodeWithTag(TestTags.DICE_ROLL_SUCCESS_COUNT).assertTextContains("3 successes") + } + + @Test + fun dialogShowsIndividualDieChips() = runComposeUiTest { + val roll = testDiceRoll() + setContent { + DiceRollResultDialog( + diceRoll = roll, + rollLabel = "Agility", + onDismiss = {} + ) + } + + // Verify each die chip is displayed + for (i in roll.result.indices) { + onNodeWithTag(TestTags.dieChip(i)).assertIsDisplayed() + } + } + + @Test + fun dialogShowsRollLabel() = runComposeUiTest { + setContent { + DiceRollResultDialog( + diceRoll = testDiceRoll(), + rollLabel = "Body", + onDismiss = {} + ) + } + + // Verify the roll label appears as title + onNodeWithText("Body").assertIsDisplayed() + } + + @Test + fun dialogCanBeDismissedViaOkButton() = runComposeUiTest { + var dismissed = false + + setContent { + var showDialog by remember { mutableStateOf(true) } + + if (showDialog) { + DiceRollResultDialog( + diceRoll = testDiceRoll(), + rollLabel = "Body", + onDismiss = { + dismissed = true + showDialog = false + } + ) + } + } + + // Dialog should be visible initially + onNodeWithTag(TestTags.DICE_ROLL_DIALOG).assertIsDisplayed() + + // Click dismiss button + onNodeWithTag(TestTags.DICE_ROLL_DISMISS_BUTTON).performClick() + + // Verify dismiss callback was triggered + assertTrue(dismissed, "onDismiss callback should have been called") + + // Dialog should no longer exist + val nodes = onAllNodesWithTag(TestTags.DICE_ROLL_DIALOG).fetchSemanticsNodes() + assertTrue(nodes.isEmpty(), "Dialog should be gone after dismiss") + } +} diff --git a/sharedUI/src/commonTest/kotlin/org/shahondin1624/TestTagsTest.kt b/sharedUI/src/commonTest/kotlin/org/shahondin1624/TestTagsTest.kt index 1996155..832e0b8 100644 --- a/sharedUI/src/commonTest/kotlin/org/shahondin1624/TestTagsTest.kt +++ b/sharedUI/src/commonTest/kotlin/org/shahondin1624/TestTagsTest.kt @@ -42,6 +42,16 @@ class TestTagsTest { assertTrue(TestTags.PANEL_DAMAGE_MONITOR.isNotBlank()) } + @Test + fun diceRollDialogTagsAreDefined() { + assertTrue(TestTags.DICE_ROLL_DIALOG.isNotBlank()) + assertTrue(TestTags.DICE_ROLL_DICE_COUNT.isNotBlank()) + assertTrue(TestTags.DICE_ROLL_SUCCESS_COUNT.isNotBlank()) + assertTrue(TestTags.DICE_ROLL_DISMISS_BUTTON.isNotBlank()) + assertEquals("die_chip_0", TestTags.dieChip(0)) + assertEquals("die_chip_5", TestTags.dieChip(5)) + } + @Test fun allTagsAreUnique() { val staticTags = listOf( @@ -55,7 +65,11 @@ class TestTagsTest { TestTags.NAV_PERMANENT_DRAWER, TestTags.TOP_APP_BAR, TestTags.THEME_TOGGLE, - TestTags.MENU_BUTTON + TestTags.MENU_BUTTON, + TestTags.DICE_ROLL_DIALOG, + TestTags.DICE_ROLL_DICE_COUNT, + TestTags.DICE_ROLL_SUCCESS_COUNT, + TestTags.DICE_ROLL_DISMISS_BUTTON ) assertEquals(staticTags.size, staticTags.toSet().size, "All static tags should be unique") }