feat(kotlin-compose): design system + 33 components + gallery_kt + e2e android emulator + scaffolder fixes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 16:29:04 +02:00
parent 0b9e33da78
commit ab3f8e36b1
9 changed files with 397 additions and 26 deletions
+1
View File
@@ -56,6 +56,7 @@ dependencies {
testImplementation("io.github.takahirom.roborazzi:roborazzi:1.20.0")
testImplementation("io.github.takahirom.roborazzi:roborazzi-compose:1.20.0")
testImplementation("io.github.takahirom.roborazzi:roborazzi-junit-rule:1.20.0")
androidTestImplementation(platform("androidx.compose:compose-bom:2024.02.00"))
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
@@ -1,8 +1,10 @@
package com.fnregistry.counterkt
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
@@ -15,9 +17,31 @@ class MainActivityTest {
val composeTestRule = createAndroidComposeRule<MainActivity>()
@Test
fun appLaunchesAndShowsReadyText() {
composeTestRule
.onNodeWithText("counter_kt ready")
fun startsAtZero() {
composeTestRule.onNodeWithTag("counter_value")
.assertIsDisplayed()
.assertTextEquals("0")
}
@Test
fun incrementBumpsCounter() {
composeTestRule.onNodeWithTag("btn_increment").performClick()
composeTestRule.onNodeWithTag("btn_increment").performClick()
composeTestRule.onNodeWithTag("btn_increment").performClick()
composeTestRule.onNodeWithTag("counter_value").assertTextEquals("3")
}
@Test
fun decrementDropsCounter() {
composeTestRule.onNodeWithTag("btn_decrement").performClick()
composeTestRule.onNodeWithTag("btn_decrement").performClick()
composeTestRule.onNodeWithTag("counter_value").assertTextEquals("-2")
}
@Test
fun resetReturnsToZero() {
repeat(5) { composeTestRule.onNodeWithTag("btn_increment").performClick() }
composeTestRule.onNodeWithTag("btn_reset").performClick()
composeTestRule.onNodeWithTag("counter_value").assertTextEquals("0")
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
android:theme="@android:style/Theme.Material.Light.NoActionBar">
<activity
android:name=".MainActivity"
@@ -3,11 +3,26 @@ package com.fnregistry.counterkt
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import fn.compose.theme.FnSpacing
import fn.compose.theme.FnTheme
class MainActivity : ComponentActivity() {
@@ -16,9 +31,57 @@ class MainActivity : ComponentActivity() {
setContent {
FnTheme {
Surface(modifier = Modifier.fillMaxSize()) {
Text("counter_kt ready")
CounterScreen()
}
}
}
}
}
@Composable
fun CounterScreen(initial: Int = 0) {
var count by remember { mutableIntStateOf(initial) }
CounterContent(
count = count,
onIncrement = { count++ },
onDecrement = { count-- },
onReset = { count = 0 },
)
}
@Composable
fun CounterContent(
count: Int,
onIncrement: () -> Unit,
onDecrement: () -> Unit,
onReset: () -> Unit,
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(FnSpacing.lg),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "$count",
style = MaterialTheme.typography.displayLarge,
modifier = Modifier.testTag("counter_value"),
)
Spacer(Modifier.height(FnSpacing.lg))
Row(horizontalArrangement = Arrangement.spacedBy(FnSpacing.md)) {
Button(
onClick = onDecrement,
modifier = Modifier.testTag("btn_decrement"),
) { Text("-") }
Button(
onClick = onReset,
modifier = Modifier.testTag("btn_reset"),
) { Text("Reset") }
Button(
onClick = onIncrement,
modifier = Modifier.testTag("btn_increment"),
) { Text("+") }
}
}
}
@@ -0,0 +1,35 @@
package com.fnregistry.counterkt
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.GraphicsMode
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
class CounterLogicTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun incrementsAndDecrementsViaState() {
composeTestRule.setContent { CounterScreen() }
composeTestRule.onNodeWithTag("counter_value").assertTextEquals("0")
composeTestRule.onNodeWithTag("btn_increment").performClick()
composeTestRule.onNodeWithTag("btn_increment").performClick()
composeTestRule.onNodeWithTag("counter_value").assertTextEquals("2")
composeTestRule.onNodeWithTag("btn_decrement").performClick()
composeTestRule.onNodeWithTag("counter_value").assertTextEquals("1")
composeTestRule.onNodeWithTag("btn_reset").performClick()
composeTestRule.onNodeWithTag("counter_value").assertTextEquals("0")
}
}
@@ -1,9 +1,9 @@
package com.fnregistry.counterkt
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.ui.test.junit4.createComposeRule
import com.github.takahirom.roborazzi.RoborazziRule
import androidx.compose.ui.test.onRoot
import com.github.takahirom.roborazzi.captureRoboImage
import fn.compose.theme.FnTheme
import org.junit.Rule
import org.junit.Test
@@ -18,22 +18,24 @@ class ExampleScreenshotTest {
@get:Rule
val composeTestRule = createComposeRule()
@get:Rule
val roborazziRule = RoborazziRule(
options = RoborazziRule.Options(
outputDirectoryPath = "src/test/snapshots/images",
),
)
@Test
fun screenshotFnThemeSurface() {
private fun render(count: Int, name: String) {
composeTestRule.setContent {
FnTheme {
Surface {
Text("counter_kt screenshot")
CounterContent(
count = count,
onIncrement = {},
onDecrement = {},
onReset = {},
)
}
}
}
// Captura automaticamente al finalizar el test via RoborazziRule
composeTestRule.onRoot()
.captureRoboImage("src/test/snapshots/images/counter_$name.png")
}
@Test fun snapshotZero() = render(0, "zero")
@Test fun snapshotPositive() = render(42, "positive_42")
@Test fun snapshotNegative() = render(-7, "negative_7")
}