Best use case
Mobile Testing Frameworks is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Comprehensive mobile testing framework expertise
Teams using Mobile Testing Frameworks should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/mobile-testing/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How Mobile Testing Frameworks Compares
| Feature / Agent | Mobile Testing Frameworks | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Comprehensive mobile testing framework expertise
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Mobile Testing Frameworks Skill
## Overview
This skill provides comprehensive expertise in mobile testing frameworks across platforms. It enables E2E testing with Detox and Maestro, native testing with XCUITest and Espresso, and cross-platform testing with Appium.
## Allowed Tools
- `bash` - Execute test commands and framework CLIs
- `read` - Analyze test files and configurations
- `write` - Generate test cases and configurations
- `edit` - Update existing tests
- `glob` - Search for test files
- `grep` - Search for patterns in test code
## Capabilities
### Detox (React Native)
1. **Configuration**
- Set up Detox configurations
- Configure iOS and Android builds
- Set up device/simulator targets
- Configure test runners (Jest)
2. **Test Writing**
- Write element matchers
- Implement actions (tap, type, scroll)
- Configure expectations
- Handle synchronization
3. **Advanced Features**
- Mock native modules
- Handle permissions
- Configure network mocking
- Implement visual regression
### Maestro
4. **Flow Configuration**
- Write YAML test flows
- Configure app launch
- Set up device targets
- Handle environment variables
5. **Actions and Assertions**
- Tap, type, swipe gestures
- Assert element visibility
- Take screenshots
- Run JavaScript assertions
### XCUITest (iOS)
6. **Test Setup**
- Configure test schemes
- Set up test plans
- Configure device targets
- Handle launch arguments
7. **UI Testing**
- Element queries with XCUIElement
- Actions (tap, swipe, pinch)
- Accessibility identifier usage
- Keyboard handling
### Espresso (Android)
8. **Test Configuration**
- Set up instrumentation tests
- Configure test runner
- Handle Hilt injection
- Configure Compose testing
9. **UI Testing**
- ViewMatchers and ViewActions
- Compose semantics testing
- IdlingResources for async
- Intent verification
### Appium
10. **Cross-Platform Testing**
- Configure capabilities
- Set up driver sessions
- Handle multiple platforms
- Configure cloud testing
### Device Farms
11. **Cloud Testing**
- AWS Device Farm integration
- Firebase Test Lab setup
- BrowserStack configuration
- Test distribution
## Target Processes
This skill integrates with the following processes:
- `mobile-testing-strategy.js` - Testing strategy implementation
- `mobile-accessibility-implementation.js` - Accessibility testing
- `mobile-security-implementation.js` - Security testing
## Dependencies
### Required
- Node.js (for Detox, Maestro)
- Xcode (for XCUITest)
- Android Studio (for Espresso)
- Platform-specific SDKs
### Optional
- Appium
- Device farm accounts
- CI/CD platform
## Configuration
### Detox Configuration
```javascript
// .detoxrc.js
module.exports = {
testRunner: {
args: {
$0: 'jest',
config: 'e2e/jest.config.js',
},
jest: {
setupTimeout: 120000,
},
},
apps: {
'ios.debug': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/MyApp.app',
build: 'xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',
},
'ios.release': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Release-iphonesimulator/MyApp.app',
build: 'xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Release -sdk iphonesimulator -derivedDataPath ios/build',
},
'android.debug': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
build: 'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug',
reversePorts: [8081],
},
'android.release': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/release/app-release.apk',
build: 'cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release',
},
},
devices: {
simulator: {
type: 'ios.simulator',
device: { type: 'iPhone 15 Pro' },
},
emulator: {
type: 'android.emulator',
device: { avdName: 'Pixel_7_API_34' },
},
},
configurations: {
'ios.sim.debug': {
device: 'simulator',
app: 'ios.debug',
},
'ios.sim.release': {
device: 'simulator',
app: 'ios.release',
},
'android.emu.debug': {
device: 'emulator',
app: 'android.debug',
},
'android.emu.release': {
device: 'emulator',
app: 'android.release',
},
},
};
```
## Usage Examples
### Detox Test
```typescript
// e2e/login.test.ts
import { device, element, by, expect } from 'detox';
describe('Login Flow', () => {
beforeAll(async () => {
await device.launchApp({
newInstance: true,
permissions: { notifications: 'YES' },
});
});
beforeEach(async () => {
await device.reloadReactNative();
});
it('should show login screen on first launch', async () => {
await expect(element(by.id('login-screen'))).toBeVisible();
await expect(element(by.id('email-input'))).toBeVisible();
await expect(element(by.id('password-input'))).toBeVisible();
});
it('should show error for invalid credentials', async () => {
await element(by.id('email-input')).typeText('invalid@example.com');
await element(by.id('password-input')).typeText('wrongpassword');
await element(by.id('login-button')).tap();
await expect(element(by.id('error-message'))).toBeVisible();
await expect(element(by.text('Invalid credentials'))).toBeVisible();
});
it('should navigate to home on successful login', async () => {
await element(by.id('email-input')).typeText('test@example.com');
await element(by.id('password-input')).typeText('password123');
await element(by.id('login-button')).tap();
await waitFor(element(by.id('home-screen')))
.toBeVisible()
.withTimeout(5000);
await expect(element(by.id('welcome-message'))).toBeVisible();
});
it('should handle scroll in long list', async () => {
// Login first
await element(by.id('email-input')).typeText('test@example.com');
await element(by.id('password-input')).typeText('password123');
await element(by.id('login-button')).tap();
await waitFor(element(by.id('home-screen'))).toBeVisible().withTimeout(5000);
// Scroll to bottom of list
await element(by.id('item-list')).scrollTo('bottom');
await expect(element(by.id('item-50'))).toBeVisible();
// Scroll back to top
await element(by.id('item-list')).scrollTo('top');
await expect(element(by.id('item-1'))).toBeVisible();
});
});
```
### Maestro Flow
```yaml
# flows/login.yaml
appId: com.example.myapp
---
- launchApp:
clearState: true
- assertVisible: "Welcome"
- tapOn: "Email"
- inputText: "test@example.com"
- tapOn: "Password"
- inputText: "password123"
- tapOn: "Sign In"
- assertVisible: "Home"
- takeScreenshot: "home_after_login"
# Test logout flow
- tapOn: "Profile"
- tapOn: "Sign Out"
- assertVisible: "Welcome"
```
### XCUITest
```swift
// MyAppUITests/LoginTests.swift
import XCTest
final class LoginTests: XCTestCase {
var app: XCUIApplication!
override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication()
app.launchArguments = ["--uitesting"]
app.launch()
}
override func tearDownWithError() throws {
app = nil
}
func testLoginScreenElements() throws {
XCTAssertTrue(app.textFields["email-input"].exists)
XCTAssertTrue(app.secureTextFields["password-input"].exists)
XCTAssertTrue(app.buttons["login-button"].exists)
}
func testSuccessfulLogin() throws {
let emailField = app.textFields["email-input"]
let passwordField = app.secureTextFields["password-input"]
let loginButton = app.buttons["login-button"]
emailField.tap()
emailField.typeText("test@example.com")
passwordField.tap()
passwordField.typeText("password123")
loginButton.tap()
// Wait for home screen
let homeScreen = app.otherElements["home-screen"]
XCTAssertTrue(homeScreen.waitForExistence(timeout: 5))
}
func testInvalidCredentials() throws {
app.textFields["email-input"].tap()
app.textFields["email-input"].typeText("invalid@example.com")
app.secureTextFields["password-input"].tap()
app.secureTextFields["password-input"].typeText("wrong")
app.buttons["login-button"].tap()
XCTAssertTrue(app.staticTexts["Invalid credentials"].waitForExistence(timeout: 3))
}
func testScrollBehavior() throws {
// Navigate to list screen
app.buttons["list-tab"].tap()
let list = app.tables["item-list"]
let lastItem = app.cells["item-cell-50"]
// Scroll down
while !lastItem.isHittable {
list.swipeUp()
}
XCTAssertTrue(lastItem.exists)
// Scroll back up
let firstItem = app.cells["item-cell-1"]
while !firstItem.isHittable {
list.swipeDown()
}
XCTAssertTrue(firstItem.exists)
}
}
```
### Espresso Test
```kotlin
// app/src/androidTest/java/com/example/myapp/LoginTest.kt
package com.example.myapp
import androidx.compose.ui.test.*
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
class LoginTest {
@get:Rule(order = 0)
val hiltRule = HiltAndroidRule(this)
@get:Rule(order = 1)
val composeRule = createAndroidComposeRule<MainActivity>()
@Before
fun setup() {
hiltRule.inject()
}
@Test
fun loginScreen_displaysAllElements() {
composeRule.onNodeWithTag("email-input").assertIsDisplayed()
composeRule.onNodeWithTag("password-input").assertIsDisplayed()
composeRule.onNodeWithTag("login-button").assertIsDisplayed()
}
@Test
fun login_withValidCredentials_navigatesToHome() {
composeRule.onNodeWithTag("email-input")
.performTextInput("test@example.com")
composeRule.onNodeWithTag("password-input")
.performTextInput("password123")
composeRule.onNodeWithTag("login-button")
.performClick()
composeRule.waitUntil(5000) {
composeRule.onAllNodesWithTag("home-screen")
.fetchSemanticsNodes().isNotEmpty()
}
composeRule.onNodeWithTag("home-screen").assertIsDisplayed()
}
@Test
fun login_withInvalidCredentials_showsError() {
composeRule.onNodeWithTag("email-input")
.performTextInput("invalid@example.com")
composeRule.onNodeWithTag("password-input")
.performTextInput("wrong")
composeRule.onNodeWithTag("login-button")
.performClick()
composeRule.onNodeWithText("Invalid credentials")
.assertIsDisplayed()
}
@Test
fun list_scrollsBehavior() {
// Login first
composeRule.onNodeWithTag("email-input")
.performTextInput("test@example.com")
composeRule.onNodeWithTag("password-input")
.performTextInput("password123")
composeRule.onNodeWithTag("login-button")
.performClick()
composeRule.waitUntil(5000) {
composeRule.onAllNodesWithTag("item-list")
.fetchSemanticsNodes().isNotEmpty()
}
// Scroll to item 50
composeRule.onNodeWithTag("item-list")
.performScrollToNode(hasTestTag("item-50"))
composeRule.onNodeWithTag("item-50").assertIsDisplayed()
}
}
```
### Firebase Test Lab
```yaml
# .github/workflows/android-test.yml
name: Android Tests
on: [push, pull_request]
jobs:
instrumented-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build APKs
run: |
./gradlew assembleDebug assembleDebugAndroidTest
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}
- name: Run tests on Firebase Test Lab
run: |
gcloud firebase test android run \
--type instrumentation \
--app app/build/outputs/apk/debug/app-debug.apk \
--test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
--device model=Pixel6,version=33 \
--device model=Pixel7,version=34 \
--timeout 15m \
--results-bucket gs://my-test-results
```
## Quality Gates
### Test Coverage
- Unit test coverage > 80%
- Integration test coverage > 60%
- E2E critical path coverage 100%
### Test Reliability
- Flaky test rate < 2%
- Test execution time < 15 minutes
- Retry logic for network tests
### Accessibility Testing
- VoiceOver/TalkBack verification
- Color contrast validation
- Touch target size verification
## Related Skills
- `accessibility-testing` - Accessibility-focused testing
- `mobile-perf` - Performance testing
- `fastlane-cicd` - CI/CD integration
## Version History
- 1.0.0 - Initial release with major framework supportRelated Skills
react-testing-library
React Testing Library patterns, queries, user events, and accessibility testing.
cloud-security-testing
Multi-cloud security assessment and penetration testing capabilities. Execute Prowler/ScoutSuite assessments, analyze IAM policies, identify cloud misconfigurations, test permissions, and enumerate cloud resources across AWS/GCP/Azure.
Stryker Mutation Testing
Stryker mutation testing for assessing test suite quality and effectiveness
pytest Testing
Expert pytest framework for Python unit, integration, and functional testing
Playwright E2E Testing
Deep integration with Playwright for browser automation and end-to-end testing
Percy Visual Testing
Percy visual testing platform integration for visual regression detection
pact-contract-testing
Consumer-driven contract testing with Pact framework. Generate consumer contracts, configure Pact Broker publishing, execute provider verification, detect breaking changes, and integrate with CI/CD pipelines.
k6 Performance Testing
k6 load testing expertise for performance validation and analysis
JMeter Performance Testing
Apache JMeter expertise for enterprise-grade load and performance testing
Jest Testing
Expert Jest testing framework for JavaScript/TypeScript unit and integration testing
Cypress E2E Testing
Expert Cypress testing framework integration for browser-based end-to-end testing
Cucumber BDD Testing
Cucumber/Gherkin BDD testing for behavior-driven development workflows