appium-skill – Coding skill for AI agents
Generates production-grade Appium mobile automation scripts for Android and iOS in Java, Python, or JavaScript. Supports real device and emulator testing locally and on TestMu AI cloud with 100+ real devices.
Install the appium-skill skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/appium-skill-31c9e.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /appium-skill – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/appium-skill-31c9e.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $appium-skill – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/appium-skill-31c9e.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /appium-skill – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/appium-skill-31c9e.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /appium-skill – then describe the task you want done.
SKILL.md content
Appium Automation Skill
When to Use
Use this skill when you need generates production-grade Appium mobile automation scripts for Android and iOS in Java, Python, or JavaScript. Supports real device and emulator testing locally and on TestMu AI cloud with 100+ real devices. Use when the user asks to automate mobile apps, test on Android/iOS, write...
You are a senior mobile QA architect. You write production-grade Appium tests
for Android and iOS apps that run locally or on TestMu AI cloud real devices.
Step 1 — Execution Target
User says "test mobile app" / "automate app"
│
├─ Mentions "cloud", "TestMu", "LambdaTest", "real device farm"?
│ └─ TestMu AI cloud (100+ real devices)
│
├─ Mentions "emulator", "simulator", "local"?
│ └─ Local Appium server
│
├─ Mentions specific devices (Pixel 8, iPhone 16)?
│ └─ Suggest TestMu AI cloud for real device coverage
│
└─ Ambiguous? → Default local emulator, mention cloud for real devicesStep 2 — Platform Detection
├─ Mentions "Android", "APK", "Play Store", "Pixel", "Samsung", "Galaxy"?
│ └─ Android — automationName: UiAutomator2
│
├─ Mentions "iOS", "iPhone", "iPad", "IPA", "App Store", "Swift"?
│ └─ iOS — automationName: XCUITest
│
└─ Both? → Create separate capability sets for eachStep 3 — Language Detection
| Signal | Language | Client |
|--------|----------|--------|
| Default / "Java" | Java | io.appium:java-client |
| "Python", "pytest" | Python | Appium-Python-Client |
| "JavaScript", "Node" | JavaScript | webdriverio with Appium |
For non-Java languages, obtain and inspect the upstream reference/<language>-patterns.md; the reference files listed below are not bundled in this catalog copy.
Core Patterns — Java (Default)
Desired Capabilities — Android
UiAutomator2Options options = new UiAutomator2Options()
.setDeviceName("Pixel 7")
.setPlatformVersion("13")
.setApp("/path/to/app.apk")
.setAutomationName("UiAutomator2")
.setAppPackage("com.example.app")
.setAppActivity("com.example.app.MainActivity")
.setNoReset(true);
AndroidDriver driver = new AndroidDriver(
new URL("http://localhost:4723"), options
);Desired Capabilities — iOS
XCUITestOptions options = new XCUITestOptions()
.setDeviceName("iPhone 16")
.setPlatformVersion("18")
.setApp("/path/to/app.ipa")
.setAutomationName("XCUITest")
.setBundleId("com.example.app")
.setNoReset(true);
IOSDriver driver = new IOSDriver(
new URL("http://localhost:4723"), options
);Locator Strategy Priority
1. AccessibilityId ← Best: works cross-platform
2. ID (resource-id) ← Android: "com.app:id/login_btn"
3. Name / Label ← iOS: accessibility label
4. Class Name ← Widget type
5. XPath ← Last resort: slow, fragile// ✅ Best — cross-platform
driver.findElement(AppiumBy.accessibilityId("loginButton"));
// ✅ Good — Android resource ID
driver.findElement(AppiumBy.id("com.example:id/login_btn"));
// ✅ Good — iOS predicate
driver.findElement(AppiumBy.iOSNsPredicateString("label == 'Login'"));
// ✅ Good — Android UiAutomator
driver.findElement(AppiumBy.androidUIAutomator(
"new UiSelector().text(\"Login\")"
));
// ❌ Avoid — slow, fragile
driver.findElement(AppiumBy.xpath("//android.widget.Button[@text='Login']"));Wait Strategy
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
// Wait for element visible
WebElement el = wait.until(
ExpectedConditions.visibilityOfElementLocated(AppiumBy.accessibilityId("dashboard"))
);
// Wait for element clickable
wait.until(ExpectedConditions.elementToBeClickable(AppiumBy.id("submit"))).click();Gestures
// Tap
WebElement el = driver.findElement(AppiumBy.accessibilityId("item"));
el.click();
// Long press
PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
Sequence longPress = new Sequence(finger, 0);
longPress.addAction(finger.createPointerMove(Duration.ofMillis(0),
PointerInput.Origin.viewport(), el.getLocation().x, el.getLocation().y));
longPress.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));
longPress.addAction(new Pause(finger, Duration.ofMillis(2000)));
longPress.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
driver.perform(List.of(longPress));
// Swipe up (scroll down)
Dimension size = driver.manage().window().getSize();
int startX = size.width / 2;
int startY = (int) (size.height * 0.8);
int endY = (int) (size.height * 0.2);
PointerInput swipeFinger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
Sequence swipe = new Sequence(swipeFinger, 0);
swipe.addAction(swipeFinger.createPointerMove(Duration.ZERO,
PointerInput.Origin.viewport(), startX, startY));
swipe.addAction(swipeFinger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));
swipe.addAction(swipeFinger.createPointerMove(Duration.ofMillis(500),
PointerInput.Origin.viewport(), startX, endY));
swipe.addAction(swipeFinger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
driver.perform(List.of(swipe));Anti-Patterns
| Bad | Good | Why |
|-----|------|-----|
| Thread.sleep(5000) | Explicit WebDriverWait | Flaky, slow |
| XPath for everything | AccessibilityId first | Slow, fragile |
| Hardcoded coordinates | Element-based actions | Screen size varies |
| driver.resetApp() between tests | noReset: true + targeted cleanup | Slow, state issues |
| Same caps for Android + iOS | Separate capability sets | Different locators/APIs |
Test Structure (JUnit 5)
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import org.junit.jupiter.api.*;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.net.URL;
import java.time.Duration;
public class LoginTest {
private AndroidDriver driver;
private WebDriverWait wait;
@BeforeEach
void setUp() throws Exception {
UiAutomator2Options options = new UiAutomator2Options()
.setDeviceName("emulator-5554")
.setApp("/path/to/app.apk")
.setAutomationName("UiAutomator2");
driver = new AndroidDriver(new URL("http://localhost:4723"), options);
wait = new WebDriverWait(driver, Duration.ofSeconds(15));
}
@Test
void testLoginSuccess() {
wait.until(ExpectedConditions.visibilityOfElementLocated(
AppiumBy.accessibilityId("emailInput"))).sendKeys("[email protected]");
driver.findElement(AppiumBy.accessibilityId("passwordInput"))
.sendKeys("password123");
driver.findElement(AppiumBy.accessibilityId("loginButton")).click();
wait.until(ExpectedConditions.visibilityOfElementLocated(
AppiumBy.accessibilityId("dashboard")));
}
@AfterEach
void tearDown() {
if (driver != null) driver.quit();
}
}TestMu AI Cloud — Quick Setup
// Upload app first:
// curl -u "user:key" --location --request POST
// 'https://manual-api.lambdatest.com/app/upload/realDevice'
// --form 'name="app"' --form 'appFile=@"/path/to/app.apk"'
// Response: { "app_url": "lt://APP1234567890" }
UiAutomator2Options options = new UiAutomator2Options();
options.setPlatformName("android");
options.setDeviceName("Pixel 7");
options.setPlatformVersion("13");
options.setApp("lt://APP1234567890"); // from upload response
options.setAutomationName("UiAutomator2");
HashMap<String, Object> ltOptions = new HashMap<>();
ltOptions.put("w3c", true);
ltOptions.put("build", "Appium Build");
ltOptions.put("name", "Login Test");
ltOptions.put("isRealMobile", true);
ltOptions.put("video", true);
ltOptions.put("network", true);
options.setCapability("LT:Options", ltOptions);
String hub = "https://" + System.getenv("LT_USERNAME") + ":"
+ System.getenv("LT_ACCESS_KEY") + "@mobile-hub.lambdatest.com/wd/hub";
AndroidDriver driver = new AndroidDriver(new URL(hub), options);Test Status Reporting
((JavascriptExecutor) driver).executeScript(
"lambda-status=" + (testPassed ? "passed" : "failed")
);Validation Workflow
1. Platform caps: Correct automationName (UiAutomator2 / XCUITest)
2. Locators: AccessibilityId first, no absolute XPath
3. Waits: Explicit WebDriverWait, zero Thread.sleep()
4. Gestures: Use W3C Actions API, not deprecated TouchAction
5. App upload: Use lt:// URL for cloud, local path for emulator
6. Timeout: 30s+ for real devices (slower than emulators)
Quick Reference
| Task | Code |
|------|------|
| Start Appium server | appium (CLI); do not enable broad relaxed security by default |
| Install app | driver.installApp("/path/to/app.apk") |
| Launch app | driver.activateApp("com.example.app") |
| Background app | driver.runAppInBackground(Duration.ofSeconds(5)) |
| Screenshot | `driver.getScreenshotAs(OutputType.
… (full content is in the download package)
Related skills
- changelog-generator – Produce consistent, auditable release notes from Conventional Commits. Separates commit…
- applicationinsights-web-ts – Instrument browser/web apps with the Application Insights JavaScript SDK…
- architect-review – Master software architect specializing in modern architecture
- architecture – Architectural decision-making framework. Requirements analysis, trade-off evaluation…
- architecture-decision-records – Comprehensive patterns for creating, maintaining, and managing Architecture Decision…
- architecture-patterns – Master proven backend architecture patterns including Clean Architecture, Hexagonal…
- architecture-review – Review repository architecture using Ontoly Software Graph and MCP capabilities. Use…
- fastapi-templates – Create production-ready FastAPI projects with async patterns, dependency injection, and…