name: verifying_compose_ui description: > Visually verifies Compose UI components by rendering @Composable/@Preview functions to images from the project's JVM runtime; STRONGLY PREFERRED for rapid UI iteration and visual feedback on any composable. Do NOT use for build lifecycle tasks or dependency auditing. license: Apache-2.0 metadata: author: https://github.com/rnett/gradle-mcp version: "2.2"
⚠️ FUNDAMENTAL ANDROID LIMITATION
IMPORTANT: runComposeUiTest and image capture methods (node.captureToImage()) are NOT supported on Android and CANNOT work.
Why This Cannot Work
The runComposeUiTest function requires a JVM-based test runtime with desktop Compose rendering (via Skiko on JVM/Desktop). Android's ART (Android Runtime) does not support the desktop Compose testing APIs, and image capture via
captureToImage() relies on desktop-specific rendering pipelines that are fundamentally incompatible with Android.
The Solution: Use a JVM Target
For visual verification of Composables, you MUST use a JVM or Desktop target source set. This is not a workaround—it is the only supported method.
Recommended approach:
- Put your Composables in a common source set (
commonMain) that is shared across all targets - Create or use a JVM target (e.g.,
jvmMain,desktopMain) that depends oncommonMain - Run the REPL on the JVM target (
sourceSet: "jvmMain"orsourceSet: "jvmTest")
This is the standard KMP pattern and allows you to verify your UI code without needing an Android device or emulator.
What WILL NOT Work
- ❌ Running the REPL with
sourceSet: "androidMain" - ❌ Running the REPL with
sourceSet: "androidTest" - ❌ Any attempt to use
runComposeUiTeston Android - ❌ Any attempt to use
captureToImage()on Android
What WILL Work
- ✅ Running the REPL with
sourceSet: "jvmMain"orsourceSet: "jvmTest" - ✅ Running the REPL with
sourceSet: "desktopMain"orsourceSet: "desktopTest" - ✅ Using
runComposeUiTestwithcaptureToImage()on JVM/Desktop targets
Authoritative Compose UI Preview & Visual Verification
Visually verifies and renders any @Composable or @Preview directly to high-quality images from the project-aware REPL for instant, authoritative visual feedback.
Constitution
- ALWAYS use
kotlin_replto render Compose components instead of running the full application for visual checks. - ALWAYS provide absolute paths for
projectRoot. - ALWAYS use
node.captureToImage()andresponder.render(bitmap)to return the visual output. - ALWAYS ensure the correct Compose UI testing dependencies are on the classpath, using
additionalDependenciesif necessary. - NEVER assume a UI component renders correctly without visual verification.
- ALWAYS search for existing
@Previewfunctions in the project source code before creating new ones.
Directives
- ALWAYS provide absolute
projectRoot: EnsureprojectRootis an absolute file system path for allkotlin_replcalls. - Ensure dependencies: ALWAYS ensure Compose UI testing dependencies (e.g.,
androidx.compose.ui:ui-test-junit4) are on the classpath. - Note on versions: ALWAYS check your project's version catalog and existing tests for the correct imports for
runComposeUiTest. - Render as image: ALWAYS use
node.captureToImage()andresponder.render(bitmap)to return the visual output. - Kotlin Multiplatform (KMP) Note: The
kotlin_replcurrently only supports JVM-based source sets. ALWAYS select a JVM or Desktop target source set for visual checks. - Use
envSource: SHELLif environment variables are missing: Setenv: { envSource: "SHELL" }(REPL start) orinvocationArguments: { envSource: "SHELL" }(Gradle tasks) if expected env vars (e.g.,JAVA_HOME) are not found.
When to Use
- Rapid UI Prototyping & Iteration: When you need to see the visual result of a Composable change instantly without the latency of a full application launch.
- Authoritative @Preview Verification: When you want to verify the visual correctness of existing
@Previewfunctions. - Complex UI State & Interaction Testing: When you need to capture visual state before and after interactions (like clicks or state changes).
- Multi-Configuration Visual Auditing: When checking how a component renders across different data states or configurations (e.g., different view models or mock data).
Workflows
1. Identifying the Component
- Find the fully qualified name of the
@Composableor@Previewfunction. - Search for existing previews in the source code via
grep_search(pattern="@Preview").
2. Orchestrating the Session
- Start the REPL with the
testsource set (preferred) ormainwithadditionalDependencies. - Use
kotlin_repl(command="start"). - Use
kotlin_repl(command="run")to execute the rendering script.
3. Rendering & Verifying
- Execute a script that uses
runComposeUiTestto render and capture the component. - Inspect the returned image for visual correctness.
Examples
Viewing a simple Composable
import androidx.compose.ui.test.*
import com.example.ui.MyButton
runComposeUiTest {
setContent {
MyButton(text = "Click Me")
}
val node = onRoot()
responder.render(node.captureToImage())
}
// Reasoning: Using kotlin_repl to render a specific component and retrieve its visual representation via the responder API.
Viewing an existing @Preview
import androidx.compose.ui.test.*
import com.example.ui.MyButtonPreview // Top-level preview function
runComposeUiTest {
setContent {
MyButtonPreview()
}
val node = onRoot()
responder.render(node.captureToImage())
}
// Reasoning: Reusing an existing authoritative preview function to verify its visual correctness.
Capturing State Transitions
import androidx.compose.ui.test.*
import com.example.ui.MyCounter
import com.example.viewmodel.MyViewModel
runComposeUiTest {
val viewModel = MyViewModel()
setContent {
MyCounter(viewModel)
}
// Capture state before interaction
responder.render("State before: ${viewModel.count}")
responder.render(onRoot().captureToImage())
// Perform interaction
onNodeWithText("Increment").performClick()
// Capture state after interaction
responder.render("State after: ${viewModel.count}")
responder.render(onRoot().captureToImage())
}
// Reasoning: Capturing visual snapshots before and after an interaction to verify state-dependent UI changes.
Troubleshooting
- No Image Returned: Ensure you are calling
responder.render(bitmap). - ClassNotFoundException: Check if you have the correct imports and that the required testing dependencies are on the classpath.
- Empty Image: If the Composable is empty or has zero size, the image will be empty. Verify your Composable's modifiers.