Mobile Testing Frameworks

Comprehensive mobile testing framework expertise

509 stars

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

$curl -o ~/.claude/skills/mobile-testing/SKILL.md --create-dirs "https://raw.githubusercontent.com/a5c-ai/babysitter/main/library/specializations/mobile-development/skills/mobile-testing/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/mobile-testing/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How Mobile Testing Frameworks Compares

Feature / AgentMobile Testing FrameworksStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/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 support

Related Skills

react-testing-library

509
from a5c-ai/babysitter

React Testing Library patterns, queries, user events, and accessibility testing.

cloud-security-testing

509
from a5c-ai/babysitter

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

509
from a5c-ai/babysitter

Stryker mutation testing for assessing test suite quality and effectiveness

pytest Testing

509
from a5c-ai/babysitter

Expert pytest framework for Python unit, integration, and functional testing

Playwright E2E Testing

509
from a5c-ai/babysitter

Deep integration with Playwright for browser automation and end-to-end testing

Percy Visual Testing

509
from a5c-ai/babysitter

Percy visual testing platform integration for visual regression detection

pact-contract-testing

509
from a5c-ai/babysitter

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

509
from a5c-ai/babysitter

k6 load testing expertise for performance validation and analysis

JMeter Performance Testing

509
from a5c-ai/babysitter

Apache JMeter expertise for enterprise-grade load and performance testing

Jest Testing

509
from a5c-ai/babysitter

Expert Jest testing framework for JavaScript/TypeScript unit and integration testing

Cypress E2E Testing

509
from a5c-ai/babysitter

Expert Cypress testing framework integration for browser-based end-to-end testing

Cucumber BDD Testing

509
from a5c-ai/babysitter

Cucumber/Gherkin BDD testing for behavior-driven development workflows