with one click
mobile-testing-frameworks
Comprehensive mobile testing framework expertise
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Comprehensive mobile testing framework expertise
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
| name | Mobile Testing Frameworks |
| description | Comprehensive mobile testing framework expertise |
| version | 1.0.0 |
| category | Quality Assurance |
| slug | mobile-testing |
| status | active |
| graph | {"domains":["domain:mobile"],"specializations":["specialization:mobile-development"],"skillAreas":["skill-area:mobile-ui-automation","skill-area:cross-platform-testing"],"roles":["role:mobile-engineer"],"workflows":["workflow:feature-development","workflow:release-management"],"topics":["topic:accessibility"]} |
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.
bash - Execute test commands and framework CLIsread - Analyze test files and configurationswrite - Generate test cases and configurationsedit - Update existing testsglob - Search for test filesgrep - Search for patterns in test codeConfiguration
Test Writing
Advanced Features
Flow Configuration
Actions and Assertions
Test Setup
UI Testing
Test Configuration
UI Testing
This skill integrates with the following processes:
mobile-testing-strategy.js - Testing strategy implementationmobile-accessibility-implementation.js - Accessibility testingmobile-security-implementation.js - Security testing// .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',
},
},
};
// 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();
});
});
# 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"
// 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)
}
}
// 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()
}
}
# .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
accessibility-testing - Accessibility-focused testingmobile-perf - Performance testingfastlane-cicd - CI/CD integrationReference for querying the Atlas knowledge graph through its MCP tools — the SECONDARY enrichment/comparison layer that adds best-practice context to systems you have ALREADY scanned from your real sources (`az`, repos, dirs). Use when you need to look up nodes, edges, kinds, clusters, stats, or wiki pages in Atlas to compare against your real inventory. (atlas graph, query atlas, atlas mcp, search the graph, graph neighbors, atlas record, atlas kinds, enrichment layer)
Atlas turns your STATED NEED into a real systems atlas by SCANNING your actual sources (Azure via `az`, git repos, local dirs) and process/data mining them, THEN enriching against the Atlas knowledge graph. Use this skill when asked to inventory/map your real systems, scan your cloud + repos + directories, mine the real processes or data they contain, or collect their real constraints/gotchas. (atlas, scan my systems, inventory our azure account, map my repos, real systems atlas, process mining, data mining, collect nuances, system discovery)
This skill should be used when the user asks to "find skills in the wild", "assimilate popular workflows", "discover SKILL.md files in repos", "research external skills", "find workflow patterns", "survey the skill landscape", "what skills exist out there", or wants to investigate public repositories for extractable processes, babysitter plugins, and reusable procedural insights. Searches GitHub for SKILL.md files, classifies repos by archetype, and maintains structured research under docs/reference-repos/.
JavaScript and TypeScript documentation generation using JSDoc and TSDoc. Parse source code, generate API documentation, validate coverage, and integrate with TypeDoc for comprehensive developer documentation.
Structured debugging methodology using hypothesis-driven investigation, log analysis, and bisection to isolate and resolve defects.
Zero-knowledge circuit development using Circom and Noir languages. Supports constraint optimization, ZK-friendly cryptographic primitives, proof generation (Groth16, PLONK), and Merkle tree implementations.