一键导入
add-ui-tests
Identify and fill UI test gaps for changed screens by analyzing the branch diff. Creates UiTest, UiRobot, and StateRobot following the Robot pattern.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Identify and fill UI test gaps for changed screens by analyzing the branch diff. Creates UiTest, UiRobot, and StateRobot following the Robot pattern.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Convert acceptance criteria, Jira tickets, Gherkin scenarios, PRDs, or any product requirements into a structured spec template. Use when translating PM artifacts into actionable specs for add-*, update, migrate, or remove skills.
Scaffold a complete new feature module with all 6 submodules, source files, tests, fakes, and AGENTS.md. Use when adding an entirely new feature to the app.
Execute cross-cutting migrations — library swaps, pattern changes, API version upgrades, or architecture refactors. Handles phased rollout, coexistence, and rollback planning.
Reverse-engineer a spec from existing code — reconstructs presumed acceptance criteria, data flow, API contracts, UI states, and business rules by reading source, tests, and git history. Use when inheriting undocumented features, onboarding onto unfamiliar code, or preparing for a refactor.
Modify existing feature code across all affected layers — domain models, data, presentation, tests, and fakes. Use when changing behavior, adding fields, or enhancing existing features.
Verification pipeline with three scopes — diff (default, changed modules only), full (whole project lint + unit + arch + builds), and all (every test level + every variant + full assemble). Use after any code change.
基于 SOC 职业分类
| name | add-ui-tests |
| description | Identify and fill UI test gaps for changed screens by analyzing the branch diff. Creates UiTest, UiRobot, and StateRobot following the Robot pattern. |
Identify changed/new Compose UI screens and create the full Robot pattern test suite.
.agents/standards/testing-ui-component.md.agents/standards/testing.mdThis skill covers Compose UI tests (Robot pattern) in features/{name}/impl/presentation/src/androidDeviceTest/. These tests render individual UI screens in isolation with a static UiState.
This skill does NOT cover navigation and integration tests in testing/navint-tests/. Those tests exercise full navigation flows and Circuit presenter wiring across screens, use JUnit4 @RunWith(AndroidJUnit4::class), and live in testing/navint-tests/src/androidDeviceTest/kotlin/. Use add-tests (step 4) to evaluate navint-tests coverage when presentation or navigation modules change.
This skill also does NOT cover iOS navigation/integration tests in iosApp/iosAppTests/NavInt/. Those tests exercise NavigationStateManager state transitions, tab switching, deep links, and auth flows using Swift Testing. They are separate from iOS UI tests (which live in iosApp/iosAppTests/{Feature}/ and use ViewInspector). Use add-tests (step 4) to evaluate iOS navint-tests coverage when iosApp/iosApp/Circuit/ changes.
git diff origin/main...HEAD --name-only -- '**/androidMain/**/*Ui.kt'
For each changed {Feature}Ui.kt, verify these files exist in impl/presentation/src/androidDeviceTest/:
{Feature}UiTest.kt{Feature}UiRobot.kt{Feature}StateRobot.ktAlso verify {Feature}TestTags.kt exists in api/navigation/.
Reference: features/order/impl/presentation/src/androidDeviceTest/.../OrderStateRobot.kt
package com.mockdonalds.app.features.{name}.presentation
import com.mockdonalds.app.core.test.StateRobot
class {Feature}StateRobot : StateRobot<{Feature}UiState, {Feature}Event>() {
override fun defaultState() = {Feature}UiState(
// populate with representative test data
eventSink = createEventSink(),
)
// Add variant states as needed:
// fun stateWithError() = defaultState().copy(error = "...", eventSink = createEventSink())
}
Key: every state variant must call createEventSink() for a fresh event sink — do NOT reuse eventSink from defaultState().
Reference: features/order/impl/presentation/src/androidDeviceTest/.../OrderUiRobot.kt
package com.mockdonalds.app.features.{name}.presentation
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import com.mockdonalds.app.core.theme.LocalWindowSizeClass
import com.mockdonalds.app.core.theme.MockDonaldsTheme
import com.mockdonalds.app.features.{name}.api.ui.{Feature}TestTags
class {Feature}UiRobot(private val rule: ComposeContentTestRule) {
private val stateRobot = {Feature}StateRobot()
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
private fun setContentWith(state: {Feature}UiState, landscape: Boolean = false) {
val size = if (landscape) DpSize(800.dp, 400.dp) else DpSize(400.dp, 800.dp)
rule.setContent {
CompositionLocalProvider(
LocalWindowSizeClass provides WindowSizeClass.calculateFromSize(size),
) {
MockDonaldsTheme { {Feature}Ui(state = state) }
}
}
}
fun setDefaultContent() = setContentWith(stateRobot.defaultState())
fun setLandscapeContent() = setContentWith(stateRobot.defaultState(), landscape = true)
fun assertDefaultScreen() {
// Assert key elements are displayed using TestTags
}
fun assertLandscapeScreen() {
// Assert landscape-specific layout
}
fun assertLastEvent(expected: {Feature}Event) {
org.junit.Assert.assertEquals(expected, stateRobot.lastEvent)
}
}
Reference: features/order/impl/presentation/src/androidDeviceTest/.../OrderUiTest.kt
package com.mockdonalds.app.features.{name}.presentation
import androidx.compose.ui.test.junit4.createComposeRule
import io.kotest.core.spec.style.BehaviorSpec
class {Feature}UiTest : BehaviorSpec({
val rule = createComposeRule()
Given("the {name} screen") {
val robot = {Feature}UiRobot(rule)
Then("it should render the default screen correctly") {
robot.setDefaultContent()
robot.assertDefaultScreen()
}
Then("it should render the landscape layout correctly") {
robot.setLandscapeContent()
robot.assertLandscapeScreen()
}
}
})
Location: features/{name}/api/navigation/src/commonMain/.../api/ui/{Feature}TestTags.kt
package com.mockdonalds.app.features.{name}.api.ui
object {Feature}TestTags {
const val SCREEN = "{name}_screen"
// Add semantic tags for testable UI elements
}
Location: features/{name}/impl/presentation/src/androidDeviceTest/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest>
<application>
<activity
android:name="androidx.activity.ComponentActivity"
android:exported="false" />
</application>
</manifest>
Work is NEVER complete until verification passes. Run the verify skill to validate all changes. It will:
If ANY check fails, fix the issue and re-run. Do not declare the task complete until verification passes.