Skills Plugins MCP Prompt Model 博客 我的中心
开发编程 #react #mcp #cloud #testing

maestro-mobile-testing

Maestro mobile E2E testing patterns for React Native/Expo apps: YAML test flows, testID selectors, adaptive auth state, optimistic update verification, GraalJS scripting, cross-platform stability, CI/CD integration, Maestro Cloud, and MCP server integration

DeepseekModel 官方收录技能 质量 优秀 · 90 v1.0.0

获取

https://deepseekmodel.com/api/download.php?id=bagisto-opensource-ecommerce-mobile-app-agents-skills-maestro-mobile-testing-skill-md&format=skill
下载 .skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用
.skill 文件中 system_prompt 字段的实际内容。
name maestro-mobile-testing description Maestro mobile E2E testing patterns for React Native/Expo apps: YAML test flows, testID selectors, adaptive auth state, optimistic update verification, GraalJS scripting, cross-platform stability, CI/CD integration, Maestro Cloud, and MCP server integration version 1.1.0 category toolchain author tovimx license MIT progressive_disclosure {"entry_point":{"summary":"Write reliable Maestro mobile E2E tests with declarative YAML flows, testID selectors, auth-aware adaptive patterns, and optimistic update verification","when_to_use":"When writing mobile E2E tests, debugging flaky flows, testing authentication, verifying optimistic updates, capturing screenshots, or setting up Maestro CI for React Native/Expo apps","quick_start":"1. Install Maestro CLI 2. Add testID props to components 3. Write YAML flows with testID selectors 4. Use auth-loaded pre-flight pattern 5. Start mock API server for backend-dependent tests 6. Run with maestro test"},"token_estimate":{"entry":150,"full":9000}} context_limit 900 tags ["react-native","expo","testing","maestro","e2e","mobile","ios","android","yaml","ci-cd","mcp"] requires_tools [] Maestro Mobile E2E Testing Overview Maestro is a declarative YAML-based mobile E2E testing framework. It provides automatic waiting, built-in retry logic, and fast execution without boilerplate. It's more stable than Detox or Appium for React Native apps. Key Features Declarative YAML — no imperative test code, just steps Automatic waiting — no manual sleep() or flaky waits Built-in retry — reduces test flakiness Fast execution — runs quickly without setup overhead Maestro Studio — interactive test builder ( maestro studio ) Sub-flows — reusable YAML sequences for DRY tests JavaScript scripting — GraalJS runtime for HTTP calls and data manipulation Maestro Cloud — real device testing in CI without local simulators Quick Start Install curl -Ls "https://get.maestro.mobile.dev" | bash brew install openjdk@17 export JAVA_HOME=/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home Minimal test appId: com.myapp --- - launchApp - tapOn: id: "my-button" - assertVisible: "Expected Text" Run maestro test .maestro/smoke-test.yaml maestro test --debug .maestro/smoke-test.yaml # step through maestro studio # interactive builder Core Patterns 1. Selector Strategy: testID vs Text Choose your selector approach based on project context. Both are valid — the right choice depends on whether your app is localized and your team's testing philosophy. Context Recommended Selector Rationale Multi-language / i18n id: (testID) Stable across translations Single language Text labels Human-readable, self-documenting tests Agent-maintained tests Either — ask the developer Readability matters less for AI-maintained flows System dialogs Text (always) No testID possible on native alerts # testID selector — stable across translations - tapOn: id: "submit-button" # Text selector — human-readable, self-documenting - tapOn: "Submit" When to prefer testIDs: App supports multiple languages or will be translated UI text is dynamic or frequently changes Multiple elements share the same visible text When to prefer text selectors: Single-language app with stable copy Readability and self-documentation are a priority Testing user-visible behavior exactly as it appears In React Native, add testID props when using ID-based selectors: < TouchableOpacity testID= "submit-button" onPress={handleSubmit}> < Text > {t('submit')} </ Text > </ TouchableOpacity > testID Naming Convention When using ID-based selectors: {component}-{action/type}[-{variant}] Examples: - auth-prompt-login-button - product-card-{id} - otp-input-0 - tab-home - dashboard-loading 2. Auth Pre-Flight Pattern Prevent race conditions where Maestro interacts with the UI before auth state resolves. Add a zero-size auth-loaded marker that only renders when auth loading completes: // In your tab bar or root layout {!isLoading && < View testID = "auth-loaded" style = {{ width: 0 , height: 0 }} /> } Then in every test: - launchApp # Prevent XCTest crash on cold boot (iOS) - swipe: direction: DOWN duration: 100 # Wait for auth state to resolve - extendedWaitUntil: visible: id: "auth-loaded" timeout: 15000 # Now safe to interact - tapOn: id: "tab-home" 3. Adaptive Tests (Handle Both Auth States) Tests should work regardless of whether the user is authenticated: # Auth flow — only runs if login prompt is visible - runFlow: when: visible: "Sign In" file: flows/auth-flow.yaml # Already authenticated — proceed directly - runFlow: when: visible: id: "tab-home" file: flows/authenticated-action.yaml 4. Testing Optimistic Updates Use short timeouts to verify UI changes happen before server response: # Trigger mutation - tapOn: id: "action-button" # OPTIMISTIC: UI must change within 3s (not waiting for server) - extendedWaitUntil: visible: id: "undo-button" timeout: 3000 # Verify derived UI state - extendedWaitUntil: visible: id: "user-indicator" timeout: 5000 Action Expected Change Timeout Mutation trigger Button state flips < 3s List update Item appears/disappears < 5s Re-do action Proves persistence < 3s 5. Dismissing Native Alerts React Native Alert.alert() creates native dialogs that block the UI: - tapOn: id: "action-button" # Wait for expected state change first - extendedWaitUntil: visible: id: "new-state-element" timeout: 5000 # Dismiss alert (optional in case it already closed) - tapOn: text: "OK" optional: true # Brief delay for alert animation - swipe: direction: DOWN duration: 300 6. Sub-Flows for Reusability Break repeated sequences into sub-flow files: .maestro/ ├── flows/ │ ├── auth-and-return.yaml │ ├── complete-purchase.yaml │ └── verify-result.yaml ├── smoke-test.yaml └── feature-test.yaml # In main test - runFlow: file: flows/auth-and-return.yaml 7. Deep Links (Expo) Use the Expo scheme from app.json , not the bundle ID: # WRONG - openLink: "com.myapp://profile/settings" # CORRECT - openLink: "myapp://profile/settings" Deep links must be registered in your app's deep link handler. Unregistered routes silently fail. 8. Platform-Specific Logic - runFlow: when: platform: ios file: flows/ios-specific.yaml - runFlow: when: platform: android file: flows/android-specific.yaml 9. Environment Variables appId: com.myapp env: TEST_EMAIL: maestro-test@example.com API_BASE_URL: http://localhost:3000 --- - inputText: ${TEST_EMAIL} 10. Selector State Properties Use enabled , selected , checked , and focused to target elements by their current state. This is useful for validating interactive element states before or after actions. # Only tap the submit button if it's enabled - tapOn: id: "submit-button" enabled: true # Assert a checkbox is checked - assertVisible: id: "terms-checkbox" checked: true # Wait for an input to be focused - extendedWaitUntil: visible: id: "email-input" focused: true timeout: 3000 Property Values Use Case enabled true / false Buttons that disable during submission or until form is valid checked true / false Checkboxes, toggle switches selected true / false Tab items, segmented controls focused true / false Input fields with auto-focus 11. Relative Position Selectors Distinguish between similar elements by their spatial relationship to other elements. This is more idiomatic and resilient than index-based selection. # BAD — fragile, breaks if order changes - tapOn: text: "Add to Basket" index: 1 # GOOD — contextual, self-documenting - tapOn: text: "Add to Basket" below: text: "Awesome Shoes" Available relative selectors: # Target element below another - tapOn: text: "Buy Now" below: "Product Title" # Target element that is a child of a parent - tapOn: text: "Delete" childOf: id: "item-card-42" # Target a parent that contains a specific child - tapOn: containsChild: "Urgent" # Target by multiple descendants - tapOn: containsDescendants: - id: title_id text: "Specific Title" - "Another descendant text" # Horizontal positioning - tapOn: text: "Edit" rightOf: "Username" Selector Meaning below: Element is positioned below the referenced element above: Element is positioned above the referenced element leftOf: Element is to the left of the referenced element rightOf: Element is to the right of the referenced element childOf: Element is a direct child of the referenced parent containsChild: Element contains a direct child matching the reference containsDescendants: Element contains all specified descendant elements Authentication Testing Architecture Testing OTP or magic-link authentication in E2E requires capturing emails programmatically. The general pattern: ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │ Maestro │────▶│ Auth │────▶│ Email Capture │ │ Test │ │ Provider │ │ Service │ └─────────────┘ └──────────────┘ └─────────────────┘ │ │ │ ┌──────────────────────────────┘ │ ▼ │ ┌─────────────┐ └──▶│ REST API │ ─── GET /api/v1/messages │ (email) │ ─── Extract OTP code └─────────────┘ Common email capture services: Mailpit , MailHog , Ethereal . OTP Fetch Script Fetch OTP codes from your email capture service using Maestro's GraalJS runtime: // CRITICAL: Maestro uses GraalJS — NO async/await, NO fetch() var email = typeof EMAIL !== "undefined" ? EMAIL : "test@example.com" ; var emailServiceUrl = typeof EMAIL_SERVICE_URL !== "undefined" ? EMAIL_SERVICE_URL : "http://localhost:8025" ; var response = http. get (emailServiceUrl + "/api/v1/messages" ); if (!response. ok ) { throw new Error ( "Failed to fetch emails: " + response. status ); } var data = json (response. body ); // Find the latest email and extract OTP code var body = data. messages [ 0 ]. Content . Body ; var match = body. match ( /(\d{6})/ ); output. OTP_CODE = match[ 1 ]; OTP Input Strategy OTP components with auto-focus need individual digit entry. Tap each input before typing: # Split OTP into digits via helper script - runScript: file: scripts/split-otp.js env: OTP_CODE: ${output.OTP_CODE} # Enter each digit by tapping its input - tapOn: id: "otp-input-0" - inputText: ${output.OTP_0} - tapOn: id: "otp-input-1" - inputText: ${output.OTP_1} # ... repeat for all digits For provider-specific implementations (Supabase + Mailpit, Firebase Auth, Auth0), create a project-level skill that extends this one. GraalJS Script Rules Maestro uses the GraalJS runtime. These constraints are non-negotiable: Feature Status async/await NOT supported fetch() NOT supported http.get() , http.post() Use these instead json() Use to parse response bodies output.VAR Set variables for use in YAML flow var declarations Required (use var , not const / let for safety) // Script template var response = http. get ( "http://localhost:8025/api/endpoint" ); if (!response. ok ) { throw new Error ( "Request failed: " + response. status ); } var data = json (response. body ); output. RESULT = data. value ; Critical Gotchas clearState Does NOT Clear iOS Keychain clearState: true clears the app sandbox (UserDefaults, files, caches) but does NOT clear the iOS Keychain. Auth tokens stored via expo-secure-store (or any Keychain-based storage) persist across clearState resets and even app reinstalls. # WRONG — user may still be authenticated - launchApp: clearState: true - assertVisible: "Welcome" # Fails if Keychain has tokens # CORRECT — wait for auth resolution, then adapt - launchApp - extendedWaitUntil: visible: id: "auth-loaded" timeout: 15000 Rules: Never rely on clearState to produce guest state on iOS For auth tests: skip clearState , use auth-loaded pre-flight For guest tests: use adaptive flows that handle both states Never assert guest-only UI after clearState Note: On Android, clearState: true fully resets app data including credentials. This is an iOS-only gotcha. XCTest kAXErrorInvalidUIElement Crash (iOS) The XCTest driver may crash if Maestro interacts with the accessibility tree before the first render cycle completes on cold boot.
Agent 识别该技能的关键词,点击任意一个即可复制。

该技能未提供触发词。

下载的 .skill 包内含以下字段。
字段 说明
format格式标识(skill/v1)
skill_id技能唯一 ID
name技能名称
version版本号
description技能描述
category所属分类(数组)
trigger_words触发词列表
tags标签列表
source来源标识
source_url来源链接(本页地址)
exported_at导出时间(每次下载生成)
system_prompt系统提示词正文
model_config模型参数:provider / model / temperature / max_tokens / top_p
examples示例
install_guide各平台导入说明(Coze / Dify / Claude / 自定义框架)
同一份技能可按不同平台格式导出。
.skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用 下载
.skillpro 增强格式,额外含脚本 / 工具 / 依赖 / 钩子占位 下载
.json 纯 JSON 导出,只含 system_prompt 与模型参数 下载
Coze 带 frontmatter 的 Markdown,Coze 平台导入用 下载
Dify Dify DSL,创建应用后直接导入 下载

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。