Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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...
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 164% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 159% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 145% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 132% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 150% | 0% |
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.
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├─ 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| 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
javaUiAutomator2Options 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 );
javaXCUITestOptions 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 );
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, fragilejava// ✅ 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']"));
javaWebDriverWait 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();
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));
| 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 |
javaimport 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("user@test.com"); 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(); } }
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);
java((JavascriptExecutor) driver).executeScript( "lambda-status=" + (testPassed ? "passed" : "failed") );
lt:// URL for cloud, local path for emulator| 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() |
| 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 |
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 |
Other measured skills in the registry, with their headline benchmark lift.