This directory contains end-to-end tests for GuildPass Mobile using Maestro, an Expo-compatible mobile UI testing framework.
- ✅ Validates onboarding screen display
- ✅ Tests navigation to profile screen
- File:
01-onboarding-to-profile.yaml
- ✅ Tests manual wallet address input
- ✅ Validates wallet connection flow
- ✅ Confirms connected state display
- File:
02-wallet-entry.yaml
- ✅ Tests navigation to guilds list
- ✅ Validates guild card display
- ✅ Tests guild detail navigation
- ✅ Confirms membership status display
- File:
03-guild-navigation.yaml
- ✅ Tests successful access check flow
- ✅ Validates form input and submission
- ✅ Confirms success result display
- File:
04-access-check-success.yaml - Note: Requires mock API to return success response
- ✅ Tests failed access check flow
- ✅ Validates error handling
- ✅ Confirms error message display
- File:
05-access-check-failure.yaml - Note: Requires mock API to return error response
- ✅ Tests settings navigation
- ✅ Validates reset functionality
- ✅ Confirms app returns to disconnected state
- File:
06-reset-app-state.yaml
- ✅ Validates WalletConnect UI entry point
- ✅ Tests manual-entry fallback flow
- ✅ Confirms disconnect returns to the connect form
- File:
07-walletconnect-flow.yaml
- ✅ Verifies the configured social/email onboarding branch and its email input
- File:
08-embedded-wallet-entry.yaml - Note: Run this flow explicitly against a development build configured with
EXPO_PUBLIC_PRIVY_APP_IDandEXPO_PUBLIC_PRIVY_CLIENT_ID. It is excluded from the default suite because OTP sign-in requires a real provider account.
- ✅ Tests scanner rejection UI
- ✅ Confirms expired QR messaging is specific
- ✅ Verifies Scan Again clears the error state
- File:
09-access-scanner-rescan.yaml
- ✅ Simulates an expired access QR payload through the scanner test fixture
- ✅ Asserts the specific
This QR code has expired.error - ✅ Confirms the generic QR fallback message is not shown
- File:
10-access-qr-expired.yaml
- ✅ Simulates an unsupported future QR payload version through the scanner test fixture
- ✅ Asserts the specific update-required QR version error
- ✅ Confirms the generic QR fallback message is not shown
- File:
11-access-qr-unsupported-version.yaml
- ✅ Simulates non-JSON QR contents through the scanner test fixture
- ✅ Asserts the specific malformed GuildPass payload error
- ✅ Confirms the generic QR fallback message is not shown
- File:
12-access-qr-malformed-json.yaml
- ✅ Opens
guildpass://access-check?guildId=alpha-guild - ✅ Asserts the specific missing
resourceIdparameter error - ✅ Confirms the generic deep-link fallback message is not shown
- File:
13-deep-link-access-check-missing-resource-id.yaml
- ✅ Opens
guildpass://guild/%20 - ✅ Asserts the specific invalid
guildIderror - ✅ Confirms the generic deep-link fallback message is not shown
- File:
14-deep-link-guild-detail-invalid-guild-id.yaml
macOS/Linux:
curl -Ls "https://get.maestro.mobile.dev" | bashWindows:
# Using WSL (recommended)
wsl
curl -Ls "https://get.maestro.mobile.dev" | bashVerify installation:
maestro --versioniOS Simulator:
# Install Xcode from App Store
# Open Xcode and install iOS Simulator
xcrun simctl list devicesAndroid Emulator:
# Install Android Studio
# Create an AVD (Android Virtual Device)
# Start emulator
emulator -list-avds
emulator @your_avd_nameDevelopment Build (recommended for E2E testing):
# iOS
npx expo run:ios
# Android
npx expo run:androidThe app will be installed on the simulator/emulator with the bundle ID xyz.guildpass.mobile.
In a separate terminal:
pnpm start# Run all flows
maestro test .maestro/
# Run specific flow
maestro test .maestro/01-onboarding-to-profile.yaml
# Run with recording
maestro test --format junit --output test-results .maestro/The default suite is defined in .maestro/config.yaml and includes all flows except
08-embedded-wallet-entry.yaml, which depends on a real OTP provider account.
# Open Maestro Studio for interactive testing
maestro studioTest IDs follow this naming convention:
- Screens:
{screen-name}-screen(e.g.,onboarding-screen) - Buttons:
{action}-button(e.g.,wallet-connect-button) - Inputs:
{field-name}-input(e.g.,wallet-address-input) - Navigation:
navigate-{destination}-button - Results:
{feature}-resultor{feature}-error
QR edge-case flows use dev-only scanner fixture buttons to exercise the same scanner error UI
without relying on physical camera frame injection. Deep-link edge-case flows use Maestro
openLink commands with malformed or incomplete URLs.
For tests that depend on API responses (access checks), you can:
-
Use environment variables to switch between mock and real API:
env: MOCK_API_SUCCESS: true
-
Set up a local mock server using tools like:
-
Configure mock endpoint in
.env.test:EXPO_PUBLIC_API_URL=http://localhost:3000
See .github/workflows/e2e-tests.yml for automated E2E testing on PR and push events.
The workflow:
- Sets up Node.js and dependencies
- Installs Maestro CLI
- Builds Expo development build
- Starts iOS Simulator or Android Emulator
- Runs all Maestro test flows
- Uploads test results and recordings as artifacts
# Verify app is installed
xcrun simctl listapps booted | grep guildpass
# Reinstall app
npx expo run:ios --device- Use
extendedWaitUntilfor longer waits:- extendedWaitUntil: visible: id: "element-id" timeout: 10000
- Check testID is correctly added to component
- Verify element is visible (not hidden or scrolled off-screen)
- Use Maestro Studio to inspect element hierarchy
# Reset iOS Simulator
xcrun simctl erase all
# Restart Android Emulator
adb reboot- Keep tests independent: Each test should be able to run in isolation
- Use descriptive test IDs: Make element identification clear
- Add timeouts: Network requests need appropriate wait times
- Clean state: Reset app state between tests when needed
- Mock network: Reduce flakiness by mocking API responses
- Record failures: Use
--format junitto capture test results
When adding new screens or features:
- Add
testIDprops to interactive elements - Create corresponding Maestro flow in
.maestro/ - Update this README with new test coverage
- Ensure tests pass locally before opening PR