diff --git a/.github/workflows/mobile:validate-build-pre-eas.yml b/.github/workflows/mobile:validate-build-pre-eas.yml index 7e8ae6de4f..a9ab7eaccd 100644 --- a/.github/workflows/mobile:validate-build-pre-eas.yml +++ b/.github/workflows/mobile:validate-build-pre-eas.yml @@ -2,46 +2,78 @@ name: mobile:validate-build-pre-eas permissions: contents: read + checks: read on: # Run on release-please dev releases release: types: [published] - - # Run on PRs that affect mobile + + # Run on PRs that affect mobile or its runtime dependencies pull_request: paths: - 'apps/mobile/**' - - 'packages/**' + - 'packages/analytics/**' + - 'packages/bitcoin/**' + - 'packages/constants/**' + - 'packages/crypto/**' + - 'packages/features/**' + - 'packages/models/**' + - 'packages/provider/**' + - 'packages/queries/**' + - 'packages/query/**' + - 'packages/rpc/**' + - 'packages/services/**' + - 'packages/stacks/**' + - 'packages/state/**' + - 'packages/tokens/**' + - 'packages/ui/**' + - 'packages/utils/**' - 'pnpm-lock.yaml' - 'turbo.json' - + # Allow manual trigger workflow_dispatch: jobs: + code-quality-gate: + name: code-quality-gate + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + + steps: + - name: await-repo-code-checks + uses: wechuli/allcheckspassed@v1 + with: + checks_include: lint-eslint,typecheck,lint-prettier,test-unit + polling_interval: 0.5 + retries: 50 + delay: 0.5 + mobile-validate-build: name: validate-mobile-build + needs: code-quality-gate + if: ${{ !cancelled() && (needs.code-quality-gate.result == 'success' || needs.code-quality-gate.result == 'skipped') }} runs-on: ubuntu-latest - + steps: - name: checkout-code uses: actions/checkout@v4 - + - name: setup-node uses: actions/setup-node@v4 with: node-version: '22.15.0' - + - name: setup-pnpm uses: pnpm/action-setup@v4 - + - name: get-pnpm-store-directory id: pnpm-cache shell: bash run: | echo "STORE_PATH=$(pnpm store path)" >> "$GITHUB_OUTPUT" - + - name: setup-pnpm-cache uses: actions/cache@v4 with: @@ -49,10 +81,10 @@ jobs: key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store- - + - name: run-mobile-build-validation run: ./scripts/test-mobile-build.sh - + - name: upload-build-logs if: failure() uses: actions/upload-artifact@v4 diff --git a/apps/mobile/.eas/workflows/android-maestro-test.yml b/apps/mobile/.eas/workflows/android-maestro-test.yml index 497f8adb9d..e71c4d171c 100644 --- a/apps/mobile/.eas/workflows/android-maestro-test.yml +++ b/apps/mobile/.eas/workflows/android-maestro-test.yml @@ -26,4 +26,5 @@ jobs: params: build_id: ${{ needs.build_android.outputs.build_id }} flow_path: - - maestro/flows/smoke-tests.yaml + - maestro/flows/smoke/ + - maestro/flows/android/ diff --git a/apps/mobile/.eas/workflows/ios-maestro-test.yml b/apps/mobile/.eas/workflows/ios-maestro-test.yml index d76804d309..a1d4096135 100644 --- a/apps/mobile/.eas/workflows/ios-maestro-test.yml +++ b/apps/mobile/.eas/workflows/ios-maestro-test.yml @@ -26,4 +26,4 @@ jobs: params: build_id: ${{ needs.build_ios.outputs.build_id }} flow_path: - - maestro/flows/smoke-tests.yaml + - maestro/flows/smoke/ diff --git a/apps/mobile/.eas/workflows/maestro-smoke-test.yml b/apps/mobile/.eas/workflows/maestro-smoke-test.yml index d3d73cbe71..1401c74ba3 100644 --- a/apps/mobile/.eas/workflows/maestro-smoke-test.yml +++ b/apps/mobile/.eas/workflows/maestro-smoke-test.yml @@ -1,4 +1,4 @@ -name: Maestro Smoke Test +name: Maestro E2E Tests on: pull_request: @@ -21,6 +21,7 @@ jobs: run_eas_update: name: EAS Update type: update + environment: development params: platform: all channel: cicd @@ -61,8 +62,12 @@ jobs: platform: ios profile: devClient - maestro_android_cached: - name: Android Maestro (cached) + # ============================================ + # Smoke tests — fast fail gate + # ============================================ + + smoke_android_cached: + name: Android Smoke (cached) needs: [get_android_build, run_eas_update] if: ${{ needs.get_android_build.outputs.build_id }} type: maestro @@ -72,8 +77,8 @@ jobs: build_id: ${{ needs.get_android_build.outputs.build_id }} flow_path: maestro/flows/smoke-tests-ci.yaml - maestro_ios_cached: - name: iOS Maestro (cached) + smoke_ios_cached: + name: iOS Smoke (cached) needs: [get_ios_build, run_eas_update] if: ${{ needs.get_ios_build.outputs.build_id }} type: maestro @@ -83,8 +88,8 @@ jobs: build_id: ${{ needs.get_ios_build.outputs.build_id }} flow_path: maestro/flows/smoke-tests-ci.yaml - maestro_android_fresh: - name: Android Maestro (fresh) + smoke_android_fresh: + name: Android Smoke (fresh) needs: [build_android, run_eas_update] type: maestro env: @@ -93,8 +98,8 @@ jobs: build_id: ${{ needs.build_android.outputs.build_id }} flow_path: maestro/flows/smoke-tests-ci.yaml - maestro_ios_fresh: - name: iOS Maestro (fresh) + smoke_ios_fresh: + name: iOS Smoke (fresh) needs: [build_ios, run_eas_update] type: maestro env: @@ -102,3 +107,49 @@ jobs: params: build_id: ${{ needs.build_ios.outputs.build_id }} flow_path: maestro/flows/smoke-tests-ci.yaml + + # ============================================ + # Full suite — runs only after smoke passes + # ============================================ + + maestro_android_cached: + name: Android Full Suite (cached) + needs: [smoke_android_cached, get_android_build] + if: ${{ needs.get_android_build.outputs.build_id }} + type: maestro + env: + MAESTRO_DEEP_LINK_URL: 'exp+leather://expo-development-client/?url=https://u.expo.dev/c03c1f22-be7b-4b76-aa1b-3ebf716bd2cc?channel-name=cicd' + params: + build_id: ${{ needs.get_android_build.outputs.build_id }} + flow_path: maestro/flows/full-suite-ci.yaml + + maestro_ios_cached: + name: iOS Full Suite (cached) + needs: [smoke_ios_cached, get_ios_build] + if: ${{ needs.get_ios_build.outputs.build_id }} + type: maestro + env: + MAESTRO_DEEP_LINK_URL: 'exp+leather://expo-development-client/?url=https://u.expo.dev/c03c1f22-be7b-4b76-aa1b-3ebf716bd2cc?channel-name=cicd' + params: + build_id: ${{ needs.get_ios_build.outputs.build_id }} + flow_path: maestro/flows/full-suite-ci.yaml + + maestro_android_fresh: + name: Android Full Suite (fresh) + needs: [smoke_android_fresh, build_android] + type: maestro + env: + MAESTRO_DEEP_LINK_URL: 'exp+leather://expo-development-client/?url=https://u.expo.dev/c03c1f22-be7b-4b76-aa1b-3ebf716bd2cc?channel-name=cicd' + params: + build_id: ${{ needs.build_android.outputs.build_id }} + flow_path: maestro/flows/full-suite-ci.yaml + + maestro_ios_fresh: + name: iOS Full Suite (fresh) + needs: [smoke_ios_fresh, build_ios] + type: maestro + env: + MAESTRO_DEEP_LINK_URL: 'exp+leather://expo-development-client/?url=https://u.expo.dev/c03c1f22-be7b-4b76-aa1b-3ebf716bd2cc?channel-name=cicd' + params: + build_id: ${{ needs.build_ios.outputs.build_id }} + flow_path: maestro/flows/full-suite-ci.yaml diff --git a/apps/mobile/maestro/flows/android/010-create-wallet-sheet.yaml b/apps/mobile/maestro/flows/android/010-create-wallet-sheet.yaml new file mode 100644 index 0000000000..7445ac21cf --- /dev/null +++ b/apps/mobile/maestro/flows/android/010-create-wallet-sheet.yaml @@ -0,0 +1,16 @@ +appId: io.leather.mobilewallet +name: "Android: Create Wallet via Sheet" +--- +- launchApp +- runFlow: ../../shared/clean-up.yaml +- tapOn: + id: 'homeCreateWalletCard' +- tapOn: 'Create new wallet' +- tapOn: + id: 'walletCreationTapToReveal' +- tapOn: + id: 'walletCreationBackedUpButton' +- tapOn: 'Skip for now' +- tapOn: 'Proceed' +- assertVisible: + id: 'homeAccountCard-0' diff --git a/apps/mobile/maestro/flows/android/020-restore-wallet-sheet.yaml b/apps/mobile/maestro/flows/android/020-restore-wallet-sheet.yaml new file mode 100644 index 0000000000..27b0ed825f --- /dev/null +++ b/apps/mobile/maestro/flows/android/020-restore-wallet-sheet.yaml @@ -0,0 +1,18 @@ +appId: io.leather.mobilewallet +name: "Android: Restore Wallet via Sheet" +--- +- launchApp +- runFlow: ../../shared/clean-up.yaml +- tapOn: + id: 'homeCreateWalletCard' +- tapOn: + id: 'restoreWalletSheetButton' +- tapOn: + id: 'restoreWalletTextInput' +- inputText: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon cactus' +- tapOn: + id: 'restoreWalletContinue' +- tapOn: 'Skip for now' +- tapOn: 'Proceed' +- assertVisible: + id: 'homeAccountCard-0' diff --git a/apps/mobile/maestro/flows/full-suite-ci.yaml b/apps/mobile/maestro/flows/full-suite-ci.yaml new file mode 100644 index 0000000000..10bed56100 --- /dev/null +++ b/apps/mobile/maestro/flows/full-suite-ci.yaml @@ -0,0 +1,201 @@ +# Full E2E Test Suite (CI with EAS Update deep link) +# This version loads the JS bundle via EAS Update for faster CI testing +appId: io.leather.mobilewallet +name: Full Test Suite CI +--- +# Launch the app first (required for deep links to work) +- launchApp + +# Wait for app to fully initialize and register URL schemes (iOS needs this) +- waitForAnimationToEnd + +# Then open the deep link to load EAS Update +- openLink: ${MAESTRO_DEEP_LINK_URL} + +# Handle iOS deep link confirmation prompt if it appears +- runFlow: + when: + visible: 'Open' + commands: + - tapOn: 'Open' + +# Wait for EAS Update to load - shows empty home screen +- extendedWaitUntil: + visible: 'Add account' + timeout: 30000 + +# ============================================ +# SECTION 0: Capture Environment Info +# ============================================ + +# Navigate to dev console and screenshot env vars for debugging +- tapOn: + id: 'homeDeveloperToolsButton' +- extendedWaitUntil: + visible: 'Environment' + timeout: 5000 +- takeScreenshot: env-debug-info +- tapOn: + id: 'backButton' + +# ============================================ +# SECTION 1: Wallet Creation +# ============================================ + +# Verify empty home screen +- assertVisible: + id: 'homeCreateWalletCard' + +# Create a wallet via developer console (sheets don't present reliably in EAS Update CI) +- runFlow: ../shared/create-wallet-dev-console.yaml + +# Verify wallet created +- assertVisible: + id: 'homePrivacyButton' + +# ============================================ +# SECTION 2: Settings Navigation +# ============================================ + +# Navigate to Settings +- tapOn: + id: 'homeSettingsButton' +- assertVisible: 'SETTINGS' + +# Test Wallets and Accounts +- tapOn: + id: 'settingsWalletAndAccountsButton' +- assertVisible: 'Wallet 1' +- tapOn: + id: 'backButton' + +# Test Display settings +- tapOn: + id: 'settingsDisplayButton' +- assertVisible: 'DISPLAY' +- tapOn: + id: 'backButton' + +# Test Security settings +- tapOn: + id: 'settingsSecurityButton' +- assertVisible: 'SECURITY' +- tapOn: + id: 'backButton' + +# Test Networks settings +- tapOn: + id: 'settingsNetworkButton' +- assertVisible: 'NETWORKS' +- tapOn: + id: 'backButton' + +# Test Help settings +- tapOn: + id: 'settingsHelpButton' +- assertVisible: 'HELP' +- tapOn: + id: 'backButton' + +# Back to home +- tapOn: + id: 'backButton' +- assertVisible: + id: 'homePrivacyButton' + +# ============================================ +# SECTION 3: Send Flow +# ============================================ + +# Open send flow +- tapOn: + text: 'Send' +- assertVisible: 'Select asset' +- assertVisible: 'Bitcoin' +- assertVisible: 'Stacks' + +# Close send sheet (no back button on sheets, swipe to dismiss) +- swipe: + start: 50%, 15% + end: 50%, 85% +- assertVisible: + id: 'homePrivacyButton' + +# ============================================ +# SECTION 4: Receive Flow +# ============================================ + +# Open receive flow +- tapOn: + text: 'Receive' +- assertVisible: 'Select asset' + +# Test Bitcoin address +- tapOn: + id: 'receiveAssetItem' + index: 0 +- assertVisible: 'Native Segwit' +- tapOn: + id: 'backButton' + +# Close receive sheet (no back button on first sheet screen, swipe to dismiss) +- swipe: + start: 50%, 15% + end: 50%, 85% +- assertVisible: + id: 'homePrivacyButton' + +# ============================================ +# SECTION 5: Network Switching +# ============================================ + +# Switch to Testnet +- tapOn: + id: 'homeSettingsButton' +- tapOn: + id: 'settingsNetworkButton' +- tapOn: 'Testnet4.*Disabled' +- tapOn: + id: 'backButton' +- tapOn: + id: 'backButton' +- assertVisible: 'Testnet4' + +# Switch back to Mainnet +- tapOn: + id: 'homeSettingsButton' +- tapOn: + id: 'settingsNetworkButton' +- tapOn: 'Mainnet.*Disabled' +- tapOn: + id: 'backButton' +- tapOn: + id: 'backButton' +- assertNotVisible: 'Testnet4' + +# ============================================ +# SECTION 6: Cleanup - Remove Wallet +# ============================================ + +# Remove the wallet +- runFlow: ../shared/remove-wallet.yaml + +# Verify back to empty state +- assertVisible: + id: 'homeCreateWalletCard' + +# ============================================ +# SECTION 7: Wallet Restore +# ============================================ + +# Restore a wallet from mnemonic +- runFlow: ../shared/restore-wallet.yaml + +# Verify wallet restored +- assertVisible: + id: 'homePrivacyButton' + +# Final verification - settings accessible +- tapOn: + id: 'homeSettingsButton' +- assertVisible: 'SETTINGS' diff --git a/apps/mobile/maestro/flows/full-suite.yaml b/apps/mobile/maestro/flows/full-suite.yaml new file mode 100644 index 0000000000..857f63639d --- /dev/null +++ b/apps/mobile/maestro/flows/full-suite.yaml @@ -0,0 +1,169 @@ +# Full E2E Test Suite +# Runs all tests in sequence, optimized for speed by reusing wallet state +# This is the recommended flow for comprehensive testing +appId: io.leather.mobilewallet +name: Full Test Suite +--- +# Start fresh +- launchApp: + clearState: true + +# ============================================ +# SECTION 1: Wallet Creation +# ============================================ + +# Verify empty home screen +- assertVisible: + id: 'homeCreateWalletCard' + +# Create a wallet +- runFlow: ../shared/create-wallet.yaml + +# Verify wallet created +- assertVisible: + id: 'homePrivacyButton' + +# ============================================ +# SECTION 2: Settings Navigation +# ============================================ + +# Navigate to Settings +- tapOn: + id: 'homeSettingsButton' +- assertVisible: 'SETTINGS' + +# Test Wallets and Accounts +- tapOn: + id: 'settingsWalletAndAccountsButton' +- assertVisible: 'Wallet 1' +- tapOn: + id: 'backButton' + +# Test Display settings +- tapOn: + id: 'settingsDisplayButton' +- assertVisible: 'DISPLAY' +- tapOn: + id: 'backButton' + +# Test Security settings +- tapOn: + id: 'settingsSecurityButton' +- assertVisible: 'SECURITY' +- tapOn: + id: 'backButton' + +# Test Networks settings +- tapOn: + id: 'settingsNetworkButton' +- assertVisible: 'NETWORKS' +- tapOn: + id: 'backButton' + +# Test Help settings +- tapOn: + id: 'settingsHelpButton' +- assertVisible: 'HELP' +- tapOn: + id: 'backButton' + +# Back to home +- tapOn: + id: 'backButton' +- assertVisible: + id: 'homePrivacyButton' + +# ============================================ +# SECTION 3: Send Flow +# ============================================ + +# Open send flow +- tapOn: + text: 'Send' +- assertVisible: 'Select asset' +- assertVisible: 'Bitcoin' +- assertVisible: 'Stacks' + +# Close send sheet +- tapOn: + id: 'backButton' +- assertVisible: + id: 'homePrivacyButton' + +# ============================================ +# SECTION 4: Receive Flow +# ============================================ + +# Open receive flow +- tapOn: + text: 'Receive' +- assertVisible: 'Select asset' + +# Test Bitcoin address +- tapOn: + id: 'receiveAssetItem' + index: 0 +- assertVisible: 'Native Segwit' +- tapOn: + id: 'backButton' + +# Close receive sheet +- tapOn: + id: 'backButton' +- assertVisible: + id: 'homePrivacyButton' + +# ============================================ +# SECTION 5: Network Switching +# ============================================ + +# Switch to Testnet +- tapOn: + id: 'homeSettingsButton' +- tapOn: + id: 'settingsNetworkButton' +- tapOn: 'Testnet4.*Disabled' +- tapOn: + id: 'backButton' +- tapOn: + id: 'backButton' +- assertVisible: 'Testnet4' + +# Switch back to Mainnet +- tapOn: + id: 'homeSettingsButton' +- tapOn: + id: 'settingsNetworkButton' +- tapOn: 'Mainnet.*Disabled' +- tapOn: + id: 'backButton' +- tapOn: + id: 'backButton' +- assertNotVisible: 'Testnet4' + +# ============================================ +# SECTION 6: Cleanup - Remove Wallet +# ============================================ + +# Remove the wallet +- runFlow: ../shared/remove-wallet.yaml + +# Verify back to empty state +- assertVisible: + id: 'homeCreateWalletCard' + +# ============================================ +# SECTION 7: Wallet Restore +# ============================================ + +# Restore a wallet from mnemonic +- runFlow: ../shared/restore-wallet.yaml + +# Verify wallet restored +- assertVisible: + id: 'homePrivacyButton' + +# Final verification - settings accessible +- tapOn: + id: 'homeSettingsButton' +- assertVisible: 'SETTINGS' diff --git a/apps/mobile/maestro/flows/receive-flow.yaml b/apps/mobile/maestro/flows/receive-flow.yaml new file mode 100644 index 0000000000..6d87599fb0 --- /dev/null +++ b/apps/mobile/maestro/flows/receive-flow.yaml @@ -0,0 +1,42 @@ +# Test: Receive flow UI +# Verifies the receive flow opens and shows address options +appId: io.leather.mobilewallet +name: Receive Flow +--- +- launchApp: + clearState: true + +# Create a wallet first +- runFlow: ../shared/create-wallet.yaml + +# Open receive flow by tapping Receive button +- tapOn: + text: 'Receive' + +# Verify receive sheet opens with asset selection +- assertVisible: 'Select asset' + +# Verify Bitcoin address types are available +- assertVisible: + id: 'receiveAssetItem' + index: 0 + +# Tap on first receive asset (Bitcoin Native Segwit) +- tapOn: + id: 'receiveAssetItem' + index: 0 + +# Verify QR code / address screen appears +- assertVisible: 'Native Segwit' + +# Go back to asset selection +- tapOn: + id: 'backButton' + +# Close the sheet +- tapOn: + id: 'backButton' + +# Verify we're back on home screen +- assertVisible: + id: 'homePrivacyButton' diff --git a/apps/mobile/maestro/flows/send-flow.yaml b/apps/mobile/maestro/flows/send-flow.yaml new file mode 100644 index 0000000000..9efcf3e779 --- /dev/null +++ b/apps/mobile/maestro/flows/send-flow.yaml @@ -0,0 +1,31 @@ +# Test: Send flow UI +# Verifies the send flow opens and shows asset selection +appId: io.leather.mobilewallet +name: Send Flow +--- +- launchApp: + clearState: true + +# Create a wallet first +- runFlow: ../shared/create-wallet.yaml + +# Open send flow by tapping Send button +- tapOn: + text: 'Send' + +# Verify send sheet opens with asset selection +- assertVisible: 'Select asset' + +# Verify Bitcoin is available as an option +- assertVisible: 'Bitcoin' + +# Verify Stacks is available as an option +- assertVisible: 'Stacks' + +# Close the sheet by going back +- tapOn: + id: 'backButton' + +# Verify we're back on home screen +- assertVisible: + id: 'homePrivacyButton' diff --git a/apps/mobile/maestro/flows/settings-navigation.yaml b/apps/mobile/maestro/flows/settings-navigation.yaml new file mode 100644 index 0000000000..002e737342 --- /dev/null +++ b/apps/mobile/maestro/flows/settings-navigation.yaml @@ -0,0 +1,53 @@ +# Test: Settings navigation +# Verifies all settings screens are accessible +appId: io.leather.mobilewallet +name: Settings Navigation +--- +- launchApp: + clearState: true + +# Create a wallet first (settings content varies based on wallet state) +- runFlow: ../shared/create-wallet.yaml + +# Navigate to Settings +- tapOn: + id: 'homeSettingsButton' +- assertVisible: 'SETTINGS' + +# Test Wallets and Accounts navigation +- tapOn: + id: 'settingsWalletAndAccountsButton' +- assertVisible: 'Wallet 1' +- tapOn: + id: 'backButton' + +# Test Display settings navigation +- tapOn: + id: 'settingsDisplayButton' +- assertVisible: 'DISPLAY' +- tapOn: + id: 'backButton' + +# Test Security settings navigation +- tapOn: + id: 'settingsSecurityButton' +- assertVisible: 'SECURITY' +- tapOn: + id: 'backButton' + +# Test Networks settings navigation +- tapOn: + id: 'settingsNetworkButton' +- assertVisible: 'NETWORKS' +- tapOn: + id: 'backButton' + +# Test Help settings navigation +- tapOn: + id: 'settingsHelpButton' +- assertVisible: 'HELP' +- tapOn: + id: 'backButton' + +# Verify we're back at settings +- assertVisible: 'SETTINGS' diff --git a/apps/mobile/maestro/flows/settings-network.yaml b/apps/mobile/maestro/flows/settings-network.yaml new file mode 100644 index 0000000000..16046595d2 --- /dev/null +++ b/apps/mobile/maestro/flows/settings-network.yaml @@ -0,0 +1,45 @@ +# Test: Network switching +# Verifies network can be changed and persists +appId: io.leather.mobilewallet +name: Settings Network +--- +- launchApp: + clearState: true + +# Create a wallet first +- runFlow: ../shared/create-wallet.yaml + +# Verify wallet exists on home screen +- assertVisible: + id: 'homePrivacyButton' + +# Navigate to Settings > Networks +- tapOn: + id: 'homeSettingsButton' +- tapOn: + id: 'settingsNetworkButton' +- assertVisible: 'NETWORKS' + +# Switch to Testnet +- tapOn: 'Testnet4.*Disabled' +- tapOn: + id: 'backButton' + +# Verify network badge shows Testnet +- tapOn: + id: 'backButton' +- assertVisible: 'Testnet4' + +# Switch back to Mainnet +- tapOn: + id: 'homeSettingsButton' +- tapOn: + id: 'settingsNetworkButton' +- tapOn: 'Mainnet.*Disabled' +- tapOn: + id: 'backButton' +- tapOn: + id: 'backButton' + +# Verify network badge no longer shows Testnet +- assertNotVisible: 'Testnet4' diff --git a/apps/mobile/maestro/flows/smoke-tests-ci.yaml b/apps/mobile/maestro/flows/smoke-tests-ci.yaml index ffe6f3dd84..4791ca50eb 100644 --- a/apps/mobile/maestro/flows/smoke-tests-ci.yaml +++ b/apps/mobile/maestro/flows/smoke-tests-ci.yaml @@ -23,7 +23,11 @@ name: Smoke Tests CI visible: 'Add account' timeout: 30000 -# When the user toggles the settings button it should work +# Run smoke tests: create wallet via dev console (sheets unreliable in EAS Update CI) +- runFlow: ../shared/clean-up.yaml +- runFlow: ../shared/create-wallet-dev-console.yaml + +# Verify settings navigation - tapOn: id: 'homeSettingsButton' - assertVisible: 'SETTINGS' diff --git a/apps/mobile/maestro/flows/smoke-tests.yaml b/apps/mobile/maestro/flows/smoke-tests.yaml index e8e628b90c..67535da18a 100644 --- a/apps/mobile/maestro/flows/smoke-tests.yaml +++ b/apps/mobile/maestro/flows/smoke-tests.yaml @@ -2,13 +2,13 @@ appId: io.leather.mobilewallet name: Smoke Tests --- -# Scenario: App launches and user can create a new wallet -- launchApp +- launchApp: + clearState: true -# Given the user is on the home screen -- assertVisible: 'All accounts' +# Create wallet via standard flow +- runFlow: ../shared/create-wallet.yaml -# When the user toggles the settings button it should work +# Verify settings navigation - tapOn: id: 'homeSettingsButton' - assertVisible: 'SETTINGS' diff --git a/apps/mobile/maestro/flows/smoke/010-create-wallet.yaml b/apps/mobile/maestro/flows/smoke/010-create-wallet.yaml new file mode 100644 index 0000000000..7d5c366eee --- /dev/null +++ b/apps/mobile/maestro/flows/smoke/010-create-wallet.yaml @@ -0,0 +1,6 @@ +appId: io.leather.mobilewallet +name: 'Smoke: Create Wallet' +--- +- launchApp: + clearState: true +- runFlow: ../../shared/create-wallet.yaml diff --git a/apps/mobile/maestro/flows/smoke/020-settings-navigation.yaml b/apps/mobile/maestro/flows/smoke/020-settings-navigation.yaml new file mode 100644 index 0000000000..8edb5353cc --- /dev/null +++ b/apps/mobile/maestro/flows/smoke/020-settings-navigation.yaml @@ -0,0 +1,7 @@ +appId: io.leather.mobilewallet +name: 'Smoke: Settings Navigation' +--- +- launchApp +- tapOn: + id: 'homeSettingsButton' +- assertVisible: 'SETTINGS' diff --git a/apps/mobile/maestro/flows/wallet-create.yaml b/apps/mobile/maestro/flows/wallet-create.yaml new file mode 100644 index 0000000000..dbdca7d690 --- /dev/null +++ b/apps/mobile/maestro/flows/wallet-create.yaml @@ -0,0 +1,28 @@ +# Test: Create a new wallet +# Verifies the complete wallet creation flow without biometric security +appId: io.leather.mobilewallet +name: Create Wallet +--- +- launchApp: + clearState: true + +# Verify we start on the empty home screen +- assertVisible: + id: 'homeCreateWalletCard' + +# Create a new wallet using the shared flow +- runFlow: ../shared/create-wallet.yaml + +# Verify wallet was created successfully +- assertVisible: + id: 'homePrivacyButton' + +# Verify settings is accessible +- tapOn: + id: 'homeSettingsButton' +- assertVisible: 'SETTINGS' + +# Navigate to wallets and accounts to verify wallet exists +- tapOn: + id: 'settingsWalletAndAccountsButton' +- assertVisible: 'Wallet 1' diff --git a/apps/mobile/maestro/flows/wallet-restore.yaml b/apps/mobile/maestro/flows/wallet-restore.yaml new file mode 100644 index 0000000000..6ba0fea77b --- /dev/null +++ b/apps/mobile/maestro/flows/wallet-restore.yaml @@ -0,0 +1,28 @@ +# Test: Restore a wallet from mnemonic +# Verifies the wallet restoration flow using the test mnemonic +appId: io.leather.mobilewallet +name: Restore Wallet +--- +- launchApp: + clearState: true + +# Verify we start on the empty home screen +- assertVisible: + id: 'homeCreateWalletCard' + +# Restore a wallet using the shared flow +- runFlow: ../shared/restore-wallet.yaml + +# Verify wallet was restored successfully +- assertVisible: + id: 'homePrivacyButton' + +# Verify settings is accessible +- tapOn: + id: 'homeSettingsButton' +- assertVisible: 'SETTINGS' + +# Navigate to wallets and accounts to verify wallet exists +- tapOn: + id: 'settingsWalletAndAccountsButton' +- assertVisible: 'Wallet 1' diff --git a/apps/mobile/maestro/legacy-flows/README.md b/apps/mobile/maestro/legacy-flows/README.md deleted file mode 100644 index 3a2d928d6f..0000000000 --- a/apps/mobile/maestro/legacy-flows/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Legacy maestro tests - -The tests in this folder are legacy tests that are outdated and failing. - -They need to be grouped together better and re-written but are left temporarily as a reference of the coverage we had before and of some useful patterns in maestro. - -A lot of these tests used text assertion which makes them easy to read however soon became outdated with our CrowdIn setup. - -They also relied heavily on `Developer tools` which was deprecated diff --git a/apps/mobile/maestro/legacy-flows/accounts-drawer.yaml b/apps/mobile/maestro/legacy-flows/accounts-drawer.yaml deleted file mode 100644 index beaa0568bb..0000000000 --- a/apps/mobile/maestro/legacy-flows/accounts-drawer.yaml +++ /dev/null @@ -1,18 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -# Accounts drawer doesn't open if no accounts are present -- tapOn: 'My accounts' -- assertNotVisible: - id: 'settingsWalletAndAccountsButton' -- runFlow: - file: ../shared/add-wallet.yaml -# Accounts drawer should open now -- tapOn: 'My accounts' -- assertVisible: 'Accounts' -- assertVisible: - id: 'settingsWalletAndAccountsButton' -- tapOn: - id: 'settingsWalletAndAccountsButton' -- assertVisible: 'WALLETS' diff --git a/apps/mobile/maestro/legacy-flows/accounts-page.yaml b/apps/mobile/maestro/legacy-flows/accounts-page.yaml deleted file mode 100644 index 4d3e699784..0000000000 --- a/apps/mobile/maestro/legacy-flows/accounts-page.yaml +++ /dev/null @@ -1,21 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -- tapOn: - id: 'homeAccountCard-0' -- assertVisible: - text: 'Account 1' -- assertVisible: - id: 'tokenBalanceItem-BTC' -- assertVisible: - id: 'tokenBalanceItem-STX' -- assertVisible: 'Send' -- assertVisible: 'Receive' -- assertVisible: 'Swap' -- tapOn: - id: 'backButton' -- assertNotVisible: - id: 'backButton' diff --git a/apps/mobile/maestro/legacy-flows/change-account-icon.yaml b/apps/mobile/maestro/legacy-flows/change-account-icon.yaml deleted file mode 100644 index c1e6e0b573..0000000000 --- a/apps/mobile/maestro/legacy-flows/change-account-icon.yaml +++ /dev/null @@ -1,34 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -- assertNotVisible: - id: 'toastContainer' -- tapOn: - id: 'homeSettingsButton' -- tapOn: - id: 'settingsWalletAndAccountsButton' -- tapOn: - id: 'walletListAccountCard' -- tapOn: - text: 'Avatar' -- tapOn: - id: 'defaultAccountIcon_alien' -- tapOn: - id: 'backButton' -- assertVisible: - id: 'defaultAccountIcon_sparkles' -- tapOn: - text: 'Avatar' -- tapOn: - id: 'defaultAccountIcon_alien' -- tapOn: - text: 'Confirm' -- assertVisible: - id: 'defaultAccountIcon_alien' -- tapOn: - id: 'backButton' -- assertVisible: - id: 'defaultAccountIcon_alien' diff --git a/apps/mobile/maestro/legacy-flows/change-network.yaml b/apps/mobile/maestro/legacy-flows/change-network.yaml deleted file mode 100644 index 0ce1bd25b1..0000000000 --- a/apps/mobile/maestro/legacy-flows/change-network.yaml +++ /dev/null @@ -1,25 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- tapOn: - id: 'homeSettingsButton' -- tapOn: - id: 'settingsNetworkButton' -- tapOn: Testnet4 Disabled -- tapOn: - id: 'backButton' -- assertVisible: Testnet4 -- tapOn: - id: 'backButton' -- assertVisible: Testnet4 -- tapOn: - id: 'homeSettingsButton' -- tapOn: Networks Mainnet, testnet or signet -- tapOn: Mainnet Disabled -- tapOn: - id: 'backButton' -- assertNotVisible: Testnet4 -- tapOn: - id: 'backButton' -- assertNotVisible: Testnet4 diff --git a/apps/mobile/maestro/legacy-flows/change-theme.yaml b/apps/mobile/maestro/legacy-flows/change-theme.yaml deleted file mode 100644 index 00883e40e0..0000000000 --- a/apps/mobile/maestro/legacy-flows/change-theme.yaml +++ /dev/null @@ -1,21 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- tapOn: - id: 'homeSettingsButton' -- tapOn: Display Theme and account identifier -- tapOn: Theme System -- tapOn: Light -- tapOn: DISPLAY -- assertVisible: Theme Light -- assertNotVisible: Theme System -- assertNotVisible: Theme Dark -- tapOn: Theme Light -- tapOn: DISPLAY -- tapOn: Theme Light -- tapOn: Dark -- tapOn: DISPLAY -- assertVisible: Theme Dark -- assertNotVisible: Theme System -- assertNotVisible: Theme Light diff --git a/apps/mobile/maestro/legacy-flows/create-wallet-without-security.yaml b/apps/mobile/maestro/legacy-flows/create-wallet-without-security.yaml deleted file mode 100644 index 3f6a8fbedc..0000000000 --- a/apps/mobile/maestro/legacy-flows/create-wallet-without-security.yaml +++ /dev/null @@ -1,6 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml diff --git a/apps/mobile/maestro/legacy-flows/hide-account.yaml b/apps/mobile/maestro/legacy-flows/hide-account.yaml deleted file mode 100644 index 8faad76e43..0000000000 --- a/apps/mobile/maestro/legacy-flows/hide-account.yaml +++ /dev/null @@ -1,31 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -- assertNotVisible: - id: 'toastContainer' -- tapOn: - id: 'homeSettingsButton' -- tapOn: - text: 'Wallets and accounts Add, configure and remove' -- tapOn: - id: 'walletListAccountCard' -- tapOn: - text: 'Hide account' -- assertVisible: 'Un-hide account' -- tapOn: - id: 'backButton' -- assertNotVisible: - id: 'walletListAccountCard' -- tapOn: - text: 'Hidden accounts 1 hidden accounts' -- tapOn: - id: 'walletListAccountCard' -- tapOn: Un-hide account -- tapOn: - id: 'backButton' -- tapOn: - id: 'backButton' -- assertNotVisible: Hidden accounts 0 hidden accounts diff --git a/apps/mobile/maestro/legacy-flows/receive.yaml b/apps/mobile/maestro/legacy-flows/receive.yaml deleted file mode 100644 index c18f3fbfa8..0000000000 --- a/apps/mobile/maestro/legacy-flows/receive.yaml +++ /dev/null @@ -1,33 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -- tapOn: 'Receive' -- assertVisible: 'Select account' -- tapOn: - id: 'walletListAccountCard' - index: 0 -- tapOn: - id: 'receiveAssetItem' - index: 0 -- assertVisible: 'This is your Native Segwit address.' -- tapOn: - id: 'backButton' -- tapOn: - id: 'receiveAssetItem' - index: 1 -- assertVisible: "This is your Taproot address. Use it to receive tokens and collectibles\ - \ on the bitcoin network." -- tapOn: - id: 'backButton' -- tapOn: - id: 'receiveAssetItem' - index: 2 -- assertVisible: 'This is your Stacks address.' -- tapOn: - id: 'backButton' -- tapOn: - id: 'backButton' -- assertVisible: 'Select account' diff --git a/apps/mobile/maestro/legacy-flows/rename-account.yaml b/apps/mobile/maestro/legacy-flows/rename-account.yaml deleted file mode 100644 index 55cadbce2d..0000000000 --- a/apps/mobile/maestro/legacy-flows/rename-account.yaml +++ /dev/null @@ -1,24 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -- assertNotVisible: - id: 'toastContainer' -- tapOn: - id: 'homeSettingsButton' -- tapOn: - text: 'Wallets and accounts Add, configure and remove' -- tapOn: - id: 'walletListAccountCard' -- tapOn: - id: 'walletSettingsAccountNameCell' -- tapOn: - id: 'accountChangeNameSheetInput' -- eraseText -- inputText: 'testAccount' -- tapOn: - text: 'Save' -- assertVisible: - text: 'testAccount' diff --git a/apps/mobile/maestro/legacy-flows/rename-wallet.yaml b/apps/mobile/maestro/legacy-flows/rename-wallet.yaml deleted file mode 100644 index d06b5e7822..0000000000 --- a/apps/mobile/maestro/legacy-flows/rename-wallet.yaml +++ /dev/null @@ -1,32 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -- assertNotVisible: - id: 'toastContainer' -- tapOn: - id: 'homeSettingsButton' -- tapOn: - text: 'Wallets and accounts Add, configure and remove' -- tapOn: - id: 'walletListSettingsButton' - index: 0 -- tapOn: - text: 'Rename wallet' -# # Doing this because iOS input is a bit flaky on maestro, -# # It's known issue and they are on it. -# # https://maestro.mobile.dev/api-reference/commands/erasetext -# - longPressOn: -# id: 'walletChangeNameSheetInput' -# - tapOn: 'Select All' -- tapOn: - id: 'walletChangeNameSheetInput' -- eraseText - -- inputText: 'testWallet' -- tapOn: - text: 'Save' -- assertVisible: - text: 'testWallet' diff --git a/apps/mobile/maestro/legacy-flows/restore-wallet.yaml b/apps/mobile/maestro/legacy-flows/restore-wallet.yaml deleted file mode 100644 index 57d00c0b71..0000000000 --- a/apps/mobile/maestro/legacy-flows/restore-wallet.yaml +++ /dev/null @@ -1,54 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- tapOn: - text: 'Add Wallet' -- tapOn: - id: 'restoreWalletSheetButton' -# verify advanced options appear -- tapOn: 'Advanced options' -- tapOn: 'BIP39 passphrase Disabled' -- assertVisible: 'Passphrase' -- assertVisible: 'Confirm' -- tapOn: 'Confirm' -- assertVisible: 'BIP39 passphrase Disabled' -- tapOn: 'Advanced options' -- assertNotVisible: 'BIP39 passphrase Disabled' -# check validation of invalid mnemonic -- tapOn: - id: 'restoreWalletTextInput' -- inputText: 'definitely not a mnemonic' -- pressKey: Enter -- assertVisible: 'Invalid words: definitely, not, a, mnemonic' -- tapOn: - id: 'restoreWalletTextInput' -- eraseText: 26 -- tapOn: - id: 'backButton' -- tapOn: - text: 'Add Wallet' -# verify validation of valid mnemonic -- tapOn: - id: 'createNewWalletSheetButton' -- tapOn: - id: 'walletCreationTapToReveal' -- tapOn: - text: 'Copy' -- tapOn: - id: 'backButton' -- tapOn: - text: 'Add Wallet' -- tapOn: - id: 'restoreWalletSheetButton' -- assertNotVisible: 'Invalid words: definitely, not, a, mnemonic' -- tapOn: - text: 'Paste' -- tapOn: - text: 'Continue' -- tapOn: - text: 'Skip for now' -- tapOn: - text: 'Proceed' -- assertVisible: - id: 'homeAccountCard-0' diff --git a/apps/mobile/maestro/legacy-flows/secure/create-wallet.yaml b/apps/mobile/maestro/legacy-flows/secure/create-wallet.yaml deleted file mode 100644 index f00c4ef885..0000000000 --- a/apps/mobile/maestro/legacy-flows/secure/create-wallet.yaml +++ /dev/null @@ -1,10 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../../shared/clean-up.yaml -- runFlow: - when: - platform: iOS - file: ../../shared/add-wallet.yaml - env: - SECURE: yes diff --git a/apps/mobile/maestro/legacy-flows/secure/delete-wallet.yaml b/apps/mobile/maestro/legacy-flows/secure/delete-wallet.yaml deleted file mode 100644 index 30836ea51f..0000000000 --- a/apps/mobile/maestro/legacy-flows/secure/delete-wallet.yaml +++ /dev/null @@ -1,29 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../../shared/clean-up.yaml -- runFlow: - file: ../../shared/add-wallet.yaml - env: - SECURE: yes -- assertNotVisible: - id: 'toastContainer' -- tapOn: - id: 'homeSettingsButton' -- tapOn: - text: 'Wallets and accounts Add, configure and remove' -- tapOn: - id: 'walletListSettingsButton' - index: 0 -- tapOn: - text: 'Remove wallet' -- tapOn: - text: 'Proceed' -- tapOn: - id: 'backButton' -- tapOn: - id: 'backButton' -- assertVisible: - text: 'Add Wallet' -- assertVisible: - id: 'homeCreateWalletCard' diff --git a/apps/mobile/maestro/legacy-flows/send.yaml b/apps/mobile/maestro/legacy-flows/send.yaml deleted file mode 100644 index 761494163b..0000000000 --- a/apps/mobile/maestro/legacy-flows/send.yaml +++ /dev/null @@ -1,13 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -- tapOn: 'Send' -- assertVisible: 'Select account' -- tapOn: '$0.00' -- assertVisible: 'Select asset' -- tapOn: '$0.00' -- assertVisible: 'Send' -- assertVisible: 'Account 1' diff --git a/apps/mobile/maestro/legacy-flows/settings-guides.yaml b/apps/mobile/maestro/legacy-flows/settings-guides.yaml deleted file mode 100644 index 03308e2373..0000000000 --- a/apps/mobile/maestro/legacy-flows/settings-guides.yaml +++ /dev/null @@ -1,9 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- tapOn: - id: 'homeSettingsButton' -- tapOn: 'Help Support, guides and articles' -- tapOn: 'Guides Dive into feature details' -- assertVisible: 'USER GUIDES' diff --git a/apps/mobile/maestro/legacy-flows/settings-learn.yaml b/apps/mobile/maestro/legacy-flows/settings-learn.yaml deleted file mode 100644 index 944bf15139..0000000000 --- a/apps/mobile/maestro/legacy-flows/settings-learn.yaml +++ /dev/null @@ -1,14 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- tapOn: - id: 'homeSettingsButton' -- tapOn: - id: 'settingsHelpButton' -- tapOn: 'Learn Expand your knowledge' -- assertVisible: 'LEARN' -- assertVisible: 'Dive Deeper into Bitcoin & Leather: Essential Knowledge & Beyond' -- launchApp: - appId: io.leather.mobilewallet - clearState: false diff --git a/apps/mobile/maestro/legacy-flows/settings-support.yaml b/apps/mobile/maestro/legacy-flows/settings-support.yaml deleted file mode 100644 index 8e79738d4d..0000000000 --- a/apps/mobile/maestro/legacy-flows/settings-support.yaml +++ /dev/null @@ -1,12 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- tapOn: - id: 'homeSettingsButton' -- assertVisible: 'Help Support, guides and articles' -- tapOn: - id: 'settingsHelpButton' -- tapOn: 'Support and feedback Contact our support team' -# view the support page in the browser -- assertVisible: 'GET SUPPORT' diff --git a/apps/mobile/maestro/legacy-flows/wallet-add-account.yaml b/apps/mobile/maestro/legacy-flows/wallet-add-account.yaml deleted file mode 100644 index 1538f5a90c..0000000000 --- a/apps/mobile/maestro/legacy-flows/wallet-add-account.yaml +++ /dev/null @@ -1,16 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -- tapOn: 'Add account All accounts in one' -- tapOn: 'Add to existing wallet Choose existing leather wallet' -- assertVisible: 'WALLETS' -- assertVisible: - id: 'walletListAccountCard' - index: 0 -- tapOn: 'Add account' -- assertVisible: - id: 'walletListAccountCard' - index: 1 diff --git a/apps/mobile/maestro/legacy-flows/wallet-management.yaml b/apps/mobile/maestro/legacy-flows/wallet-management.yaml deleted file mode 100644 index be5e8ec58d..0000000000 --- a/apps/mobile/maestro/legacy-flows/wallet-management.yaml +++ /dev/null @@ -1,39 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -- tapOn: My accounts -- tapOn: - id: 'settingsWalletAndAccountsButton' -- tapOn: Wallet 1 -- assertNotVisible: Add account -- assertNotVisible: - id: 'homeAccountCard-0' -- tapOn: Wallet 1 -- tapOn: - id: 'walletListSettingsButton' -# Test advanced options menu -- tapOn: Advanced options -- assertVisible: Address reuse -- assertVisible: Address scan range -- assertVisible: Export xPub -- tapOn: Advanced options -- assertNotVisible: Address reuse -# Test removing wallet flows -- tapOn: Remove wallet -- tapOn: Cancel -- assertVisible: CONFIGURE WALLET -- tapOn: Remove wallet -- assertVisible: >- - The wallet will be removed from this device. You will lose access - to all tokens and collectibles associated with this wallet. Before proceeding, make sure you have securely saved your secret key. Without it, you won't be able to access your tokens or collectibles from another device. -- tapOn: Proceed -- assertNotVisible: CONFIGURE WALLET -- tapOn: - id: 'backButton' -# Ensure wallet is removed and not other wallets are present -- assertNotVisible: Wallet 1 -- assertVisible: Create or restore wallet Create, Import or connect instantly -- assertVisible: Add Wallet diff --git a/apps/mobile/maestro/legacy-flows/wallet-multi-wallet.yaml b/apps/mobile/maestro/legacy-flows/wallet-multi-wallet.yaml deleted file mode 100644 index 516e404b3e..0000000000 --- a/apps/mobile/maestro/legacy-flows/wallet-multi-wallet.yaml +++ /dev/null @@ -1,65 +0,0 @@ -appId: io.leather.mobilewallet ---- -- launchApp -- runFlow: ../shared/clean-up.yaml -- runFlow: - file: ../shared/add-wallet.yaml -# add a second wallet - TODO move into flow -- tapOn: 'Add account All accounts in one' -- tapOn: 'Add to new wallet Create new wallet' -- tapOn: 'Create new wallet Create a new Bitcoin and Stacks wallet' -- assertVisible: 'BACK UP YOUR SECRET KEY' -- tapOn: "I've backed it up" -- assertVisible: 'Wallet added successfully' -- assertVisible: - id: 'homeAccountCard-0' -- assertVisible: - id: 'homeAccountCard-1' -- tapOn: 'My accounts' -- assertVisible: 'Wallet 1' -- assertVisible: 'Wallet 2' -# test multi wallethidden accounts -- tapOn: - id: 'settingsWalletAndAccountsButton' -- tapOn: 'Hidden accounts 0 hidden accounts' -# ensure empty hidden accounts list shows fallback -- assertVisible: 'View and manage your hidden accounts' -- tapOn: - id: 'backButton' -- tapOn: - id: 'walletListAccountCard' - index: 0 -- tapOn: 'Hide account' -- tapOn: - id: 'backButton' -- tapOn: 'Hidden accounts 1 hidden accounts' -- assertVisible: - id: 'walletListAccountCard' -- tapOn: - id: 'backButton' -- tapOn: 'Hidden accounts 1 hidden accounts' -- assertVisible: 'Wallet 1' -# ensure wallet 2 is not visible as no hidden accounts -- assertNotVisible: 'Wallet 2' -- tapOn: - id: 'backButton' -- tapOn: - id: 'walletListSettingsButton' - index: 0 -- tapOn: - id: 'walletSettingsRemoveWalletButton' -- tapOn: 'Proceed' -- tapOn: - id: 'walletListSettingsButton' -- tapOn: 'Remove wallet' -- tapOn: 'Proceed' -- assertVisible: 'View and manage your wallets all in one place' -- tapOn: 'Add or create wallet' -- assertVisible: 'ADD WALLET' -- assertVisible: - id: 'createNewWalletSheetButton' -- tapOn: 'WALLETS' -- tapOn: - id: 'backButton' -- assertVisible: 'Create or restore wallet Create, Import or connect instantly' -- assertVisible: 'Add Wallet' diff --git a/apps/mobile/maestro/shared/clean-up.yaml b/apps/mobile/maestro/shared/clean-up.yaml index 314a518cca..60e0ddc3ac 100644 --- a/apps/mobile/maestro/shared/clean-up.yaml +++ b/apps/mobile/maestro/shared/clean-up.yaml @@ -7,14 +7,8 @@ appId: io.leather.mobilewallet - tapOn: id: 'homeDeveloperToolsButton' - tapOn: - text: 'Wallet management' -- tapOn: - text: 'Clear' -- tapOn: - id: 'backButton' + id: 'devConsoleClearWalletsButton' - tapOn: id: 'backButton' - assertVisible: - id: 'homeAddWalletButton' -- assertNotVisible: - id: 'homeAccountCard-0' + id: 'homeCreateWalletCard' diff --git a/apps/mobile/maestro/shared/create-wallet-dev-console.yaml b/apps/mobile/maestro/shared/create-wallet-dev-console.yaml new file mode 100644 index 0000000000..85f3fe6217 --- /dev/null +++ b/apps/mobile/maestro/shared/create-wallet-dev-console.yaml @@ -0,0 +1,10 @@ +appId: io.leather.mobilewallet +--- +- tapOn: + id: 'homeDeveloperToolsButton' +- tapOn: + id: 'devConsoleCreateWalletButton' +- tapOn: + id: 'backButton' +- assertVisible: + id: 'homeAccountCard-0' diff --git a/apps/mobile/maestro/shared/create-wallet.yaml b/apps/mobile/maestro/shared/create-wallet.yaml new file mode 100644 index 0000000000..86a53e2a0e --- /dev/null +++ b/apps/mobile/maestro/shared/create-wallet.yaml @@ -0,0 +1,39 @@ +# Creates a new wallet without biometric security +# Assumes: App is on home screen without any existing wallets +# Result: Wallet created and user is on home screen with account visible +appId: io.leather.mobilewallet +--- +# Tap the create wallet card on empty home screen +- tapOn: + id: 'homeCreateWalletCard' + +# Wait for add wallet sheet to fully present +- extendedWaitUntil: + visible: 'Create new wallet' + timeout: 10000 + +# Select "Create new wallet" from the sheet +- tapOn: 'Create new wallet' + +# Reveal the secret key (required before proceeding) +- tapOn: + id: 'walletCreationTapToReveal' + +# Confirm backup +- tapOn: + id: 'walletCreationBackedUpButton' + +# Skip biometric security +- tapOn: + text: 'Skip for now' + +# Confirm skipping security in the warning sheet +- tapOn: + text: 'Continue' + +# Wait for wallet generation and verify we're back on home with account +# homePrivacyButton is only visible on home screen when a wallet exists +- extendedWaitUntil: + visible: + id: 'homePrivacyButton' + timeout: 10000 diff --git a/apps/mobile/maestro/shared/remove-wallet.yaml b/apps/mobile/maestro/shared/remove-wallet.yaml new file mode 100644 index 0000000000..e5cb22eaea --- /dev/null +++ b/apps/mobile/maestro/shared/remove-wallet.yaml @@ -0,0 +1,31 @@ +# Removes the first wallet via Settings +# Assumes: At least one wallet exists and app is on home screen +# Result: First wallet removed, returns to home screen +appId: io.leather.mobilewallet +--- +# Navigate to Settings +- tapOn: + id: 'homeSettingsButton' + +# Navigate to Wallets and Accounts +- tapOn: + id: 'settingsWalletAndAccountsButton' + +# Tap the settings gear on the first wallet +- tapOn: + id: 'walletListSettingsButton' + +# Tap Remove wallet +- tapOn: + id: 'walletSettingsRemoveWalletButton' +- waitForAnimationToEnd + +# Confirm removal in the warning sheet +- tapOn: + text: 'Continue' + +# Navigate back to home +- tapOn: + id: 'backButton' +- tapOn: + id: 'backButton' diff --git a/apps/mobile/maestro/shared/restore-wallet.yaml b/apps/mobile/maestro/shared/restore-wallet.yaml new file mode 100644 index 0000000000..2ba052d632 --- /dev/null +++ b/apps/mobile/maestro/shared/restore-wallet.yaml @@ -0,0 +1,46 @@ +# Restores a wallet from a test mnemonic without biometric security +# Assumes: App is on home screen without any existing wallets +# Result: Wallet restored and user is on home screen with account visible +# Uses the standard test mnemonic from @leather.io/test-config +appId: io.leather.mobilewallet +--- +# Tap the create wallet card on empty home screen +- tapOn: + id: 'homeCreateWalletCard' + +# Wait for add wallet sheet to fully present +- extendedWaitUntil: + visible: + id: 'restoreWalletSheetButton' + timeout: 10000 + +# Select "Restore wallet" from the sheet +- tapOn: + id: 'restoreWalletSheetButton' + +# Enter the test mnemonic (from @leather.io/test-config) +- tapOn: + id: 'restoreWalletTextInput' +- inputText: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon cactus' +- pressKey: Enter + +# Continue to security screen +- tapOn: + id: 'restoreWalletContinue' + +# Skip biometric security (only shown if securityLevelPreference is 'not-selected') +- runFlow: + when: + visible: 'Skip for now' + commands: + - tapOn: + text: 'Skip for now' + - tapOn: + text: 'Continue' + +# Wait for wallet generation and verify we're back on home with account +# homePrivacyButton is only visible on home screen when a wallet exists +- extendedWaitUntil: + visible: + id: 'homePrivacyButton' + timeout: 10000 diff --git a/apps/mobile/src/app/_layout.tsx b/apps/mobile/src/app/_layout.tsx index 16c68b56e2..3e555f9e27 100644 --- a/apps/mobile/src/app/_layout.tsx +++ b/apps/mobile/src/app/_layout.tsx @@ -81,6 +81,7 @@ function App() { + {currentAccount && ( <> diff --git a/apps/mobile/src/app/developer-console.tsx b/apps/mobile/src/app/developer-console.tsx new file mode 100644 index 0000000000..f02484ea8a --- /dev/null +++ b/apps/mobile/src/app/developer-console.tsx @@ -0,0 +1,55 @@ +import { ScrollView } from 'react-native'; + +import { Screen } from '@/components/screen/screen'; +import { TestId } from '@/shared/test-id'; +import { useKeyStore } from '@/store/key-store'; +import { useSettings } from '@/store/settings/settings'; +import { useWallets } from '@/store/wallets/wallets.read'; +import { t } from '@lingui/core/macro'; + +import { Box, Button, Text } from '@leather.io/ui/native'; + +export default function DeveloperConsole() { + const keyStore = useKeyStore(); + const wallets = useWallets(); + const { toggleNetwork } = useSettings(); + + function onCreateWallet() { + void keyStore.createNewSoftwareWallet(); + } + + function onClearWallets() { + for (const wallet of wallets.list) { + wallets.remove(wallet.fingerprint); + } + } + + return ( + + {t`Developer Console`}} /> + + + {t`Wallet Manager`} + + + + {/* eslint-disable lingui/no-unlocalized-strings */} + {t`Environment`} + {`__DEV__: ${String(__DEV__)}`} + {`NODE_ENV: ${process.env.EXPO_PUBLIC_NODE_ENV ?? 'undefined'}`} + {`LAUNCH_DARKLY: ${process.env.EXPO_PUBLIC_LAUNCH_DARKLY ? 'set' : 'unset'}`} + {`SENTRY_DSN: ${process.env.EXPO_PUBLIC_SENTRY_DSN ? 'set' : 'unset'}`} + {`MIXPANEL: ${process.env.EXPO_PUBLIC_MIXPANEL_TOKEN ? 'set' : 'unset'}`} + {`MAESTRO_CI: ${process.env.EXPO_PUBLIC_MAESTRO_CI ?? 'undefined'}`} + {/* eslint-enable lingui/no-unlocalized-strings */} + + + + ); +} diff --git a/apps/mobile/src/components/action-buttons.tsx b/apps/mobile/src/components/action-buttons.tsx index 7a2d7ee2f4..ad31e30784 100644 --- a/apps/mobile/src/components/action-buttons.tsx +++ b/apps/mobile/src/components/action-buttons.tsx @@ -1,4 +1,5 @@ import { useOnramperBuyFlag, useOnramperSellFlag, useSwapFlag } from '@/features/feature-flags'; +import { TestId } from '@/shared/test-id'; import { t } from '@lingui/core/macro'; import { Button, ButtonProps } from '@leather.io/ui/native'; @@ -29,7 +30,13 @@ export function ActionButtons({ return ( <> {onSend && ( - )} @@ -40,6 +47,7 @@ export function ActionButtons({ size={size} variant="outline" flex={fullWidth ? 1 : 0} + testID={TestId.actionButtonReceive} > {t`Receive`} @@ -51,6 +59,7 @@ export function ActionButtons({ size={size} variant="outline" flex={fullWidth ? 1 : 0} + testID={TestId.actionButtonBuy} > {t`Buy`} @@ -62,6 +71,7 @@ export function ActionButtons({ size={size} variant="outline" flex={fullWidth ? 1 : 0} + testID={TestId.actionButtonSell} > {t`Sell`} @@ -73,6 +83,7 @@ export function ActionButtons({ size={size} variant="outline" flex={fullWidth ? 1 : 0} + testID={TestId.actionButtonSwap} > {t`Swap`} diff --git a/apps/mobile/src/components/home/home-without-account-screen.tsx b/apps/mobile/src/components/home/home-without-account-screen.tsx index dc6d56544e..c89b3a7e88 100644 --- a/apps/mobile/src/components/home/home-without-account-screen.tsx +++ b/apps/mobile/src/components/home/home-without-account-screen.tsx @@ -3,18 +3,26 @@ import { HeaderActions } from '@/components/screen/screen-header/components/head import { useGlobalSheets } from '@/core/global-sheet-provider'; import { CreateWalletCard } from '@/features/account/components/create-wallet-card'; import { NetworkBadge } from '@/features/settings/network-badge'; +import { TestId } from '@/shared/test-id'; +import { useRouter } from 'expo-router'; -import { Box, LeatherLogomarkIcon } from '@leather.io/ui/native'; +import { Box, LeatherLogomarkIcon, Pressable } from '@leather.io/ui/native'; export function HomeScreenWithoutAccount() { const { addWalletSheetRef } = useGlobalSheets(); + const router = useRouter(); return ( - + router.navigate('/developer-console')} + testID={TestId.homeDeveloperToolsButton} + > + + } diff --git a/apps/mobile/src/components/screen/screen-header/components/header-actions.tsx b/apps/mobile/src/components/screen/screen-header/components/header-actions.tsx index 363cf34d75..4e7030e81f 100644 --- a/apps/mobile/src/components/screen/screen-header/components/header-actions.tsx +++ b/apps/mobile/src/components/screen/screen-header/components/header-actions.tsx @@ -4,7 +4,14 @@ import { useWallets } from '@/store/wallets/wallets.read'; import { t } from '@lingui/core/macro'; import { useRouter } from 'expo-router'; -import { Box, Eye1ClosedIcon, Eye1Icon, IconButton, SettingsGearIcon } from '@leather.io/ui/native'; +import { + Box, + CodeIcon, + Eye1ClosedIcon, + Eye1Icon, + IconButton, + SettingsGearIcon, +} from '@leather.io/ui/native'; export function HeaderActions() { const router = useRouter(); @@ -17,6 +24,12 @@ export function HeaderActions() { return ( + } + onPress={() => router.navigate('/developer-console')} + testID={TestId.homeDeveloperToolsButton} + /> {hasWallets && (