KMP Test
| This documentation was generated with the assistance of AI. Please report any inaccuracies. |
Run a Kotlin Multiplatform (Android + iOS) project’s tests on each target it actually has — the shared module’s
Android host (JVM) tests, jvmTest, the Android app’s testDebugUnitTest, the Kotlin/Native iOS simulator tests
and the SwiftUI host app’s XCTest bundle — scoped to whatever the caller asked for, and report a compact
per-target summary parsed from JUnit XML (Gradle) and .xcresult (Xcode). This is a report-only skill: it never
fixes failing tests or modifies source/test code.
Purpose
iru-kmp-test discovers the KMP modules, Android app modules and iosApp/ host project at runtime, lists the real
test task names from ./gradlew <module>:tasks --all (instead of assuming one plugin’s naming), and runs the
matching stages. Android/JVM stages run on any host; iOS stages run only on macOS with a full Xcode and an iOS
Simulator runtime and are otherwise reported "unverified", never "passed". Every stage that boots a simulator is
serialized repository-wide behind the shared atomic-mkdir .integration-test.lock directory (owner file, stale
after 60 minutes, released on every exit path). It also detects the "selector matched nothing" cases: Gradle fails
the JVM task with "No tests found for given includes", whereas a Kotlin/Native simulator task exits 0 and writes no
XML, and an unmatched -only-testing: yields zero tests. It is the KMP equivalent of
Android Test and Swift Test.
A ui selector (/iru-kmp-test ui [<scope>], or a ui: yes line) runs the UI tests per the catalog’s UI contract (see Building user interfaces): Compose Multiplatform runComposeUiTest tests on the Android host (Robolectric) and the iOS simulator, ui: native Robolectric Compose tests in androidApp, iosApp ImageRenderer/XCUITest captures, and device flow tests only when an emulator is attached. Step 5a resolves UI_SCREENSHOTS_DIR (default <repo root>/.ui-screenshots, forwarded to the JVM tests and to the simulator through SIMCTL_CHILD_/TEST_RUNNER_ variables), clears it only on a full (unscoped) UI run, forces every Gradle test task to re-run with --rerun (captures are side effects that Gradle’s up-to-date checks and build cache do not track), collects .xcresult attachments and device outputs into the contract’s <kind>/<Id>/<state>--<direction>--<theme>[--<variant>…] layout, validates the names with an embedded parser, and reports the .ui-quality.yml accessibility level with violation counts. KMP captures carry an android/ios platform variant so the same <Id> does not collide.
Plugin
Shipped by the iru-kmp plugin of the ai-catalog marketplace (install with /plugin install iru-kmp@ai-catalog; see Plugins).
Invocation
/iru-kmp-test
/iru-kmp-test <scope>
/iru-kmp-test <scope>
target: android|ios|all
module: <gradle path>
destination: <xcodebuild destination>
lock: held
Inputs
| Argument | Required | Description | Default |
|---|---|---|---|
|
No |
A test class ( |
None — every test task of every in-scope target. |
|
No |
|
|
|
No |
Restrict the run to one Gradle module ( |
All modules |
|
No |
An |
First available iPhone simulator |
|
No |
|
Not set — ordinary tests only. |
|
No |
|
Not held — the skill acquires it for simulator stages. |
Stage-to-task mapping (Step 2):
| Stage | Task (first that exists) |
|---|---|
Android host tests of a KMP module |
|
JVM target |
|
Android app module |
|
Kotlin/Native iOS |
|
Outputs
-
A plain-text summary in the conversation — never a written file.
-
One line per target (Android host, JVM, Android app, iOS simulator,
iosAppXCTest): passed (counts), failed (counts, each failingClass#test, assertion message, first stack line and the XML/.xcresultpath), no matching tests for<pattern>, timed out, not applicable, or unverified (reason). -
An explicit callout when a test fails on one target only, which usually means an
actualimplementation differs. -
The lock is mentioned only when it was anything other than an immediate acquire.
-
For a UI run: the capture directory and whether it was cleared (full run) or kept (scoped run); screenshots per kind and per platform (
android/ios); malformed names; accessibility violations (total + rule ids with counts) and the.ui-quality.ymllevel applied (enforce/report/off/none); device flow tests run or unverified (reason). -
No source or test code is ever modified; raw Gradle/
xcodebuildoutput is never pasted.
Execution flow
Dependencies
Invokes
None — iru-kmp-test is a leaf skill; it only runs ./gradlew, xcodebuild, xcrun, xcodegen and small
inline python3 parsers, and it does not call any other skill in this catalog.
Invoked by
-
KMP Code One Task Group — Step 3.3 (scoped Android/JVM tests,
target: android), Step 3.5 (full Android/JVM suite) and Step 3.7 (iOS stage,target: ios, behind the shared lock) and Step 3.8 (UI stage, with theuiselector), always through theiru-gate-runneragent. -
KMP Generate All Tests — Step 7, to run the full suite once and confirm the generated tests cause no regressions, and Step 5a, with the
uiselector, to run the newly generated UI tests.
Related agents
-
iru-gate-runner— both callers always run this skill from inside aniru-gate-runnersub-agent they spawn, not inline, so the compact summary is all that reaches their context.
Source
SKILL.md on GitHub — the file this page was generated from.