diff --git a/apps/mobile-app/.gitignore b/apps/mobile-app/.gitignore index d8472a4d5..6d26df642 100644 --- a/apps/mobile-app/.gitignore +++ b/apps/mobile-app/.gitignore @@ -47,8 +47,3 @@ app-example # Test output files coverage build - -# Maestro E2E test outputs -.maestro/tests/ -maestro-report.xml -*.png diff --git a/apps/mobile-app/.maestro/config.yaml b/apps/mobile-app/.maestro/config.yaml deleted file mode 100644 index e16641cb3..000000000 --- a/apps/mobile-app/.maestro/config.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Maestro E2E Test Configuration -# https://maestro.dev/docs/configuration - -# Application identifiers -appId: net.aliasvault.app - -# Default timeout for assertions (ms) -defaultTimeout: 10000 - -# Environment variables (can be overridden via CLI) -env: - # API server URL for testing - API_URL: "http://localhost:5092" - - # Test user credentials (set via CI secrets or local .env) - TEST_USERNAME: "" - TEST_PASSWORD: "" - -# Test configuration -flows: - # Run flows in order (numbered prefixes ensure correct sequence) - - ".maestro/flows/" - -# Screenshots configuration -screenshots: - enabled: true - format: png - -# Logging -logLevel: info diff --git a/apps/mobile-app/.maestro/flows/01-app-launch.yaml b/apps/mobile-app/.maestro/flows/01-app-launch.yaml deleted file mode 100644 index 93e6485ff..000000000 --- a/apps/mobile-app/.maestro/flows/01-app-launch.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# Test 01: App Launch -# Verifies the app launches correctly and shows the login screen -# -# Prerequisites: None (first test in sequence) -# Expected: App launches and displays login form - -appId: net.aliasvault.app ---- -# Launch the app with a clean state -- launchApp: - clearState: true - -# Wait for app to fully load - look for AliasVault text -- extendedWaitUntil: - visible: "AliasVault" - timeout: 15000 - -# Verify the login screen is displayed (use testID or fall back to text) -- assertVisible: - id: "login-screen" - optional: true - -# Verify login form elements - try testID first, then text placeholder -- assertVisible: - id: "username-input" - optional: true - -- assertVisible: - id: "password-input" - optional: true - -# Check for Log in button using text (note: "Log in" with space) -- assertVisible: - text: "Log in" - -# Take screenshot of successful launch -- takeScreenshot: "01-app-launched" diff --git a/apps/mobile-app/.maestro/flows/02-login-validation.yaml b/apps/mobile-app/.maestro/flows/02-login-validation.yaml deleted file mode 100644 index 1dac9f7fe..000000000 --- a/apps/mobile-app/.maestro/flows/02-login-validation.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# Test 02: Login Validation -# Verifies login form validation and error handling -# -# Prerequisites: App is on login screen -# Expected: Shows appropriate error messages for invalid input - -appId: net.aliasvault.app ---- -# Launch the app fresh -- launchApp: - clearState: true - -# Wait for login screen -- extendedWaitUntil: - visible: - id: "login-screen" - timeout: 15000 - -# Test 1: Empty form submission -- tapOn: - id: "login-button" - -# Should show validation error -- assertVisible: - text: "Username and password are required" - optional: true - -- takeScreenshot: "02-1-empty-form-validation" - -# Test 2: Invalid credentials -- tapOn: - id: "username-input" -- inputText: "invalid@test.com" - -- tapOn: - id: "password-input" -- inputText: "wrongpassword" - -- hideKeyboard - -- tapOn: - id: "login-button" - -# Wait for error response (network request may take time) -- extendedWaitUntil: - visible: - id: "error-message" - timeout: 15000 - optional: true - -- takeScreenshot: "02-2-invalid-credentials" diff --git a/apps/mobile-app/.maestro/flows/03-successful-login.yaml b/apps/mobile-app/.maestro/flows/03-successful-login.yaml deleted file mode 100644 index 1fddfb47b..000000000 --- a/apps/mobile-app/.maestro/flows/03-successful-login.yaml +++ /dev/null @@ -1,88 +0,0 @@ -# Test 03: Successful Login -# Verifies login flow with valid credentials against local API -# -# Prerequisites: Valid test user exists on local API server (http://localhost:5092) -# Environment: TEST_USERNAME, TEST_PASSWORD must be set -# Expected: User logs in and sees vault items screen - -appId: net.aliasvault.app ---- -# Launch the app fresh -- launchApp: - clearState: true - -# Wait for login screen -- extendedWaitUntil: - visible: - id: "login-screen" - timeout: 15000 - -# ===== Configure API URL to use local server ===== - -# Tap on the server URL link to go to settings -- tapOn: - id: "server-url-link" - -# Wait for settings screen to load -- extendedWaitUntil: - visible: "Self-hosted" - timeout: 10000 - -# Select "Self-hosted" option -- tapOn: - text: "Self-hosted" - -# Wait for custom URL input to appear -- extendedWaitUntil: - visible: - id: "custom-api-url-input" - timeout: 5000 - -# Enter the local API URL -- tapOn: - id: "custom-api-url-input" -- inputText: "http://localhost:5092" - -- hideKeyboard - -# Go back to login screen -- tapOn: - id: "back-button" - -# Wait for login screen to be visible again -- extendedWaitUntil: - visible: - id: "login-screen" - timeout: 10000 - -# ===== Now perform login ===== - -# Enter username -- tapOn: - id: "username-input" -- inputText: ${TEST_USERNAME} - -# Enter password -- tapOn: - id: "password-input" -- inputText: ${TEST_PASSWORD} - -- hideKeyboard - -- takeScreenshot: "03-1-credentials-entered" - -# Submit login -- tapOn: - id: "login-button" - -# Wait for login to complete (may include vault sync) -- extendedWaitUntil: - visible: - id: "items-screen" - timeout: 30000 - -# Verify we're on the items/vault screen -- assertVisible: - id: "items-list" - -- takeScreenshot: "03-2-login-successful" diff --git a/apps/mobile-app/.maestro/flows/04-create-item.yaml b/apps/mobile-app/.maestro/flows/04-create-item.yaml deleted file mode 100644 index a6179ef1b..000000000 --- a/apps/mobile-app/.maestro/flows/04-create-item.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# Test 04: Create New Item -# Verifies item creation flow -# -# Prerequisites: User is logged in (run 03-successful-login.yaml first) -# Expected: New item is created and visible in vault - -appId: net.aliasvault.app ---- -# Generate unique item name using timestamp -- runScript: - file: ../utils/generate-unique-name.js - env: - PREFIX: "E2E Test" - -# Ensure we're on the items screen (assumes logged in) -- assertVisible: - id: "items-screen" - optional: true - -# Tap the FAB (Floating Action Button) to add new item -- tapOn: - id: "add-item-button" - -# Wait for add/edit screen to load -- extendedWaitUntil: - visible: - id: "add-edit-screen" - timeout: 10000 - -- takeScreenshot: "04-1-add-item-screen" - -# Enter item name (uses unique name generated by script) -- tapOn: - id: "item-name-input" -- inputText: ${output.UNIQUE_NAME} - -# Enter service URL -- tapOn: - id: "service-url-input" -- inputText: "https://example.com" - -# Add email field (not visible by default for Login type) -- tapOn: - id: "add-email-button" - -# Enter email -- tapOn: - id: "login-email-input" -- inputText: "e2e-test@example.com" - -# Enter username (optional - field may not be visible) -- tapOn: - id: "login-username-input" - optional: true -- inputText: - text: "e2euser" - optional: true - -- hideKeyboard - -- takeScreenshot: "04-2-item-filled" - -# Save the item -- tapOn: - id: "save-button" - -# Wait for item detail screen to load (app navigates here after save) -- extendedWaitUntil: - visible: - text: "Login credentials" - timeout: 10000 - -- takeScreenshot: "04-3-item-detail-screen" - -# Wait for back button to be ready -- extendedWaitUntil: - visible: "Wait_for_1_sec" - optional: true - timeout: 1000 - -# Go back to items list -- tapOn: - id: "back-button" - -# Wait for items screen to be visible -- extendedWaitUntil: - visible: - id: "items-screen" - timeout: 10000 - -# Verify the newly created item appears in the list by tapping on it -- tapOn: - text: ${output.UNIQUE_NAME} - -# Wait for item detail screen to confirm we tapped the right item -- extendedWaitUntil: - visible: - text: "Login credentials" - timeout: 10000 - -- takeScreenshot: "04-4-item-verified" diff --git a/apps/mobile-app/.maestro/utils/generate-unique-name.js b/apps/mobile-app/.maestro/utils/generate-unique-name.js deleted file mode 100644 index ac1adec45..000000000 --- a/apps/mobile-app/.maestro/utils/generate-unique-name.js +++ /dev/null @@ -1,11 +0,0 @@ -/* global PREFIX, output */ -// Generate a unique name using timestamp -// Usage: Set PREFIX env var to customize the prefix (default: "Test") -// Output: UNIQUE_NAME variable containing the generated name - -const prefix = PREFIX || 'Test'; -const timestamp = Date.now(); -// Use last 6 digits to keep it readable but unique -const shortId = String(timestamp).slice(-6); - -output.UNIQUE_NAME = `${prefix} ${shortId}`; diff --git a/apps/mobile-app/package.json b/apps/mobile-app/package.json index 5af98270f..d06105841 100644 --- a/apps/mobile-app/package.json +++ b/apps/mobile-app/package.json @@ -9,9 +9,6 @@ "web": "expo start --web", "test": "jest --passWithNoTests", "test:watch": "jest --passWithNoTests --watchAll", - "test:e2e": "maestro test .maestro/flows/", - "test:e2e:android": "maestro test .maestro/flows/ --platform android", - "test:e2e:ios": "maestro test .maestro/flows/ --platform ios", "lint": "eslint .", "lint:fix": "eslint . --fix" }, diff --git a/docs/misc/dev/mobile-apps/ios/e2e-testing.md b/docs/misc/dev/mobile-apps/ios/e2e-testing.md index 7ca1a007b..375b0479c 100644 --- a/docs/misc/dev/mobile-apps/ios/e2e-testing.md +++ b/docs/misc/dev/mobile-apps/ios/e2e-testing.md @@ -1,135 +1,104 @@ -# iOS E2E Testing with Maestro +# iOS Testing Guide -This guide explains how to set up and run end-to-end tests for the AliasVault iOS mobile app using [Maestro](https://maestro.mobile.dev/). +This guide explains how to run the iOS test suites for the AliasVault mobile app. + +## Overview + +The iOS app has two test targets: + +1. **AliasVaultUITests** - End-to-end UI tests that test full user flows +2. **VaultStoreKitTests** - Unit tests for the native VaultStoreKit framework ## Prerequisites -- macOS (required for iOS simulator) -- Xcode installed with iOS Simulator +- macOS with Xcode installed (15.0+) +- iOS Simulator configured - Node.js 20+ -- The AliasVault mobile app built and ready to run +- CocoaPods dependencies installed (`cd apps/mobile-app && npx pod-install`) +- For UI tests: Local API server running at `http://localhost:5092` -## Installing Maestro +## Running Tests -Install Maestro CLI: +### Via Xcode + +1. Open the project in Xcode: + ```bash + cd apps/mobile-app/ios + open AliasVault.xcworkspace + ``` + +2. Select a simulator (e.g., iPhone 16 Pro) + +3. Run tests: + - **All tests**: `Cmd + U` or Product > Test + - **Specific test class**: Click the diamond icon next to the test class in the Test Navigator + - **Single test**: Click the diamond icon next to a specific test method + +### Via Command Line (xcodebuild) + +#### Run All Tests ```bash -curl -Ls "https://get.maestro.mobile.dev" | bash +cd apps/mobile-app/ios + +# Run all tests on iPhone 17 Pro simulator +xcodebuild test \ + -workspace AliasVault.xcworkspace \ + -scheme AliasVault \ + -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ + -resultBundlePath ./test-results ``` -After installation, restart your terminal or run: +#### Run UI Tests Only ```bash -export PATH="$PATH":"$HOME/.maestro/bin" +xcodebuild test \ + -workspace AliasVault.xcworkspace \ + -scheme AliasVault \ + -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ + -only-testing:AliasVaultUITests ``` -Verify the installation: +#### Run VaultStoreKit Unit Tests Only ```bash -maestro --version +xcodebuild test \ + -workspace AliasVault.xcworkspace \ + -scheme AliasVault \ + -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ + -only-testing:VaultStoreKitTests ``` -## Building the App for Testing - -Before running E2E tests, you need to build the app: +#### Run a Specific Test ```bash -cd apps/mobile-app +# Run a specific test class +xcodebuild test \ + -workspace AliasVault.xcworkspace \ + -scheme AliasVault \ + -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ + -only-testing:AliasVaultUITests/AliasVaultUITests -# Install dependencies -npm install - -# Build and run on iOS simulator -npm run ios +# Run a specific test method +xcodebuild test \ + -workspace AliasVault.xcworkspace \ + -scheme AliasVault \ + -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ + -only-testing:AliasVaultUITests/AliasVaultUITests/test01AppLaunch ``` -Wait for the app to fully launch in the simulator before running tests. - -## Running E2E Tests - -### Run All Tests +#### With Custom API URL (for UI tests) ```bash -cd apps/mobile-app - -# Run all E2E tests on iOS -npm run test:e2e:ios +API_URL="http://your-server:5092" xcodebuild test \ + -workspace AliasVault.xcworkspace \ + -scheme AliasVault \ + -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ + -only-testing:AliasVaultUITests ``` -### Run a Specific Test +### List Available Simulators ```bash -# Run a single test file -$HOME/.maestro/bin/maestro test .maestro/flows/01-app-launch.yaml --platform ios -``` - -### Run Tests with Environment Variables - -Some tests require credentials to log in: - -```bash -TEST_USERNAME="your-test-user" TEST_PASSWORD="your-test-password" npm run test:e2e:ios -``` - -Or pass them directly to Maestro: - -```bash -$HOME/.maestro/bin/maestro test .maestro/flows/03-successful-login.yaml \ - --platform ios \ - --env TEST_USERNAME="your-test-user" \ - --env TEST_PASSWORD="your-test-password" -``` - -## Test Structure - -Tests are located in `apps/mobile-app/.maestro/`: - -``` -.maestro/ -├── config.yaml # Maestro configuration -├── flows/ # Test flows (run in order) -│ ├── 01-app-launch.yaml -│ ├── 02-login-validation.yaml -│ ├── 03-successful-login.yaml -│ ├── 04-create-item.yaml -│ └── ... -└── utils/ # Reusable flows - └── go-back.yaml -``` - -## Debugging Failed Tests - -### View Screenshots - -Maestro saves screenshots and debug output to `~/.maestro/tests/`. After a test run, check this directory for: -- Screenshots at failure points -- JSON files with element hierarchy -- HTML reports - -### Run in Debug Mode - -```bash -maestro test .maestro/flows/01-app-launch.yaml --debug-output ./debug -``` - -### Interactive Studio - -Launch Maestro Studio to interactively build and debug tests: - -```bash -maestro studio -``` - -This opens a web UI where you can: -- See the current screen elements -- Record actions -- Test selectors - -## CI/CD Integration - -E2E tests are configured to run in GitHub Actions: - -- **Android tests**: Run on every PR (Linux runner) -- **iOS tests**: Run on schedule/manual dispatch (macOS runner - higher cost) - -See `.github/workflows/mobile-e2e-tests.yml` for the CI configuration. +xcrun simctl list devices available +``` \ No newline at end of file