test: add dice roll result dialog tests and test tags (Closes #35)
Add DiceRollResultDialogTest with 4 Compose UI tests verifying dialog shows dice count, success count, individual die chips, roll label, and can be dismissed via OK button. Add test tags to DiceRollResultDialog and update TestTagsTest to cover new dice roll dialog tags. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,13 @@ object TestTags {
|
|||||||
// --- Dice / roll buttons ---
|
// --- Dice / roll buttons ---
|
||||||
fun rollButton(name: String): String = "roll_button_${name.lowercase().replace(" ", "_")}"
|
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 ---
|
// --- Top app bar ---
|
||||||
const val TOP_APP_BAR = "top_app_bar"
|
const val TOP_APP_BAR = "top_app_bar"
|
||||||
const val THEME_TOGGLE = "theme_toggle"
|
const val THEME_TOGGLE = "theme_toggle"
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import org.shahondin1624.lib.components.TestTags
|
||||||
import org.shahondin1624.lib.functions.DiceRoll
|
import org.shahondin1624.lib.functions.DiceRoll
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,6 +31,7 @@ fun DiceRollResultDialog(
|
|||||||
|
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
|
modifier = Modifier.testTag(TestTags.DICE_ROLL_DIALOG),
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(
|
||||||
text = rollLabel,
|
text = rollLabel,
|
||||||
@@ -46,10 +49,12 @@ fun DiceRollResultDialog(
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "${diceRoll.numberOfDice} dice rolled",
|
text = "${diceRoll.numberOfDice} dice rolled",
|
||||||
|
modifier = Modifier.testTag(TestTags.DICE_ROLL_DICE_COUNT),
|
||||||
style = MaterialTheme.typography.bodyMedium
|
style = MaterialTheme.typography.bodyMedium
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "${diceRoll.numberOfSuccesses} successes",
|
text = "${diceRoll.numberOfSuccesses} successes",
|
||||||
|
modifier = Modifier.testTag(TestTags.DICE_ROLL_SUCCESS_COUNT),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = if (diceRoll.numberOfSuccesses > 0)
|
color = if (diceRoll.numberOfSuccesses > 0)
|
||||||
@@ -92,7 +97,10 @@ fun DiceRollResultDialog(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(onClick = onDismiss) {
|
TextButton(
|
||||||
|
onClick = onDismiss,
|
||||||
|
modifier = Modifier.testTag(TestTags.DICE_ROLL_DISMISS_BUTTON)
|
||||||
|
) {
|
||||||
Text("OK")
|
Text("OK")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,14 +114,14 @@ private fun DiceResultGrid(results: List<Int>) {
|
|||||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(6.dp)
|
verticalArrangement = Arrangement.spacedBy(6.dp)
|
||||||
) {
|
) {
|
||||||
for (value in results) {
|
for ((index, value) in results.withIndex()) {
|
||||||
DieChip(value)
|
DieChip(value, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DieChip(value: Int) {
|
private fun DieChip(value: Int, index: Int) {
|
||||||
val isSuccess = value >= 5
|
val isSuccess = value >= 5
|
||||||
val isOne = value == 1
|
val isOne = value == 1
|
||||||
|
|
||||||
@@ -131,7 +139,8 @@ private fun DieChip(value: Int) {
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(32.dp)
|
.size(32.dp)
|
||||||
.background(backgroundColor, CircleShape),
|
.background(backgroundColor, CircleShape)
|
||||||
|
.testTag(TestTags.dieChip(index)),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,6 +42,16 @@ class TestTagsTest {
|
|||||||
assertTrue(TestTags.PANEL_DAMAGE_MONITOR.isNotBlank())
|
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
|
@Test
|
||||||
fun allTagsAreUnique() {
|
fun allTagsAreUnique() {
|
||||||
val staticTags = listOf(
|
val staticTags = listOf(
|
||||||
@@ -55,7 +65,11 @@ class TestTagsTest {
|
|||||||
TestTags.NAV_PERMANENT_DRAWER,
|
TestTags.NAV_PERMANENT_DRAWER,
|
||||||
TestTags.TOP_APP_BAR,
|
TestTags.TOP_APP_BAR,
|
||||||
TestTags.THEME_TOGGLE,
|
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")
|
assertEquals(staticTags.size, staticTags.toSet().size, "All static tags should be unique")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user