diff --git a/sharedUI/src/commonMain/kotlin/org/shahondin1624/App.kt b/sharedUI/src/commonMain/kotlin/org/shahondin1624/App.kt index 4990081..29511d7 100644 --- a/sharedUI/src/commonMain/kotlin/org/shahondin1624/App.kt +++ b/sharedUI/src/commonMain/kotlin/org/shahondin1624/App.kt @@ -17,9 +17,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch import org.jetbrains.compose.ui.tooling.preview.Preview +import org.shahondin1624.lib.components.TestTags import org.shahondin1624.lib.components.UiConstants import org.shahondin1624.lib.components.charactermodel.attributespage.AttributesPage import org.shahondin1624.model.EXAMPLE_CHARACTER @@ -73,9 +75,11 @@ private fun AppContent( onClick = { scope.launch { drawerState.close() } }, - modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp) + modifier = Modifier + .padding(horizontal = 12.dp, vertical = 4.dp) + .testTag(TestTags.NAV_CHARACTER_SHEET) ) - + NavigationDrawerItem( icon = { Icon(Icons.Default.Settings, contentDescription = null) }, label = { Text("Settings") }, @@ -84,7 +88,9 @@ private fun AppContent( scope.launch { drawerState.close() } // TODO: Navigate to settings }, - modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp) + modifier = Modifier + .padding(horizontal = 12.dp, vertical = 4.dp) + .testTag(TestTags.NAV_SETTINGS) ) } } @@ -95,20 +101,26 @@ private fun AppContent( TopAppBar( title = { Text("Shadowrun Character Sheet") }, navigationIcon = { - IconButton(onClick = { - scope.launch { - if (drawerState.isClosed) { - drawerState.open() - } else { - drawerState.close() + IconButton( + onClick = { + scope.launch { + if (drawerState.isClosed) { + drawerState.open() + } else { + drawerState.close() + } } - } - }) { + }, + modifier = Modifier.testTag(TestTags.MENU_BUTTON) + ) { Icon(Icons.Default.Menu, contentDescription = "Menu") } }, actions = { - IconButton(onClick = { isDark = !isDark }) { + IconButton( + onClick = { isDark = !isDark }, + modifier = Modifier.testTag(TestTags.THEME_TOGGLE) + ) { Icon( imageVector = if (isDark) { Icons.Default.LightMode diff --git a/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/TestTags.kt b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/TestTags.kt new file mode 100644 index 0000000..3690c75 --- /dev/null +++ b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/TestTags.kt @@ -0,0 +1,35 @@ +package org.shahondin1624.lib.components + +/** + * Centralized test tag strings for Compose UI test identification. + * + * Usage: `Modifier.testTag(TestTags.attributeCard("Body"))` + * + * Tags that reference components not yet implemented are included so that + * future stories can import them without creating a new file. + */ +object TestTags { + // --- Attribute cards --- + fun attributeCard(type: String): String = "attribute_card_${type.lowercase()}" + + // --- Talent cards --- + fun talentCard(name: String): String = "talent_card_${name.lowercase().replace(" ", "_")}" + + // --- Panels (defined for future character display stories) --- + const val PANEL_CHARACTER_HEADER = "panel_character_header" + const val PANEL_RESOURCES = "panel_resources" + const val PANEL_DERIVED_ATTRIBUTES = "panel_derived_attributes" + const val PANEL_DAMAGE_MONITOR = "panel_damage_monitor" + + // --- Navigation items --- + const val NAV_CHARACTER_SHEET = "nav_character_sheet" + const val NAV_SETTINGS = "nav_settings" + + // --- Dice / roll buttons --- + fun rollButton(name: String): String = "roll_button_${name.lowercase().replace(" ", "_")}" + + // --- Top app bar --- + const val TOP_APP_BAR = "top_app_bar" + const val THEME_TOGGLE = "theme_toggle" + const val MENU_BUTTON = "menu_button" +} diff --git a/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/attributespage/Attribute.kt b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/attributespage/Attribute.kt index a885214..ab7c553 100644 --- a/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/attributespage/Attribute.kt +++ b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/attributespage/Attribute.kt @@ -14,9 +14,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import org.jetbrains.compose.resources.painterResource +import org.shahondin1624.lib.components.TestTags import org.shahondin1624.lib.components.UiConstants.SMALL_PADDING import org.shahondin1624.lib.functions.DiceRoll import org.shahondin1624.model.attributes.Attribute @@ -33,7 +35,7 @@ fun Attribute( ) { var isInDarkMode by LocalThemeIsDark.current val textColor = if (isInDarkMode) Color.Black else Color.White - Card { + Card(modifier = Modifier.testTag(TestTags.attributeCard(attribute.type.name))) { Row( verticalAlignment = androidx.compose.ui.Alignment.CenterVertically, horizontalArrangement = Arrangement.Start @@ -64,7 +66,9 @@ fun Attribute( val result = attribute.test() onRoll(result) }, - modifier = Modifier.padding(end = SMALL_PADDING) + modifier = Modifier + .padding(end = SMALL_PADDING) + .testTag(TestTags.rollButton(attribute.type.name)) ) { Image( painter = painterResource(Res.drawable.dice), diff --git a/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/attributespage/Talent.kt b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/attributespage/Talent.kt index b80cca9..1bf5a67 100644 --- a/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/attributespage/Talent.kt +++ b/sharedUI/src/commonMain/kotlin/org/shahondin1624/lib/components/charactermodel/attributespage/Talent.kt @@ -20,9 +20,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import org.jetbrains.compose.resources.painterResource +import org.shahondin1624.lib.components.TestTags import org.shahondin1624.lib.components.UiConstants.SMALL_PADDING import org.shahondin1624.lib.functions.DiceRoll import org.shahondin1624.model.attributes.Attributes @@ -41,7 +43,7 @@ fun Talent( ) { var isInDarkMode by LocalThemeIsDark.current val textColor = if (isInDarkMode) Color.Black else Color.White - Card { + Card(modifier = Modifier.testTag(TestTags.talentCard(talent.name))) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Start @@ -84,7 +86,9 @@ fun Talent( val result = talent.test(modifiers = emptyList(), attributes = attributes) onRoll(result) }, - modifier = Modifier.padding(end = SMALL_PADDING) + modifier = Modifier + .padding(end = SMALL_PADDING) + .testTag(TestTags.rollButton(talent.name)) ) { Image( painter = painterResource(Res.drawable.dice), diff --git a/sharedUI/src/commonTest/kotlin/org/shahondin1624/TestTagsTest.kt b/sharedUI/src/commonTest/kotlin/org/shahondin1624/TestTagsTest.kt new file mode 100644 index 0000000..bd4b539 --- /dev/null +++ b/sharedUI/src/commonTest/kotlin/org/shahondin1624/TestTagsTest.kt @@ -0,0 +1,58 @@ +package org.shahondin1624 + +import org.shahondin1624.lib.components.TestTags +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class TestTagsTest { + + @Test + fun attributeCardTagFormat() { + assertEquals("attribute_card_body", TestTags.attributeCard("Body")) + assertEquals("attribute_card_agility", TestTags.attributeCard("Agility")) + assertEquals("attribute_card_charisma", TestTags.attributeCard("Charisma")) + } + + @Test + fun talentCardTagFormat() { + assertEquals("talent_card_firearms", TestTags.talentCard("Firearms")) + assertEquals("talent_card_close_combat", TestTags.talentCard("Close Combat")) + } + + @Test + fun rollButtonTagFormat() { + assertEquals("roll_button_body", TestTags.rollButton("Body")) + assertEquals("roll_button_close_combat", TestTags.rollButton("Close Combat")) + } + + @Test + fun navTagsAreDefined() { + assertEquals("nav_character_sheet", TestTags.NAV_CHARACTER_SHEET) + assertEquals("nav_settings", TestTags.NAV_SETTINGS) + } + + @Test + fun panelTagsAreDefined() { + assertTrue(TestTags.PANEL_CHARACTER_HEADER.isNotBlank()) + assertTrue(TestTags.PANEL_RESOURCES.isNotBlank()) + assertTrue(TestTags.PANEL_DERIVED_ATTRIBUTES.isNotBlank()) + assertTrue(TestTags.PANEL_DAMAGE_MONITOR.isNotBlank()) + } + + @Test + fun allTagsAreUnique() { + val staticTags = listOf( + TestTags.PANEL_CHARACTER_HEADER, + TestTags.PANEL_RESOURCES, + TestTags.PANEL_DERIVED_ATTRIBUTES, + TestTags.PANEL_DAMAGE_MONITOR, + TestTags.NAV_CHARACTER_SHEET, + TestTags.NAV_SETTINGS, + TestTags.TOP_APP_BAR, + TestTags.THEME_TOGGLE, + TestTags.MENU_BUTTON + ) + assertEquals(staticTags.size, staticTags.toSet().size, "All static tags should be unique") + } +}