Claude-skill-registry-data manual-e2e-testing
Run manual E2E tests for Flutter/mobile apps using Appium and Dart MCPs. Use when verifying mobile app behavior. Not for screenshot-based testing or non-mobile E2E.
git clone https://github.com/majiayu000/claude-skill-registry-data
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/manual-e2e-testing" ~/.claude/skills/majiayu000-claude-skill-registry-data-manual-e2e-testing && rm -rf "$T"
data/manual-e2e-testing/SKILL.mdManual E2E Testing with Appium & Dart MCP
Appium MCP and Dart MCP testing workflows with hot reload and widget tree analysis.
Core Philosophy: Text-First Testing
Why avoid screenshots?
- Vision LLMs are unreliable for precise UI validation
- Visual changes break tests unnecessarily
- Hard to verify logical state changes
- Text and properties are more reliable
- Element states are programmatically verifiable
Dual MCP Architecture
Appium MCP handles:
- Element discovery and interaction
- UI state verification through programmatic access
- Text content retrieval and validation
- Scrolling and gesture simulation
Dart MCP handles:
- Widget tree introspection and analysis
- Runtime error diagnosis and stack traces
- Hot reload capabilities for faster iteration
- App state inspection and debugging
Combined workflow:
- Connect to Dart Tooling Daemon + Create Appium session
- Widget analysis with
get_widget_tree - Element discovery with Appium
- State validation (both Appium + Dart)
- Error diagnosis with
get_runtime_errors - Hot reload for rapid iteration
Pre-Test Setup
Step 1: Verify Emulator
adb devices
- Ensure device shows as "device" (not "offline" or "unauthorized")
- If no device:
emulator -avd <device_name>
Step 2: Clear App Data
adb shell pm clear com.voicenoteplus.app
Step 3: Connect to Dart Tooling Daemon
- Use
mcp__dart__connect_dart_tooling_daemon
Step 4: Launch Flutter App
- Ensure running:
flutter run
Step 5: Create Appium Session
- Platform:
android - Capabilities: platformVersion, deviceName, automationName
Step 6: Verify App Launch
- Find element by ID:
com.voicenoteplus.app:id/dashboard - Cross-verify with widget tree
Element Discovery
Priority Order:
- Resource IDs (most stable)
- Example:
com.voicenoteplus.app:id/record_button
- Example:
- Accessibility IDs (second most stable)
- Example:
,Record
,SettingsSave
- Example:
- Class names (moderately stable)
- Example:
android.widget.Button
- Example:
- XPath (least stable, last resort)
- Example:
//*[contains(@content-desc, "Record")]
- Example:
Binary test: "Is element stable across app updates?" → Use resource ID or accessibility ID.
Validation Techniques
Text Content Verification
mcp__appium-mcp__appium_get_text elementUUID: [from discovery]
- Verify button text contains expected content
- Check transcription area state
- Verify state changes
Element State Checks
mcp__appium-mcp__appium_get_element_attribute elementUUID: [from discovery] attribute: enabled
- Check
attributeenabled - Check
attributedisplayed
Widget Tree Analysis
mcp__dart__get_widget_tree summaryOnly: false
- Extract complete widget hierarchy
- Verify layout structure
- Analyze widget composition
Runtime Error Analysis
mcp__dart__get_runtime_errors clearRuntimeErrors: true
- Check for runtime exceptions
- Analyze stack traces
- Verify no errors during interactions
Test Procedures
Basic Interaction Test
- Pre-check: Runtime errors
- Widget tree analysis
- Find element by accessibility ID
- Verify initial state
- Tap element
- Wait for state change
- Verify state changed (both Appium + Dart)
Complete Workflow
- Start recording
- Verify recording indicator
- Simulate audio capture
- Monitor runtime state
- Stop recording
- Verify transcription
- Verify toolbar state
Settings Configuration
- Navigate to settings
- Verify API key field
- Input API key
- Verify input
- Save settings
- Verify success message
Binary test: "Does this validate state changes programmatically?" → Use text content and element attributes.
Error Handling
Retry Pattern
- Attempt 1: Try immediately
- If fails: Wait 1 second, retry
- If fails: Wait 2 seconds, retry
- If fails: Wait 4 seconds, retry
- After 3 attempts: Report failure
Fallback Strategy Chain
- Try ID-based discovery
- Try accessibility-based discovery
- Try class-based discovery
- Try XPath as last resort
- Report which strategy succeeded
State Verification
- Before action: Verify element present
- During action: Monitor state changes
- After action: Verify expected state
- If state incorrect: Retry or report failure
Best Practices
Before Testing:
- Verify emulator running
- Clear app data
- Connect Dart Tooling Daemon early
- Launch Flutter app
- Create Appium session
- Check runtime errors
- Get initial widget tree
During Testing:
- Always verify element presence before interaction
- Cross-verify widget state with Dart MCP
- Use text content for validation (not visual)
- Implement retry logic
- Log every step with timestamps
- Verify state changes after each action
- Use accessibility IDs when available
- Use hot reload for rapid iteration
After Testing:
- Delete Appium session
- Check final runtime errors
- Save test execution log
- Document issues found
Common Pitfalls
Don't Use:
- Screenshots for validation
- Hard-coded pixel coordinates
- Visual color/position assertions
- Unstable XPath expressions
- Timing sleeps
Do Use:
- Text content verification
- Element attribute checks
- State-based waiting
- Accessibility IDs
- Page source text search
- Structured logging
Binary test: "Is this validation programmatically checkable?" → If no, redesign the test.
Essential Tools Reference
Appium MCP:
- Locate elementappium_find_element
- Read text contentappium_get_text
- Tap elementappium_click
- Enter textappium_set_value
- Get page sourceappium_get_page_source
- Scroll screenappium_scroll
Dart MCP:
- Get widget hierarchyget_widget_tree
- Retrieve exceptionsget_runtime_errors
- Inspect focused widgetget_selected_widget
- Apply changes without restarthot_reload
- Restart with changeshot_restart
- Retrieve Flutter outputget_app_logs
<critical_constraint> MANDATORY: Use text/content validation, not screenshots MANDATORY: Cross-verify widget state with Dart MCP alongside Appium MANDATORY: Prefer resource/accessibility IDs over XPath for element discovery MANDATORY: Implement retry logic with exponential backoff MANDATORY: Verify element presence before any interaction No exceptions. Text-first validation is reliable; visual validation is not. </critical_constraint>
Genetic Code
This component carries essential Seed System principles for context: fork isolation:
<critical_constraint> MANDATORY: All components MUST be self-contained (zero .claude/rules dependency) MANDATORY: Achieve 80-95% autonomy (0-5 AskUserQuestion rounds per session) MANDATORY: Description MUST use What-When-Not format in third person MANDATORY: No component references another component by name in description MANDATORY: Progressive disclosure - references/ for detailed content MANDATORY: Use XML for control (mission_control, critical_constraint), Markdown for data No exceptions. Portability invariant must be maintained. </critical_constraint>
Delta Standard: Good Component = Expert Knowledge − What Claude Already Knows
Recognition Questions:
- "Would Claude know this without being told?" → Delete (zero delta)
- "Can this work standalone?" → Fix if no (non-self-sufficient)
- "Did I read the actual file, or just see it in grep?" → Verify before claiming
Validation Pattern
Use native tools to validate skill structure:
Glob: Verify skill structure exists
→ Main skill fileGlob: pattern "**/SKILL.md" in skill directory
→ Reference filesGlob: pattern "**/references/*.md"
→ Scripts directoryGlob: pattern "**/scripts/*.sh"
Grep: Verify frontmatter
→ Name fieldGrep: search for "^name: manual-e2e-testing" in SKILL.md
→ Description fieldGrep: search for "^description:" in SKILL.md
→ Frontmatter markersGrep: search for "^---" in SKILL.md
Read: Check file contents
→ Verify structure and contentRead: SKILL.md
→ Verify reference files existRead: references/
Validation workflow:
in skill dir → Confirm main file existsGlob: pattern "**/SKILL.md"
→ Verify references directoryGlob: pattern "**/references/"
→ Verify required fieldsGrep: search for "^name:\|^description:"
→ Check for constraintsGrep: search for "<critical_constraint>"