Mobile Testing Skill
Reference for manual QA testing of KMP Compose Multiplatform apps using MCP mobile automation tools.
Quick Reference: MCP Tools
| Tool |
Purpose |
When to Use |
list_devices |
Find emulators/devices |
Start of test |
set_device |
Select target device |
Multi-device testing |
launch_app |
Start application |
Begin test session |
screenshot |
Capture screen state |
Visual verification |
get_ui |
Get UI hierarchy |
Element discovery |
tap |
Click on element |
Button clicks, navigation |
swipe |
Scroll/gesture |
Lists, carousels |
input_text |
Type text |
Form fields |
press_key |
Hardware keys |
BACK, HOME, ENTER |
get_logs |
Read device logs |
Error detection |
shell |
Execute commands |
Advanced debugging |
Testing Environments
Android Emulator (Fastest)
Device: emulator-5554
Package: com.your-project.admin
Use: Daily development testing
Setup: Android Studio -> AVD Manager
iOS Simulator (macOS)
Device: iPhone 15 Simulator
Bundle ID: com.your-project.admin
Use: iOS-specific testing
Setup: Xcode -> Simulators
Physical Devices (Final)
Android: USB debugging enabled
iOS: Developer mode enabled
Use: Final validation, performance testing
Desktop (JVM)
Run: ./gradlew :composeApp:run
Platforms: macOS, Windows, Linux
Use: Desktop-specific features
Standard Test Workflow
1. Setup
list_devices(platform: "android") # Find devices
set_device(deviceId: "emulator-5554") # Select device
clear_logs() # Clear log buffer
launch_app(package: "com.your-project.admin")
wait(ms: 2000) # Wait for launch
screenshot() # Verify initial state
2. UI Interaction
get_ui() # Discover elements
tap(text: "Settings") # Navigate
wait(ms: 500)
screenshot() # Verify transition
3. Form Input
tap(text: "Search") # Focus field
input_text(text: "test query") # Type text
press_key(key: "ENTER") # Submit
wait(ms: 1000)
screenshot()
4. Log Verification
get_logs(package: "com.your-project.admin", level: "E")
# Check for: crashes, exceptions, errors
5. State Inspection
get_current_activity() # Verify screen
get_system_info() # Check resources
MCP Tool Details
Device Management
list_devices
list_devices() # All devices
list_devices(platform: "android") # Android only
list_devices(platform: "ios") # iOS only
set_device
set_device(deviceId: "emulator-5554")
set_device(deviceId: "iPhone 15")
get_system_info
get_system_info()
# Returns: battery level, memory usage (Android)
App Control
launch_app
launch_app(package: "com.your-project.admin") # Android
launch_app(package: "com.your-project.admin") # iOS (bundle ID)
stop_app
stop_app(package: "com.your-project.admin") # Force stop
install_app
install_app(path: "/path/to/app.apk") # Android
install_app(path: "/path/to/App.app") # iOS Simulator
get_current_activity
get_current_activity() # Android only
# Returns: current package/activity
UI Interaction
screenshot
screenshot() # Default quality
screenshot(quality: 90) # Higher quality
screenshot(maxWidth: 400, maxHeight: 800) # Smaller size
get_ui
get_ui() # Interactive elements
get_ui(showAll: true) # All elements
# Returns: UI hierarchy with element refs
tap
tap(x: 200, y: 400) # By coordinates
tap(text: "Settings") # By text (Android)
tap(index: 5) # By index (Android)
tap(resourceId: "btn_save") # By ID (Android)
long_press
long_press(x: 200, y: 400) # Default 1000ms
long_press(x: 200, y: 400, duration: 2000) # Custom duration
long_press(text: "Item") # By text (Android)
swipe
swipe(direction: "up") # Scroll down
swipe(direction: "down") # Scroll up
swipe(direction: "left") # Next page
swipe(direction: "right") # Previous page
swipe(x1: 200, y1: 800, x2: 200, y2: 200) # Custom swipe
swipe(x1: 200, y1: 400, x2: 200, y2: 400, duration: 500) # Slow swipe
input_text
input_text(text: "Hello World") # Type into focused field
press_key
press_key(key: "BACK") # Hardware back
press_key(key: "HOME") # Home button
press_key(key: "ENTER") # Enter/Return
press_key(key: "TAB") # Tab key
press_key(key: "DELETE") # Delete/Backspace
press_key(key: "VOLUME_UP") # Volume up
press_key(key: "VOLUME_DOWN") # Volume down
find_element
find_element(text: "Settings") # Android only
find_element(resourceId: "btn_save") # Android only
find_element(className: "Button") # Android only
find_element(clickable: true) # Filter by state
Verification
get_logs
get_logs() # Last 100 lines
get_logs(lines: 200) # More lines
get_logs(package: "com.your-project.admin") # Filter by app
get_logs(level: "E") # Errors only
get_logs(tag: "NetworkClient") # Android: by tag
# Log levels (Android): V, D, I, W, E, F
# Log levels (iOS): debug, info, default, error, fault
clear_logs
clear_logs() # Android only
shell
# Android (ADB shell)
shell(command: "dumpsys activity activities") # Current activities
shell(command: "pm list packages") # Installed packages
shell(command: "svc wifi disable") # Disable WiFi
shell(command: "svc wifi enable") # Enable WiFi
shell(command: "input keyevent 26") # Power button
# iOS (simctl)
shell(command: "status_bar override --time '9:41'")
shell(command: "privacy grant all com.your-project.admin")
Utilities
wait
wait(ms: 1000) # Wait 1 second
wait(ms: 500) # Wait 500ms
open_url
open_url(url: "https://your-project.ru") # Open in browser
Log Error Patterns
Critical Errors (Must Fix)
FATAL EXCEPTION -> App crash
ANR in com.your-project.admin -> App not responding
java.lang.NullPointerException -> Null reference crash
java.lang.OutOfMemoryError -> Memory issue
Process: com.your-project.admin, PID... -> Crash with stack trace
Common Errors (Review)
NetworkError -> API call failed
SocketTimeoutException -> Network timeout
UnknownHostException -> No network/DNS issue
SSLHandshakeException -> Certificate issue
JsonParseException -> Malformed response
Compose/KMP Specific
IllegalStateException: Expected -> State mismatch
Composition failed -> UI rendering error
Recomposition loop -> Infinite recomposition
Navigation error -> Decompose issue
Test Scenarios
Scenario: App Launch
clear_logs()
launch_app(package: "com.your-project.admin")
wait(ms: 3000)
screenshot() -> Verify home screen
get_logs(level: "E") -> No crashes
Scenario: Navigation Flow
get_ui() -> Find navigation elements
tap(text: "Settings") -> Navigate
wait(ms: 500)
get_current_activity() -> Verify screen
screenshot()
press_key(key: "BACK") -> Navigate back
wait(ms: 300)
screenshot() -> Verify return
Scenario: Form Submission
- Navigate to form screen
tap(text: "Name") -> Focus field
input_text(text: "Test User")
tap(text: "Email")
input_text(text: "test@example.com")
tap(text: "Save")
wait(ms: 1000)
screenshot() -> Verify success
get_logs(level: "E") -> No errors
Scenario: List Scrolling
- Navigate to list screen
screenshot() -> Initial state
swipe(direction: "up") -> Scroll down
wait(ms: 300)
screenshot() -> New items
swipe(direction: "up") x3 -> Load more
get_ui() -> Verify items loaded
Scenario: State Preservation
- Navigate to detail screen
screenshot() -> Record state
shell(command: "input keyevent 26") -> Power button (lock)
wait(ms: 1000)
shell(command: "input keyevent 26") -> Unlock
screenshot() -> Verify state preserved
press_key(key: "HOME") -> Background app
wait(ms: 2000)
launch_app(package: "com.your-project.admin") -> Resume
screenshot() -> Verify navigation state
Scenario: Error State
shell(command: "svc wifi disable") -> Disable network
- Trigger network action
wait(ms: 2000)
screenshot() -> Verify error UI
get_logs(level: "E") -> Check error logged
shell(command: "svc wifi enable") -> Enable network
wait(ms: 1000)
- Retry action
screenshot() -> Verify success
Scenario: Deep Link
stop_app(package: "com.your-project.admin")
shell(command: "am start -a android.intent.action.VIEW -d 'your-project://chat/123'")
wait(ms: 2000)
screenshot() -> Verify deep link handled
get_current_activity() -> Verify correct screen
Verification Checklist
UI Verification
Compose-arch Compliance
Log Verification
Performance Verification
Platform-Specific Notes
Android
Package name: com.your-project.admin
Log levels: V (Verbose), D (Debug), I (Info), W (Warning), E (Error), F (Fatal)
Shell: ADB commands available
Emulator: emulator-5554 (default)
iOS
Bundle ID: com.your-project.admin
Log levels: debug, info, default, error, fault
Shell: simctl commands available
Simulator: iPhone 15 (default)
Desktop (JVM)
Run: ./gradlew :composeApp:run
Platforms: macOS, Windows, Linux
Testing: Manual (no MCP tools)
Focus: Keyboard navigation, window resize
WASM
Run: ./gradlew :composeApp:wasmJsBrowserRun
Testing: Use Chrome testing tools
Focus: Browser compatibility
Limitations & Workarounds
| Limitation |
Workaround |
| iOS get_ui limited |
Use screenshot + coordinates |
| find_element Android only |
Use tap(x, y) on iOS |
| clear_logs Android only |
Restart simulator on iOS |
| shell varies by platform |
Use platform-specific commands |
| No network mocking |
Use shell to disable WiFi |
| No rotation via MCP |
Use shell input commands |
ADB Shell Commands (Android)
# Device info
adb shell getprop ro.build.version.sdk # API level
adb shell dumpsys battery # Battery status
adb shell dumpsys meminfo com.your-project.admin # Memory usage
# Screen control
adb shell input keyevent 26 # Power button
adb shell input keyevent 82 # Menu button
adb shell settings put system screen_brightness 200 # Brightness
# Network
adb shell svc wifi disable # WiFi off
adb shell svc wifi enable # WiFi on
adb shell svc data disable # Mobile data off
# App control
adb shell pm clear com.your-project.admin # Clear app data
adb shell am force-stop com.your-project.admin # Force stop
adb shell am start -a android.intent.action.VIEW -d "your-project://path" # Deep link
# Input
adb shell input text "hello" # Type text
adb shell input tap 200 400 # Tap at coords
adb shell input swipe 200 800 200 200 # Swipe gesture
simctl Commands (iOS)
# Device control
xcrun simctl boot "iPhone 15" # Boot simulator
xcrun simctl shutdown "iPhone 15" # Shutdown
xcrun simctl erase "iPhone 15" # Reset simulator
# App control
xcrun simctl install booted /path/to/App.app # Install app
xcrun simctl uninstall booted com.your-project.admin # Uninstall
xcrun simctl launch booted com.your-project.admin # Launch app
xcrun simctl terminate booted com.your-project.admin # Terminate
# Permissions
xcrun simctl privacy booted grant all com.your-project.admin # Grant all
xcrun simctl privacy booted reset all com.your-project.admin # Reset
# Status bar
xcrun simctl status_bar booted override --time "9:41" # Set time
xcrun simctl status_bar booted clear # Reset
# Screenshots/Recording
xcrun simctl io booted screenshot /path/to/screenshot.png
xcrun simctl io booted recordVideo /path/to/video.mp4
Release Checklist
Functionality
Error Handling
State Management
Performance
Security