From 165fe5b66be94ba6e67e1e7bd0dd605bc5cfedb7 Mon Sep 17 00:00:00 2001 From: Suriya Date: Wed, 25 Feb 2026 22:06:22 +0530 Subject: [PATCH] maestra testcases --- apps/mobile/apps/client/lib/main.dart | 21 ++++- apps/mobile/apps/client/maestro/README.md | 42 ++++++++++ apps/mobile/apps/client/maestro/login.yaml | 18 ++++ apps/mobile/apps/client/maestro/signup.yaml | 23 +++++ apps/mobile/apps/client/pubspec.yaml | 1 + apps/mobile/apps/staff/lib/main.dart | 22 ++++- apps/mobile/apps/staff/maestro/README.md | 41 +++++++++ apps/mobile/apps/staff/maestro/login.yaml | 18 ++++ apps/mobile/apps/staff/maestro/signup.yaml | 18 ++++ apps/mobile/apps/staff/pubspec.yaml | 1 + apps/mobile/pubspec.lock | 8 ++ docs/research/flutter-testing-tools.md | 14 +++- .../research/maestro-test-run-instructions.md | 84 +++++++++++++++++++ docs/research/marionette-spike-usage.md | 58 +++++++++++++ 14 files changed, 363 insertions(+), 6 deletions(-) create mode 100644 apps/mobile/apps/client/maestro/README.md create mode 100644 apps/mobile/apps/client/maestro/login.yaml create mode 100644 apps/mobile/apps/client/maestro/signup.yaml create mode 100644 apps/mobile/apps/staff/maestro/README.md create mode 100644 apps/mobile/apps/staff/maestro/login.yaml create mode 100644 apps/mobile/apps/staff/maestro/signup.yaml create mode 100644 docs/research/maestro-test-run-instructions.md create mode 100644 docs/research/marionette-spike-usage.md diff --git a/apps/mobile/apps/client/lib/main.dart b/apps/mobile/apps/client/lib/main.dart index a0e67c19..ddfa75aa 100644 --- a/apps/mobile/apps/client/lib/main.dart +++ b/apps/mobile/apps/client/lib/main.dart @@ -1,3 +1,5 @@ +import 'dart:io' show Platform; + import 'package:client_authentication/client_authentication.dart' as client_authentication; import 'package:client_create_order/client_create_order.dart' @@ -10,6 +12,7 @@ import 'package:design_system/design_system.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:marionette_flutter/marionette_flutter.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_modular/flutter_modular.dart'; @@ -20,7 +23,23 @@ import 'firebase_options.dart'; import 'src/widgets/session_listener.dart'; void main() async { - WidgetsFlutterBinding.ensureInitialized(); + final bool isFlutterTest = + !kIsWeb ? Platform.environment.containsKey('FLUTTER_TEST') : false; + if (kDebugMode && !isFlutterTest) { + MarionetteBinding.ensureInitialized( + MarionetteConfiguration( + isInteractiveWidget: (Type type) => + type == UiButton || type == UiTextField, + extractText: (Widget widget) { + if (widget is UiTextField) return widget.label; + if (widget is UiButton) return widget.text; + return null; + }, + ), + ); + } else { + WidgetsFlutterBinding.ensureInitialized(); + } await Firebase.initializeApp( options: kIsWeb ? DefaultFirebaseOptions.currentPlatform : null, ); diff --git a/apps/mobile/apps/client/maestro/README.md b/apps/mobile/apps/client/maestro/README.md new file mode 100644 index 00000000..97407ed3 --- /dev/null +++ b/apps/mobile/apps/client/maestro/README.md @@ -0,0 +1,42 @@ +# Maestro Integration Tests — Client App + +Login and signup flows for the KROW Client app. +See [docs/research/flutter-testing-tools.md](/docs/research/flutter-testing-tools.md) for the evaluation report. +**Full run instructions:** [docs/research/maestro-test-run-instructions.md](/docs/research/maestro-test-run-instructions.md) + +## Prerequisites + +- [Maestro CLI](https://maestro.dev/docs/getting-started/installation) installed +- Client app built and installed on device/emulator: + ```bash + cd apps/mobile && flutter build apk + adb install build/app/outputs/flutter-apk/app-debug.apk + ``` + +## Credentials + +| Flow | Credentials | +|------|-------------| +| **Client login** | legendary@krowd.com / Demo2026! | +| **Staff login** | 5557654321 / OTP 123456 | +| **Client signup** | Env vars: `MAESTRO_CLIENT_EMAIL`, `MAESTRO_CLIENT_PASSWORD`, `MAESTRO_CLIENT_COMPANY` | +| **Staff signup** | Env var: `MAESTRO_STAFF_SIGNUP_PHONE` (must be new Firebase test phone) | + +## Run + +From the project root: + +```bash +# Login +maestro test apps/mobile/apps/client/maestro/login.yaml + +# Signup +maestro test apps/mobile/apps/client/maestro/signup.yaml +``` + +## Flows + +| File | Flow | Description | +|------------|-------------|--------------------------------------------| +| login.yaml | Client Login| Get Started → Sign In → Home | +| signup.yaml| Client Signup| Get Started → Create Account → Home | diff --git a/apps/mobile/apps/client/maestro/login.yaml b/apps/mobile/apps/client/maestro/login.yaml new file mode 100644 index 00000000..6598a03f --- /dev/null +++ b/apps/mobile/apps/client/maestro/login.yaml @@ -0,0 +1,18 @@ +# Client App - Login Flow +# Prerequisites: App built and installed (debug or release) +# Run: maestro test apps/mobile/apps/client/maestro/login.yaml +# Test credentials: legendary@krowd.com / Demo2026! +# Note: Auth uses Firebase/Data Connect + +appId: com.krowwithus.client +--- +- launchApp +- assertVisible: "Sign In" +- tapOn: "Sign In" +- assertVisible: "Email" +- tapOn: "Email" +- inputText: "legendary@krowd.com" +- tapOn: "Password" +- inputText: "Demo2026!" +- tapOn: "Sign In" +- assertVisible: "Home" diff --git a/apps/mobile/apps/client/maestro/signup.yaml b/apps/mobile/apps/client/maestro/signup.yaml new file mode 100644 index 00000000..eba61eb0 --- /dev/null +++ b/apps/mobile/apps/client/maestro/signup.yaml @@ -0,0 +1,23 @@ +# Client App - Sign Up Flow +# Prerequisites: App built and installed +# Run: maestro test apps/mobile/apps/client/maestro/signup.yaml +# Use NEW credentials for signup (creates new account) +# Env: MAESTRO_CLIENT_EMAIL, MAESTRO_CLIENT_PASSWORD, MAESTRO_CLIENT_COMPANY + +appId: com.krowwithus.client +--- +- launchApp +- assertVisible: "Create Account" +- tapOn: "Create Account" +- assertVisible: "Company" +- tapOn: "Company" +- inputText: "${MAESTRO_CLIENT_COMPANY}" +- tapOn: "Email" +- inputText: "${MAESTRO_CLIENT_EMAIL}" +- tapOn: "Password" +- inputText: "${MAESTRO_CLIENT_PASSWORD}" +- tapOn: + text: "Confirm Password" +- inputText: "${MAESTRO_CLIENT_PASSWORD}" +- tapOn: "Create Account" +- assertVisible: "Home" diff --git a/apps/mobile/apps/client/pubspec.yaml b/apps/mobile/apps/client/pubspec.yaml index b4d6367b..31c14ec3 100644 --- a/apps/mobile/apps/client/pubspec.yaml +++ b/apps/mobile/apps/client/pubspec.yaml @@ -42,6 +42,7 @@ dependencies: sdk: flutter firebase_core: ^4.4.0 krow_data_connect: ^0.0.1 + marionette_flutter: ^0.3.0 dev_dependencies: flutter_test: diff --git a/apps/mobile/apps/staff/lib/main.dart b/apps/mobile/apps/staff/lib/main.dart index d127d3e1..91f1e952 100644 --- a/apps/mobile/apps/staff/lib/main.dart +++ b/apps/mobile/apps/staff/lib/main.dart @@ -1,7 +1,11 @@ +import 'dart:io' show Platform; + import 'package:core_localization/core_localization.dart' as core_localization; import 'package:design_system/design_system.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:marionette_flutter/marionette_flutter.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_modular/flutter_modular.dart'; @@ -15,7 +19,23 @@ import 'package:krow_core/core.dart'; import 'src/widgets/session_listener.dart'; void main() async { - WidgetsFlutterBinding.ensureInitialized(); + final bool isFlutterTest = + !kIsWeb ? Platform.environment.containsKey('FLUTTER_TEST') : false; + if (kDebugMode && !isFlutterTest) { + MarionetteBinding.ensureInitialized( + MarionetteConfiguration( + isInteractiveWidget: (Type type) => + type == UiButton || type == UiTextField, + extractText: (Widget widget) { + if (widget is UiTextField) return widget.label; + if (widget is UiButton) return widget.text; + return null; + }, + ), + ); + } else { + WidgetsFlutterBinding.ensureInitialized(); + } await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); // Register global BLoC observer for centralized error logging diff --git a/apps/mobile/apps/staff/maestro/README.md b/apps/mobile/apps/staff/maestro/README.md new file mode 100644 index 00000000..505faaec --- /dev/null +++ b/apps/mobile/apps/staff/maestro/README.md @@ -0,0 +1,41 @@ +# Maestro Integration Tests — Staff App + +Login and signup flows for the KROW Staff app. +See [docs/research/flutter-testing-tools.md](/docs/research/flutter-testing-tools.md) for the evaluation report. +**Full run instructions:** [docs/research/maestro-test-run-instructions.md](/docs/research/maestro-test-run-instructions.md) + +## Prerequisites + +- [Maestro CLI](https://maestro.dev/docs/getting-started/installation) installed +- Staff app built and installed +- **Firebase test phone** in Firebase Console (Auth > Sign-in method > Phone): + - Login: +1 555-765-4321 / OTP 123456 + - Signup: add a different test number for new accounts + +## Credentials + +| Flow | Credentials | +|------|-------------| +| **Client login** | legendary@krowd.com / Demo2026! | +| **Staff login** | 5557654321 / OTP 123456 | +| **Client signup** | Env vars: `MAESTRO_CLIENT_EMAIL`, `MAESTRO_CLIENT_PASSWORD`, `MAESTRO_CLIENT_COMPANY` | +| **Staff signup** | Env var: `MAESTRO_STAFF_SIGNUP_PHONE` (must be new Firebase test phone) | + +## Run + +From the project root: + +```bash +# Login +maestro test apps/mobile/apps/staff/maestro/login.yaml + +# Signup +maestro test apps/mobile/apps/staff/maestro/signup.yaml +``` + +## Flows + +| File | Flow | Description | +|------------|------------|-------------------------------------| +| login.yaml | Staff Login| Get Started → Log In → Phone → OTP → Home | +| signup.yaml| Staff Signup| Get Started → Sign Up → Phone → OTP → Profile Setup | diff --git a/apps/mobile/apps/staff/maestro/login.yaml b/apps/mobile/apps/staff/maestro/login.yaml new file mode 100644 index 00000000..aa0b21a1 --- /dev/null +++ b/apps/mobile/apps/staff/maestro/login.yaml @@ -0,0 +1,18 @@ +# Staff App - Login Flow (Phone + OTP) +# Prerequisites: App built and installed; Firebase test phone configured +# Firebase test phone: +1 555-765-4321 / OTP 123456 +# Run: maestro test apps/mobile/apps/staff/maestro/login.yaml + +appId: com.krowwithus.staff +--- +- launchApp +- assertVisible: "Log In" +- tapOn: "Log In" +- assertVisible: "Send Code" +- inputText: "5557654321" +- tapOn: "Send Code" +# Wait for OTP screen +- assertVisible: "Continue" +- inputText: "123456" +- tapOn: "Continue" +# On success: staff main. Adjust final assertion to match staff home screen. diff --git a/apps/mobile/apps/staff/maestro/signup.yaml b/apps/mobile/apps/staff/maestro/signup.yaml new file mode 100644 index 00000000..e441e774 --- /dev/null +++ b/apps/mobile/apps/staff/maestro/signup.yaml @@ -0,0 +1,18 @@ +# Staff App - Sign Up Flow (Phone + OTP) +# Prerequisites: App built and installed; Firebase test phone for NEW number +# Use a NEW phone number for signup (creates new account) +# Firebase: add test phone in Auth > Phone; e.g. +1 555-555-0000 / 123456 +# Run: maestro test apps/mobile/apps/staff/maestro/signup.yaml + +appId: com.krowwithus.staff +--- +- launchApp +- assertVisible: "Sign Up" +- tapOn: "Sign Up" +- assertVisible: "Send Code" +- inputText: "${MAESTRO_STAFF_SIGNUP_PHONE}" +- tapOn: "Send Code" +- assertVisible: "Continue" +- inputText: "123456" +- tapOn: "Continue" +# On success: Profile Setup. Adjust assertion to match destination. diff --git a/apps/mobile/apps/staff/pubspec.yaml b/apps/mobile/apps/staff/pubspec.yaml index d3b270ef..4019f01b 100644 --- a/apps/mobile/apps/staff/pubspec.yaml +++ b/apps/mobile/apps/staff/pubspec.yaml @@ -30,6 +30,7 @@ dependencies: path: ../../packages/core krow_data_connect: path: ../../packages/data_connect + marionette_flutter: ^0.3.0 cupertino_icons: ^1.0.8 flutter_modular: ^6.3.0 firebase_core: ^4.4.0 diff --git a/apps/mobile/pubspec.lock b/apps/mobile/pubspec.lock index 9aa8910e..777d1470 100644 --- a/apps/mobile/pubspec.lock +++ b/apps/mobile/pubspec.lock @@ -813,6 +813,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.257.0" + marionette_flutter: + dependency: transitive + description: + name: marionette_flutter + sha256: "0077073f62a8031879a91be41aa91629f741a7f1348b18feacd53443dae3819f" + url: "https://pub.dev" + source: hosted + version: "0.3.0" matcher: dependency: transitive description: diff --git a/docs/research/flutter-testing-tools.md b/docs/research/flutter-testing-tools.md index f7fccba0..d7cde701 100644 --- a/docs/research/flutter-testing-tools.md +++ b/docs/research/flutter-testing-tools.md @@ -68,11 +68,17 @@ Semantics( ) ``` -### Phase 2: Repository Structure -Tests will be localized within the respective app directories to maintain modularity: +### Phase 2: Repository Structure (Implemented) +Maestro flows are co-located with each app: -* `apps/mobile/apps/client/maestro/` -* `apps/mobile/apps/staff/maestro/` +* `apps/mobile/apps/client/maestro/login.yaml` — Client login +* `apps/mobile/apps/client/maestro/signup.yaml` — Client signup +* `apps/mobile/apps/staff/maestro/login.yaml` — Staff login (phone + OTP) +* `apps/mobile/apps/staff/maestro/signup.yaml` — Staff signup (phone + OTP) + +Each directory has a README with run instructions. + +**Marionette MCP:** `marionette_flutter` is added to both apps; `MarionetteBinding` is initialized in debug mode. See [marionette-spike-usage.md](marionette-spike-usage.md) for prompts and workflow. ### Phase 3: CI/CD Integration The Maestro CLI will be added to our **GitHub Actions** workflow to automate quality gates. diff --git a/docs/research/maestro-test-run-instructions.md b/docs/research/maestro-test-run-instructions.md new file mode 100644 index 00000000..a4fb80e7 --- /dev/null +++ b/docs/research/maestro-test-run-instructions.md @@ -0,0 +1,84 @@ +# How to Run Maestro Integration Tests + +## Credentials + +| Flow | Credentials | +|------|-------------| +| **Client login** | legendary@krowd.com / Demo2026! | +| **Staff login** | 5557654321 / OTP 123456 | +| **Client signup** | Env vars: `MAESTRO_CLIENT_EMAIL`, `MAESTRO_CLIENT_PASSWORD`, `MAESTRO_CLIENT_COMPANY` | +| **Staff signup** | Env var: `MAESTRO_STAFF_SIGNUP_PHONE` (must be new Firebase test phone) | + +--- + +## Step-by-step: Run login tests + +### 1. Install Maestro CLI + +```bash +curl -Ls "https://get.maestro.mobile.dev" | bash +``` + +Or: https://maestro.dev/docs/getting-started/installation + +### 2. Add Firebase test phone (Staff app only) + +In [Firebase Console](https://console.firebase.google.com) → your project → **Authentication** → **Sign-in method** → **Phone** → **Phone numbers for testing**: + +- Add: **+1 5557654321** with verification code **123456** + +### 3. Build and install the apps + +From the **project root**: + +```bash +# Client +make mobile-client-build PLATFORM=apk MODE=debug +adb install apps/mobile/apps/client/build/app/outputs/flutter-apk/app-debug.apk + +# Staff +make mobile-staff-build PLATFORM=apk MODE=debug +adb install apps/mobile/apps/staff/build/app/outputs/flutter-apk/app-debug.apk +``` + +Or run the app on a connected device/emulator: `make mobile-client-dev-android DEVICE=` (then Maestro can launch the already-installed app by appId). + +### 4. Run Maestro tests + +From the **project root** (`e:\Krow-google\krow-workforce`): + +```bash +# Client login (uses legendary@krowd.com / Demo2026!) +maestro test apps/mobile/apps/client/maestro/login.yaml + +# Staff login (uses 5557654321 / OTP 123456) +maestro test apps/mobile/apps/staff/maestro/login.yaml +``` + +### 5. Run signup tests (optional) + +**Client signup** — set env vars first: +```bash +$env:MAESTRO_CLIENT_EMAIL="newuser@example.com" +$env:MAESTRO_CLIENT_PASSWORD="YourPassword123!" +$env:MAESTRO_CLIENT_COMPANY="Test Company" +maestro test apps/mobile/apps/client/maestro/signup.yaml +``` + +**Staff signup** — use a new Firebase test phone: +```bash +# Add +1 555-555-0000 / 123456 in Firebase, then: +$env:MAESTRO_STAFF_SIGNUP_PHONE="5555550000" +maestro test apps/mobile/apps/staff/maestro/signup.yaml +``` + +--- + +## Checklist + +- [ ] Maestro CLI installed +- [ ] Firebase test phone +1 5557654321 / 123456 added (for staff) +- [ ] Client app built and installed +- [ ] Staff app built and installed +- [ ] Run from project root: `maestro test apps/mobile/apps/client/maestro/login.yaml` +- [ ] Run from project root: `maestro test apps/mobile/apps/staff/maestro/login.yaml` diff --git a/docs/research/marionette-spike-usage.md b/docs/research/marionette-spike-usage.md new file mode 100644 index 00000000..09553e89 --- /dev/null +++ b/docs/research/marionette-spike-usage.md @@ -0,0 +1,58 @@ +# Marionette MCP Spike — Usage Guide + +**Issue:** #533 +**Purpose:** Document how to run the Marionette MCP spike for auth flows. + +## Prerequisites + +1. **Marionette MCP server** — Install globally: + ```bash + dart pub global activate marionette_mcp + ``` + +2. **Add Marionette to Cursor** — In `.cursor/mcp.json` or global config: + ```json + { + "mcpServers": { + "marionette": { + "command": "marionette_mcp", + "args": [] + } + } + } + ``` + +3. **Run app in debug mode** — The app must be running with VM Service: + ```bash + cd apps/mobile && flutter run -d + ``` + +4. **Get VM Service URI** — From the `flutter run` output, copy the `ws://127.0.0.1:XXXX/ws` URI (often shown in the DevTools link). + +## Spike flows (AI agent prompts) + +Use these prompts with the Marionette MCP connected to the running app. + +### Client — Login + +> Connect to the app using the VM Service URI. Navigate to the Get Started screen, tap "Sign In", enter legendary@krowd.com and Demo2026!, then tap "Sign In". Verify we land on the home screen. + +### Client — Sign up + +> Connect to the app. Tap "Create Account", fill in Company, Email, Password (and confirm) with new credentials, then tap "Create Account". Verify we land on the home screen. + +### Staff — Login + +> Connect to the app. Tap "Log In", enter phone number 5557654321, tap "Send Code", enter OTP 123456, tap "Continue". Verify we reach the staff home screen. +> (Firebase test phone: +1 555-765-4321 / OTP 123456) + +### Staff — Sign up + +> Connect to the app. Tap "Sign Up", enter a NEW phone number (Firebase test phone), tap "Send Code", enter OTP, tap "Continue". Verify we reach Profile Setup or staff home. + +## Limitations observed (from spike) + +- **Debug only** — Marionette needs the Dart VM Service; does not work with release builds. +- **Non-deterministic** — LLM-driven actions can vary in behavior and timing. +- **Latency** — Each step involves API roundtrips (~45s+ for full flow vs ~5s for Maestro). +- **Best use** — Exploratory testing, live debugging, smoke checks during development.