Appium Test Debug

SkillDev tools

Appium failure triage for flaky tests, locators, waits, sessions, and stability.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Appium Test Debug skill

What this skill tells your AI

The instructions your AI receives, as published by po4yka/ripdpi in .agents/skills/appium-test-debug/SKILL.md and read by ahel’s review.

Systematic troubleshooting for failing or flaky Appium tests in the RIPDPI suite.

Triage Checklist

Work through in order -- stop at the first failure:

  1. Appium server running? -- curl -s http://127.0.0.1:4723/status | jq .value.ready
  2. Device/emulator connected? -- adb devices -l (should show at least one device)
  3. Debug APK installed? -- adb shell pm list packages | grep ripdpi
  4. Route exists in Kotlin? -- Search for the start_route value in Route.kt sealed class
  5. testTag present in the contract? -- check app/src/main/kotlin/com/poyka/ripdpi/ui/testing/RipDpiTestTags.kt and docs/automation/selector-contract.md, then confirm the tag is actually attached in Compose source
  6. Correct preset combination? -- See preset tables in appium-automation-contract skill

Failure Patterns

SymptomCauseFix
NoSuchElementExceptionElement not on screen, wrong tag, or needs scrollVerify tag matches Modifier.testTag() in Compose source. Use scroll_to() if below viewport.
TimeoutException from wait_forScreen didn't load or element not renderedCheck automation contract params -- wrong start_route or data_preset. Increase timeout for slow emulators.
StaleElementReferenceExceptionCompose recomposition invalidated element referenceRe-find the element after any action that triggers recomposition. Don't store element references across interactions.
Session creation failsAppium server down, UiAutomator2 driver missing, or no deviceRun triage checklist steps 1-3. Install driver: appium driver install uiautomator2.
Passes locally, fails in CIAnimation timing, slower emulator, permission stateVerify disable_motion=True in marker. Check CI emulator specs. Increase timeout if needed.
Wrong screen appearsIncorrect start_route or route not handled in contractVerify route exists in Kotlin Route class. Check data_preset matches screen requirements.
Element found but tap has no effectElement overlapped by another, or animation in progressWait for animations to settle. Check if a dialog/overlay is blocking. Use wait_for before tap.

Flakiness Diagnosis

Step-by-step:

  1. Reproduce -- Run the single test 5 times:
    for i in {1..5}; do pytest tests/test_XX.py::test_name -v; done
    
  2. Classify -- Is the failure:
    • Timing (passes with longer timeout)? Increase specific timeout, not global.
    • State (depends on previous test)? Verify reset_state=True in marker.
    • Animation (element moves during interaction)? Verify disable_motion=True.
    • Race condition (element appears then disappears)? Check if Compose recomposes the element.
  3. Check screenshot -- Failure screenshots in appium/screenshots/{test_name}.png show what was actually displayed.
  4. Check element tree -- Add print(driver.page_source) temporarily to dump the XML tree and search for the expected resource-id.
  5. Check Appium logs -- Server logs show the exact command sent and UiAutomator2's response.

Debugging Locators

Verify a tag exists on screen

# In test or debug session:
source = driver.page_source
assert "com.poyka.ripdpi:id/{tag}" in source, f"Tag '{tag}' not in element tree"

Dump element tree via ADB

adb shell uiautomator dump /sdcard/ui.xml
adb pull /sdcard/ui.xml
rg "resource-id" ui.xml  # Search for specific IDs

Match against Compose source

# Find which composable sets the testTag
rg '{tag}|RipDpiTestTags\\.' app/src/main/kotlin/

If the tag is not found, the composable is missing Modifier.testTag("{tag}") -- this is the root cause and must be fixed in the Kotlin source, not the test.

Screenshot Analysis

The conftest.py fixture saves screenshots on failure:

  • Location: appium/screenshots/{test_name}.png
  • Created automatically by launch_app fixture when rep_call.failed is True
  • Check the screenshot to verify: correct screen displayed, element visibility, dialog/overlay blocking

Wait Strategy Fixes

ProblemSolution
Element appears after animationUse wait_for(tag, timeout=10) not find(tag)
Element appears after network callIncrease to wait_for(tag, timeout=15)
Element below viewportUse scroll_to(tag) before interacting
Element disappears after actionUse is_visible(tag, timeout=3) with assert not
Screen takes long to loadOnly increase timeout in conftest.py launch wait (15s), not in individual tests
Element exists in DOM but not renderedUse is_visible() which checks presence, not just DOM

Common Mistakes

MistakeFix
Adding time.sleep() to fix timingUse wait_for() or is_visible() with appropriate timeout
Increasing all timeouts globallyIdentify the specific slow element and adjust only that call
Ignoring reset_state=TrueStale state from previous test causes cascading failures
Catching exceptions to hide failuresLet exceptions propagate; fix the root cause
Re-running flaky test without diagnosisClassify the failure type first (timing/state/animation)

See Also

  • .github/skills/appium-automation-contract/SKILL.md -- Preset values and launch flow
  • .github/skills/appium-test-authoring/SKILL.md -- Conventions for writing tests and page objects
  • .github/skills/android-device-debug/SKILL.md -- ADB commands, logcat, emulator management

Signals

GitHub stars
69
Forks
4
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
appium-test-debug
Source
github.com/po4yka/ripdpi