compose-testing
Skill0 starsChanged 32 days agoMITView on GitHub
Jetpack Compose testing discipline: test-rule choice, synchronization without sleeps, ui-test dependencies, and semantics-based assertions. Use when writing or reviewing Compose UI tests. Core rules have machine checks in checks/.
In this repository11 other files it gives its agents.
- android-testingSkill
- compose-architectureSkill
- compose-migrationSkill
- compose-multiplatformSkill
- compose-performanceSkill
- dependency-injectionSkill
- gradle-build-logicSkill
- kmp-fundamentalsSkill
- material3-themingSkill
- offline-firstSkill
- release-engineeringSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 4 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
After ANY Compose test edit, run the Verification step (bottom of this file).
- Very specific: line 19
MUST NOT block the test thread (Thread.sleep, SystemClock.sleep, delay) to "wait for the UI".
- Very specific: line 45
MUST drive mainClock instead of sleeping through animations:
- Very specific: line 58
MUST NOT gate tests on external blocking (CountDownLatch) where a waitUntil API fits — external blocking does not advance the test clock.
- Very specific: line 63
MUST use createComposeRule() for pure composable content and createAndroidComposeRule<Activity>() when the test needs the Activity.
- Very specific: line 65
MUST NOT pair ActivityScenarioRule (or a manually launched activity) with a ComposeTestRule — the activity is then launched twice, a …
- Distinctive: line 82
MUST declare, in the module holding the UI tests:
- Very specific: line 95
MUST find nodes through semantics: onNodeWithText / onNodeWithTag / onNodeWithContentDescription, and assert visibility with …
- Distinctive: line 118
Run after every Compose test edit (from the project root):
- Distinctive: line 126
All three must pass (exit 0) before declaring the task done.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Compose Testing
Operational rules for a coding agent. RIGHT/WRONG pairs are canonical. After ANY Compose test edit, run the Verification step (bottom of this file).
1. Synchronization — never block, drive the clock
MUST NOT block the test thread (Thread.sleep, SystemClock.sleep,
delay) to "wait for the UI". Compose tests run on a virtual clock:
assertions and actions auto-synchronize on idle. For conditions the clock
cannot see (external data loading, non-Compose measure/draw) use
waitUntil and its helpers; for animations control mainClock.
WRONG:
@Test
fun feedLoads() {
composeRule.setContent { FeedScreen() }
Thread.sleep(2_000) // real time, flaky
composeRule.onNodeWithText("Done").assertIsDisplayed()
}RIGHT:
@Test
fun feedLoads() {
composeRule.setContent { FeedScreen() }
composeRule.waitUntilExactlyOneExists(hasText("Done"), timeoutMillis = 5_000)
composeRule.onNodeWithText("Done").assertIsDisplayed()
}MUST drive mainClock instead of sleeping through animations:
WRONG:
Thread.sleep(1_000) // let the animation finishRIGHT:
composeRule.mainClock.autoAdvance = false
composeRule.mainClock.advanceTimeBy(1_000)MUST NOT gate tests on external blocking (CountDownLatch) where a
waitUntil API fits — external blocking does not advance the test clock.
2. Test rule choice
MUST use createComposeRule() for pure composable content and
createAndroidComposeRule<Activity>() when the test needs the Activity.
MUST NOT pair ActivityScenarioRule (or a manually launched activity) with
a ComposeTestRule — the activity is then launched twice, a classic
source of flakiness.
WRONG:
@get:Rule val composeRule = createComposeRule()
@get:Rule val activityRule = ActivityScenarioRule(MainActivity::class.java)RIGHT:
@get:Rule val composeRule = createAndroidComposeRule<MainActivity>()3. Test dependencies
MUST declare, in the module holding the UI tests:
androidTestImplementation("androidx.compose.ui:ui-test-junit4:...")
debugImplementation("androidx.compose.ui:ui-test-manifest:...")ui-test-junit4 provides the rules; ui-test-manifest registers the
empty activity createComposeRule() needs (not required for
createAndroidComposeRule<YourActivity>()).
4. Semantics-based assertions
MUST find nodes through semantics: onNodeWithText / onNodeWithTag /
onNodeWithContentDescription, and assert visibility with
assertIsDisplayed() — existence is not visibility. Add testTag or
semantics { contentDescription = ... } only when no natural matcher
exists; keep tags in a shared constants object.
WRONG:
composeRule.onNodeWithText("Submit").assertExists() // exists ≠ visible
composeRule.onNodeWithTag("btn_1") // ad-hoc tag literalRIGHT:
composeRule.onNodeWithText("Submit").assertIsDisplayed()
composeRule.onNodeWithTag(TestTags.Submit) // shared constantsThis section is review-verified (no deterministic check): the checks cannot see which matcher fits your UI.
Verification
Run after every Compose test edit (from the project root):
bash <skill-dir>/checks/check_no_sleep_in_compose_tests.sh <src-dir>
bash <skill-dir>/checks/check_no_activity_scenario_rule.sh <src-dir>
bash <skill-dir>/checks/check_ui_test_dependencies.sh <project-or-src-dir>All three must pass (exit 0) before declaring the task done. Checks are deterministic import/call-site heuristics — they catch the documented anti-patterns above, not every testing bug. Assertion quality (§4) is verified by review against references/testing.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

