Appium Mobile Test Automation
Automate iOS and Android testing at scale instantly
❌ Manual mobile app testing across multiple devices and platforms is time-consuming, error-prone, and expensive to scale.
✅ Production-ready Appium automation scripts that run on 100+ real devices in the cloud, reducing test cycles from days to hours.
- ✓Multi-language support: Java, Python, JavaScript, Ruby, C#
- ✓Real device and emulator testing across Android and iOS
- ✓Cloud execution on 100+ devices via TestMu AI platform
- ✓Native driver integration: UiAutomator and XCUITest
- ✓Local and cloud-based test orchestration
👁 2 views · 📦 0 installs
Free to install — no account needed
Copy the command below and paste into your agent.
Instant access • No coding needed • No account needed
What you get in 5 minutes
- Full skill code ready to install
- Works with 7 AI agents
- Lifetime updates included
Run this helper
Answer a few questions and let this helper do the work.
▸Advanced: use with your AI agent
Description
--- name: appium-skill description: > 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 Appium tests, or mentions "Appium", "mobile testing", "real device", "app automation". Triggers on: "Appium", "mobile test", "Android test", "iOS test", "real device", "app automation", "UiAutomator", "XCUITest driver", "TestMu", "LambdaTest". languages: - Java - Python - JavaScript - Ruby - C# category: mobile-testing license: MIT metadata: author: TestMu AI version: "1.0" --- # Appium Automation Skill 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 devices ``` ## Step 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 each ``` ## Step 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 → read `reference/<language>-patterns.md` ## Core Patterns — Java (Default) ### Desired Capabilities — Android ```java 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 ```java 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 ``` ```java // ✅ 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 ```java 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 ```java // 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) ```java 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 ```java // 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 ```java ((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) or `appium --relaxed-security` | | 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.FILE)` | | Device orientation | `driver.rotate(ScreenOrientation.LANDSCAPE)` | | Hide keyboard | `driver.hideKeyboard()` | | Push file (Android) | `driver.pushFile("/sdcard/test.txt", bytes)` | | Context switch | `driver.context("WEBVIEW_com.example")` | | Get contexts | `driver.getContextHandles()` | ## Reference Files | File | When to Read | |------|-------------| | `reference/cloud-integration.md` | App upload, real devices, capabilities | | `reference/python-patterns.md` | Python + pytest-appium | | `reference/javascript-patterns.md` | JS + WebdriverIO-Appium | | `reference/ios-specific.md` | iOS-only patterns, XCUITest driver | | `reference/hybrid-apps.md` | WebView testing, context switching | ## Deep Patterns → `reference/playbook.md` | § | Section | Lines | |---|---------|-------| | 1 | Project Setup & Capabilities | Maven, Android/iOS options | | 2 | BaseTest with Thread-Safe Driver | ThreadLocal, multi-platform | | 3 | Cross-Platform Page Objects | AndroidFindBy/iOSXCUITFindBy | | 4 | Advanced Gestures (W3C Actions) | Swipe, long press, pinch zoom, scroll | | 5 | WebView & Hybrid App Testing | Context switching | | 6 | Device Interactions | Files, notifications, clipboard, geo | | 7 | Parallel Device Execution | Multi-device TestNG XML | | 8 | LambdaTest Real Device Cloud | Cloud grid integration | | 9 | CI/CD Integration | GitHub Actions, emulator runner | | 10 | Debugging Quick-Reference | 12 common problems | | 11 | Best Practices Checklist | 13 items |
Security Status
Verified
Manually verified by security team
Related AI Tools
More Grow Business tools you might like
codex-collab
FreeUse when the user asks to invoke, delegate to, or collaborate with Codex on any task. Also use PROACTIVELY when an independent, non-Claude perspective from Codex would add value — second opinions on code, plans, architecture, or design decisions.
Rails Upgrade Analyzer
FreeAnalyze Rails application upgrade path. Checks current version, finds latest release, fetches upgrade notes and diffs, then performs selective upgrade preserving local customizations.
Asta MCP — Academic Paper Search
FreeDomain expertise for Ai2 Asta MCP tools (Semantic Scholar corpus). Intent-to-tool routing, safe defaults, workflow patterns, and pitfall warnings for academic paper search, citation traversal, and author discovery.
Hand Drawn Diagrams
FreeCreate hand-drawn Excalidraw diagrams, flows, explainers, wireframes, and page mockups. Default to monochrome sketch output; allow restrained color only for page mockups when the user explicitly wants webpage-like fidelity.
Move Code Quality Checker
FreeAnalyzes Move language packages against the official Move Book Code Quality Checklist. Use this skill when reviewing Move code, checking Move 2024 Edition compliance, or analyzing Move packages for best practices. Activates automatically when working
Claude Memory Kit
Free"Persistent memory system for Claude Code. Your agent remembers everything across sessions and projects. Two-layer architecture: hot cache (MEMORY.md) + knowledge wiki. Safety hooks prevent context loss. /close-day captures your day in one command. Z