maestro improvise

This commit is contained in:
2026-03-09 22:10:40 +05:30
parent 91cedf54c9
commit 52bb1d1af4
53 changed files with 903 additions and 452 deletions

View File

@@ -0,0 +1,56 @@
# Client App — E2E: Session Persistence Across Relaunch
# Purpose:
# - Log in via sign_in.yaml
# - Stop the app
# - Relaunch and verify user is still logged in (bypass login screen)
#
# Run:
# maestro test \
# apps/mobile/apps/client/maestro/auth/sign_in.yaml \
# apps/mobile/apps/client/maestro/auth/session_persistence.yaml \
# -e TEST_CLIENT_EMAIL=... \
# -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client
---
# We rely on sign_in.yaml being run before this to establish a session.
- launchApp
# If we are logged in, Home/Orders content should be visible directly.
- extendedWaitUntil:
visible: "(?i).*(Home|Orders|Welcome).*"
timeout: 15000
# Perform a full stop to clear memory (not just backgrounding)
- stopApp
# Relaunch - should NOT show the login screen
- launchApp
- extendedWaitUntil:
visible: "(?i).*(Home|Orders|Welcome).*"
timeout: 15000
# Verification: Log out to ensure clean state for next test
# Open Settings via header gear icon (top-right)
- tapOn:
point: "92%,10%"
- extendedWaitUntil:
visible: "(?i).*Logout.*"
timeout: 10000
- tapOn: "(?i).*Logout.*"
# Confirm Log Out
- tapOn:
text: "(?i).*(Yes|Confirm).*(Logout|Log Out).*"
optional: true
# Should return to the sign in landing page
- extendedWaitUntil:
visible: "(?i)Sign In"
timeout: 10000
- assertVisible: "(?i)Sign In"

View File

@@ -1,22 +1,51 @@
# Client App — Sign In flow # Client App — Sign In flow
# Credentials via env: TEST_CLIENT_EMAIL, TEST_CLIENT_PASSWORD
# Run: maestro test apps/mobile/apps/client/maestro/auth/sign_in.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
# Or: export MAESTRO_TEST_CLIENT_EMAIL / MAESTRO_TEST_CLIENT_PASSWORD (Maestro auto-reads MAESTRO_*)
appId: com.krowwithus.client appId: com.krowwithus.client
env: env:
EMAIL: ${TEST_CLIENT_EMAIL} EMAIL: ${TEST_CLIENT_EMAIL}
PASSWORD: ${TEST_CLIENT_PASSWORD} PASSWORD: ${TEST_CLIENT_PASSWORD}
--- ---
- launchApp - launchApp:
- assertVisible: "Sign In" clearState: true
- tapOn: "Sign In" - extendedWaitUntil:
- assertVisible: "Email" visible:
text: "(?i).*(Sign In|Log In|Welcome).*"
timeout: 45000
# Try tap by both ID and Text for maximum reliability
- tapOn: - tapOn:
id: sign_in_email id: "client_landing_sign_in"
optional: true
- tapOn:
text: "(?i)Sign In"
optional: true
- extendedWaitUntil:
visible: "(?i)Email"
timeout: 20000
- tapOn:
id: "sign_in_email"
- inputText: ${EMAIL} - inputText: ${EMAIL}
- tapOn: - tapOn:
id: sign_in_password id: "sign_in_password"
- inputText: ${PASSWORD} - inputText: ${PASSWORD}
- tapOn: "Sign In"
- assertVisible: "Home" # In the form, just tap Sign In text
- tapOn:
text: "(?i)Sign In"
- hideKeyboard
- extendedWaitUntil:
visible: "(?i).*(Home|Orders|Welcome).*"
timeout: 45000
# Final check: ensure the bottom nav is rendered before finishing
- extendedWaitUntil:
visible:
id: "client_nav_home"
timeout: 15000
optional: true
- assertVisible: "(?i).*(Home|Orders|Welcome).*"

View File

@@ -21,3 +21,6 @@ env:
visible: "Invalid" visible: "Invalid"
timeout: 5000 timeout: 5000
- assertVisible: "Sign In" - assertVisible: "Sign In"

View File

@@ -20,3 +20,6 @@ appId: com.krowwithus.client
- extendedWaitUntil: - extendedWaitUntil:
visible: "Create Account" visible: "Create Account"
timeout: 20000 timeout: 20000

View File

@@ -33,3 +33,6 @@ env:
- inputText: ${PASSWORD} - inputText: ${PASSWORD}
- tapOn: "Create Account" - tapOn: "Create Account"
- assertVisible: "Home" - assertVisible: "Home"

View File

@@ -1,23 +1,20 @@
# Client App — Billing tab overview widgets # Client App — Billing overview
# Verifies Billing tab navigation plus key billing metrics/sections.
# Run:
# maestro test \
# apps/mobile/apps/client/maestro/auth/sign_in.yaml \
# apps/mobile/apps/client/maestro/billing/billing_overview.yaml \
# -e TEST_CLIENT_EMAIL=... \
# -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
clearState: false
# Navigate to Billing tab - extendedWaitUntil:
- tapOn: "Billing" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil: - extendedWaitUntil:
visible: "Current Period" visible: "(?i)Billing"
timeout: 10000 timeout: 30000
# Verify key labels from client_billing translations that always appear - tapOn: "(?i)Billing"
- assertVisible: "Current Period"
- extendedWaitUntil:
visible: "(?i)Current Period"
timeout: 20000
- assertVisible: "(?i)Current Period"

View File

@@ -51,3 +51,18 @@ appId: com.krowwithus.client
- extendedWaitUntil: - extendedWaitUntil:
visible: "Invoice approved and payment initiated" visible: "Invoice approved and payment initiated"
timeout: 15000 timeout: 15000
# Post-Action State Verification:
# After approval, we confirm we are back on the 'Invoices' screen and the count has updated (or the item is gone)
- extendedWaitUntil:
visible: "Awaiting Approval"
timeout: 10000
# Optionally, verify the 'Review & Approve' button for that specific invoice is gone.
- assertNotVisible:
text: "Review & Approve"
optional: true

View File

@@ -21,22 +21,30 @@ appId: com.krowwithus.client
timeout: 10000 timeout: 10000
# If there are invoices ready, open one and verify details actions (optional) # If there are invoices ready, open one and verify details actions (optional)
- tapOn: "Invoice Ready" - tapOn:
optional: true text: "Invoice Ready"
optional: true
- extendedWaitUntil: - extendedWaitUntil:
visible: "Download Invoice PDF" visible: "Download Invoice PDF"
timeout: 10000 timeout: 10000
optional: true optional: true
- assertVisible: "Download Invoice PDF" - assertVisible:
optional: true text: "Download Invoice PDF"
optional: true
# Otherwise, validate deterministic empty states (still a valid smoke outcome) # Otherwise, validate deterministic empty states (still a valid smoke outcome)
- assertVisible: "No invoices ready yet" - assertVisible:
optional: true text: "No invoices ready yet"
optional: true
- assertVisible: "No Invoices for the selected period" - assertVisible:
optional: true text: "No Invoices for the selected period"
optional: true
# Always end by asserting we are still in Billing context # Always end by asserting we are still in Billing context
- assertVisible: "Current Period" - assertVisible: "Current Period"

View File

@@ -1,45 +1,35 @@
# Client App — Home dashboard widgets & quick actions # Client App — Home dashboard widgets & quick actions
# Verifies key widgets (Actions, Coverage, Spending, Live Activity) render
# and that Actions quick links can navigate into create order.
# Run:
# maestro test \
# apps/mobile/apps/client/maestro/auth/sign_in.yaml \
# apps/mobile/apps/client/maestro/home/home_dashboard_widgets.yaml \
# -e TEST_CLIENT_EMAIL=... \
# -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
clearState: false
# Make sure we're on the Home tab and content has loaded
- tapOn: "Home"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Welcome back" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 15000 timeout: 45000
- extendedWaitUntil: - extendedWaitUntil:
visible: "Create Order\\nSchedule shifts" visible: "(?i)Home"
timeout: 30000
- tapOn: "(?i)Home"
- extendedWaitUntil:
visible: "(?i).*(Welcome back|Home).*"
timeout: 20000 timeout: 20000
# Note: In normal mode the dashboard widgets do NOT render section titles - extendedWaitUntil:
# like "Quick Actions" (those titles only exist in edit mode wrappers). visible: "(?i)Create Order.*Schedule.*"
# So we assert on the always-present action cards instead. timeout: 30000
# Verify Actions widget buttons via accessibility labels (they include subtitle on new line) - assertVisible: "(?i)RAPID.*Urgent.*"
- assertVisible: "RAPID\\nUrgent same-day" - assertVisible: "(?i)Create Order.*Schedule.*"
- assertVisible: "Create Order\\nSchedule shifts"
# Open Create Order from Home quick action and verify we reach Create Order screen - tapOn: "(?i)Create Order.*Schedule.*"
- tapOn: "Create Order\\nSchedule shifts"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Create Order" visible: "(?i)Create Order"
timeout: 10000 timeout: 15000
- assertVisible: "ORDER TYPE"
- assertVisible: "RAPID\\nURGENT same-day Coverage"
- assertVisible: "One-Time\\nSingle Event or Shift Request"
- assertVisible: "Recurring\\nOngoing Weekly / Monthly Coverage"
- assertVisible: "Permanent\\nLong-Term Staffing Placement"
- assertVisible: "(?i)ORDER TYPE"
- assertVisible: "(?i)RAPID.*URGENT.*"
- assertVisible: "(?i)One-Time.*Single Event.*"

View File

@@ -37,3 +37,7 @@ appId: com.krowwithus.client
- tapOn: "Home" - tapOn: "Home"
- assertVisible: "Welcome back" - assertVisible: "Welcome back"

View File

@@ -60,3 +60,15 @@ appId: com.krowwithus.client
visible: "Hubs\nManage clock-in locations" visible: "Hubs\nManage clock-in locations"
timeout: 20000 timeout: 20000
# Post-Action State Verification:
# Verify the newly created hub name is in the list
- scrollUntilVisible:
element: "E2E Hub Automation"
visibilityPercentage: 50
timeout: 10000
- assertVisible: "E2E Hub Automation"

View File

@@ -78,3 +78,7 @@ appId: com.krowwithus.client
visible: "Hub deleted successfully" visible: "Hub deleted successfully"
timeout: 15000 timeout: 15000

View File

@@ -84,3 +84,7 @@ appId: com.krowwithus.client
visible: "Hub updated successfully" visible: "Hub updated successfully"
timeout: 15000 timeout: 15000

View File

@@ -1,60 +1,49 @@
# Client App — Manage Hubs via Settings quick link # Client App — Manage Hubs via Settings quick link
# Covers navigation from Settings → Clock-In Hubs, basic Hubs page content,
# and Add Hub form validation messages.
# Run:
# maestro test \
# apps/mobile/apps/client/maestro/auth/sign_in.yaml \
# apps/mobile/apps/client/maestro/hubs/manage_hubs_from_settings.yaml \
# -e TEST_CLIENT_EMAIL=... \
# -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
clearState: false
# Ensure we're on Home (where the gear icon exists in header)
- tapOn: "Home"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Welcome back" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil:
visible: "(?i)Home"
timeout: 30000
- tapOn: "(?i)Home"
- extendedWaitUntil:
visible: "(?i).*(Welcome back|Home).*"
timeout: 20000
# Open Settings via stable semantic ID
- tapOn:
id: "client_home_settings"
- extendedWaitUntil:
visible: "(?i).*Quick Links.*"
timeout: 20000
- assertVisible: "(?i)Profile"
- assertVisible: "(?i)Clock-In Hubs"
- tapOn: "(?i)Clock-In Hubs"
- extendedWaitUntil:
visible: "(?i).*Hubs.*"
timeout: 15000 timeout: 15000
# Open Settings from the main shell header (gear icon, top-right) - assertVisible: "(?i).*Add Hub.*"
- tapOn:
point: "92%,10%"
# Wait for Settings content to load (profile + quick links) - tapOn: "(?i)Add Hub"
- extendedWaitUntil:
visible: "Quick Links"
timeout: 10000
- assertVisible: "Profile"
- assertVisible: "Clock-In Hubs"
# Open Clock-In Hubs from quick links
- tapOn: "Clock-In Hubs"
# Verify Hubs main page content
- extendedWaitUntil:
visible: "Hubs\nManage clock-in locations"
timeout: 10000
- assertVisible: "Hubs\nManage clock-in locations"
- assertVisible: "About Hubs\nHubs are clock-in stations at your locations. Assign NFC tags to each hub so workers can quickly clock in/out using their phones."
- assertVisible: "Add Hub"
# Open Add Hub dialog / page
- tapOn: "Add Hub"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Add New Hub" visible: "(?i)Add New Hub"
timeout: 10000 timeout: 10000
- assertVisible: "Add New Hub" - tapOn: "(?i)Create Hub"
- assertVisible: "Hub Name *"
- assertVisible: "Address"
- assertVisible: "Cost Center"
# Try to submit empty form to trigger validation - extendedWaitUntil:
- tapOn: "Create Hub" visible: "(?i).*required.*"
timeout: 5000
- assertVisible: "Name is required"

View File

@@ -1,7 +1,20 @@
# Client App — Billing tab navigation # Client App — Billing tab navigation
# Run: maestro test auth/sign_in.yaml navigation/billing.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
- tapOn: "Billing" clearState: false
- assertVisible: "Billing" - extendedWaitUntil:
visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil:
visible: "(?i)Billing"
timeout: 30000
- tapOn: "(?i)Billing"
- extendedWaitUntil:
visible: "(?i).*(Current Period|Billing).*"
timeout: 20000
- assertVisible: "(?i).*(Current Period|Billing).*"

View File

@@ -1,7 +1,20 @@
# Client App — Coverage tab navigation # Client App — Coverage tab navigation
# Run: maestro test auth/sign_in.yaml navigation/coverage.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
- tapOn: "Coverage" clearState: false
- assertVisible: "Coverage" - extendedWaitUntil:
visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil:
visible: "(?i)Coverage"
timeout: 30000
- tapOn: "(?i)Coverage"
- extendedWaitUntil:
visible: "(?i).*(Today.*Status|Daily Coverage|Unfilled|Checked In).*"
timeout: 20000
- assertVisible: "(?i).*(Today.*Status|Daily Coverage|Unfilled|Checked In).*"

View File

@@ -1,6 +1,20 @@
# Client App — Home tab (default after sign-in) # Client App — Home tab navigation
# Run: maestro test auth/sign_in.yaml navigation/home.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
- assertVisible: "Orders" clearState: false
- extendedWaitUntil:
visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil:
visible: "(?i)Home"
timeout: 30000
- tapOn: "(?i)Home"
- extendedWaitUntil:
visible: "(?i).*(Welcome back|Create Order|RAPID).*"
timeout: 20000
- assertVisible: "(?i).*(Welcome back|Create Order|RAPID).*"

View File

@@ -1,7 +1,20 @@
# Client App — Orders tab navigation # Client App — Orders tab navigation
# Run: maestro test auth/sign_in.yaml navigation/orders.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
- tapOn: "Orders" clearState: false
- assertVisible: "Orders" - extendedWaitUntil:
visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil:
visible: "(?i)Orders"
timeout: 30000
- tapOn: "(?i)Orders"
- extendedWaitUntil:
visible: "(?i).*(Up Next|Post an Order).*"
timeout: 20000
- assertVisible: "(?i).*(Up Next|Post an Order).*"

View File

@@ -1,7 +1,20 @@
# Client App — Reports tab navigation # Client App — Reports tab navigation
# Run: maestro test auth/sign_in.yaml navigation/reports.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
- tapOn: "Reports" clearState: false
- assertVisible: "Reports" - extendedWaitUntil:
visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil:
visible: "(?i)Reports"
timeout: 30000
- tapOn: "(?i)Reports"
- extendedWaitUntil:
visible: "(?i)Workforce Control Tower"
timeout: 20000
- assertVisible: "(?i)Workforce Control Tower"

View File

@@ -1,14 +1,26 @@
# Client App — Completed tab: edit icon hidden for past/completed orders (#492) # Client App — Completed tab: edit icon hidden for past/completed orders (#492)
# Run: maestro test auth/sign_in.yaml orders/completed_no_edit_icon.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
- tapOn: "Orders" clearState: false
- extendedWaitUntil: - extendedWaitUntil:
visible: "Orders" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 10000 timeout: 45000
- extendedWaitUntil: - extendedWaitUntil:
visible: "Completed.*" visible: "(?i)Orders"
timeout: 30000
- tapOn: "(?i)Orders"
- extendedWaitUntil:
visible: "(?i)Orders"
timeout: 15000
- extendedWaitUntil:
visible: "(?i)Completed.*"
timeout: 10000 timeout: 10000
- tapOn: "Completed.*"
- assertVisible: "Completed.*" - tapOn: "(?i)Completed.*"
- assertVisible: "(?i)Completed.*"

View File

@@ -1,24 +1,30 @@
# Client App — Create order flow entry (tap Post, see order type selection) # Client App — Create order flow entry
# Run: maestro test auth/sign_in.yaml orders/create_order_entry.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
clearState: false
# Ensure we are on Home, then open Create Order from the Home quick action - extendedWaitUntil:
- tapOn: "Home" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil: - extendedWaitUntil:
visible: "Welcome back" visible: "(?i)Home"
timeout: 15000 timeout: 30000
- tapOn: "(?i)Home"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Create Order\\nSchedule shifts" visible: "(?i).*(Welcome back|Home).*"
timeout: 20000 timeout: 20000
- tapOn: "Create Order\\nSchedule shifts" - extendedWaitUntil:
visible: "(?i)Create Order.*Schedule.*"
timeout: 20000
- tapOn: "(?i)Create Order.*Schedule.*"
- extendedWaitUntil: - extendedWaitUntil:
visible: "ORDER TYPE" visible: "(?i)ORDER TYPE"
timeout: 10000 timeout: 10000
- assertVisible: "RAPID\\nURGENT same-day Coverage" - assertVisible: "(?i)RAPID.*URGENT.*"

View File

@@ -1,48 +1,38 @@
# Client App — Create One-Time Order flow (layout + basic navigation) # Client App — Create One-Time Order flow
# Covers navigation from Orders tab → Post action → One-Time order type
# and verifies core One-Time order form fields are present.
# Run:
# maestro test \
# apps/mobile/apps/client/maestro/auth/sign_in.yaml \
# apps/mobile/apps/client/maestro/orders/create_order_one_time.yaml \
# -e TEST_CLIENT_EMAIL=... \
# -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
clearState: false
# Ensure we are on Home, then open Create Order from the Home quick action - extendedWaitUntil:
- tapOn: "Home" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil: - extendedWaitUntil:
visible: "Welcome back" visible: "(?i)Home"
timeout: 15000 timeout: 30000
- tapOn: "(?i)Home"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Create Order\\nSchedule shifts" visible: "(?i).*(Welcome back|Home).*"
timeout: 20000 timeout: 20000
- tapOn: "Create Order\\nSchedule shifts"
# Select the One-Time order type (label from client_create_order.types.one_time)
- extendedWaitUntil: - extendedWaitUntil:
visible: "One-Time\\nSingle Event or Shift Request" visible: "(?i)Create Order.*Schedule.*"
timeout: 30000
- tapOn: "(?i)Create Order.*Schedule.*"
- extendedWaitUntil:
visible: "(?i)One-Time.*Single Event.*"
timeout: 10000 timeout: 10000
- tapOn: "One-Time\\nSingle Event or Shift Request" - tapOn: "(?i)One-Time.*Single Event.*"
# Verify One-Time Order form header and key fields
- extendedWaitUntil: - extendedWaitUntil:
visible: "One-Time Order" visible: "(?i)One-Time Order"
timeout: 10000 timeout: 15000
- assertVisible: "Create Your Order"
- assertVisible: "SELECT VENDOR"
- assertVisible: "Date"
- assertVisible: "HUB"
- assertVisible: "Shift Contact\\nOn-site manager or supervisor for this shift\\nSelect Contact"
- assertVisible: "Positions"
- assertVisible: "Add Position"
- assertVisible: "Create Order"
- assertVisible: "(?i)Create Your Order"
- assertVisible: "(?i).*(SELECT VENDOR|Date|HUB|Positions).*"
- assertVisible: "(?i)Create Order"

View File

@@ -55,4 +55,8 @@ appId: com.krowwithus.client
# Success screen shows "Order received." or similar success title/message # Success screen shows "Order received." or similar success title/message
- extendedWaitUntil: - extendedWaitUntil:
visible: "Test E2E Event" # or success message, assuming it goes back to Orders or shows Success Screen visible: "Test E2E Event" # or success message, assuming it goes back to Orders or shows Success Screen
timeout: 30000 timeout: 45000

View File

@@ -33,3 +33,7 @@ appId: com.krowwithus.client
timeout: 10000 timeout: 10000
- assertVisible: "Permanent Order" - assertVisible: "Permanent Order"

View File

@@ -1,47 +1,39 @@
# Client App — Create Rapid Order flow (UI smoke) # Client App — Create Rapid Order flow (UI smoke)
# Starts from Home quick action, opens Create Order, selects RAPID, and
# verifies core Rapid order fields and actions are present.
# Run:
# maestro test \
# apps/mobile/apps/client/maestro/auth/sign_in.yaml \
# apps/mobile/apps/client/maestro/home/home_dashboard_widgets.yaml \
# apps/mobile/apps/client/maestro/orders/create_order_rapid.yaml \
# -e TEST_CLIENT_EMAIL=... \
# -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
clearState: false
# Open Create Order from Home quick action (most reliable entry point) - extendedWaitUntil:
- tapOn: "Home" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil: - extendedWaitUntil:
visible: "Welcome back" visible: "(?i)Home"
timeout: 15000 timeout: 30000
- tapOn: "(?i)Home"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Create Order\\nSchedule shifts" visible: "(?i).*(Welcome back|Home).*"
timeout: 20000 timeout: 20000
- tapOn: "Create Order\\nSchedule shifts" - extendedWaitUntil:
visible: "(?i)Create Order.*Schedule.*"
timeout: 30000
- tapOn: "(?i)Create Order.*Schedule.*"
- extendedWaitUntil: - extendedWaitUntil:
visible: "ORDER TYPE" visible: "(?i)ORDER TYPE"
timeout: 10000 timeout: 10000
- assertVisible: "RAPID\\nURGENT same-day Coverage" - assertVisible: "(?i)RAPID.*URGENT.*"
# Select RAPID order type - tapOn: "(?i)RAPID.*URGENT.*"
- tapOn: "RAPID\\nURGENT same-day Coverage"
- extendedWaitUntil: - extendedWaitUntil:
visible: "RAPID Order" visible: "(?i)RAPID Order"
timeout: 10000 timeout: 15000
- assertVisible: "Emergency staffing in minutes"
- assertVisible: "Need staff urgently?"
- assertVisible: "Type or speak what you need. I'll handle the rest"
- assertVisible: "Send Message"
- assertVisible: "Speak"
- assertVisible: "(?i)Emergency staffing in minutes"
- assertVisible: "(?i).*(Send Message|Speak).*"

View File

@@ -33,3 +33,7 @@ appId: com.krowwithus.client
timeout: 10000 timeout: 10000
- assertVisible: "Recurring Order" - assertVisible: "Recurring Order"

View File

@@ -65,3 +65,7 @@ appId: com.krowwithus.client
- extendedWaitUntil: - extendedWaitUntil:
notVisible: "Confirm & Save" notVisible: "Confirm & Save"
timeout: 15000 timeout: 15000

View File

@@ -64,3 +64,7 @@ appId: com.krowwithus.client
visible: "Orders" visible: "Orders"
timeout: 15000 timeout: 15000

View File

@@ -30,3 +30,7 @@ appId: com.krowwithus.client
- assertVisible: "Recurring\nOngoing Weekly / Monthly Coverage" - assertVisible: "Recurring\nOngoing Weekly / Monthly Coverage"
- assertVisible: "Permanent\nLong-Term Staffing Placement" - assertVisible: "Permanent\nLong-Term Staffing Placement"

View File

@@ -44,3 +44,7 @@ appId: com.krowwithus.client
- assertVisible: "Send Message" - assertVisible: "Send Message"

View File

@@ -46,3 +46,7 @@ appId: com.krowwithus.client
timeout: 60000 timeout: 60000
- assertVisible: "Select Role" - assertVisible: "Select Role"

View File

@@ -1,15 +1,26 @@
# Client App — View Orders page with filter tabs # Client App — View Orders page with filter tabs
# Run: maestro test auth/sign_in.yaml orders/view_orders.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
- tapOn: "Orders" clearState: false
- extendedWaitUntil: - extendedWaitUntil:
visible: "Orders" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 10000 timeout: 45000
- extendedWaitUntil: - extendedWaitUntil:
visible: "Up Next.*" visible: "(?i)Orders"
timeout: 30000
- tapOn: "(?i)Orders"
- extendedWaitUntil:
visible: "(?i)Orders"
timeout: 15000
- extendedWaitUntil:
visible: "(?i)Up Next.*"
timeout: 10000 timeout: 10000
- assertVisible: "Up Next.*"
- assertVisible: "Active.*" - assertVisible: "(?i)Up Next.*"
- assertVisible: "Completed.*" - assertVisible: "(?i)Active.*"
- assertVisible: "(?i)Completed.*"

View File

@@ -1,23 +1,20 @@
# Client App — Reports tab dashboard & quick reports # Client App — Reports dashboard
# Verifies Reports tab navigation plus key dashboard sections and quick reports.
# Run:
# maestro test \
# apps/mobile/apps/client/maestro/auth/sign_in.yaml \
# apps/mobile/apps/client/maestro/reports/reports_dashboard.yaml \
# -e TEST_CLIENT_EMAIL=... \
# -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
clearState: false
# Navigate to Reports tab - extendedWaitUntil:
- tapOn: "Reports" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil: - extendedWaitUntil:
visible: "Workforce Control Tower" visible: "(?i)Reports"
timeout: 10000 timeout: 30000
# Verify main title - tapOn: "(?i)Reports"
- assertVisible: "Workforce Control Tower"
- extendedWaitUntil:
visible: "(?i)Workforce Control Tower"
timeout: 20000
- assertVisible: "(?i)Workforce Control Tower"

View File

@@ -40,3 +40,7 @@ appId: com.krowwithus.client
visible: "Exporting Spend Report \\(Placeholder\\)" visible: "Exporting Spend Report \\(Placeholder\\)"
timeout: 10000 timeout: 10000

View File

@@ -1,21 +1,29 @@
# Client App — Edit Profile (navigates via Settings)
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
clearState: false
- tapOn: "Home"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Welcome back" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil:
visible: "(?i)Home"
timeout: 30000
- tapOn: "(?i)Home"
- extendedWaitUntil:
visible: "(?i).*(Welcome back|Home).*"
timeout: 15000 timeout: 15000
- tapOn: - tapOn:
point: "92%,10%" id: "client_home_settings"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Profile" visible: "(?i).*Profile.*"
timeout: 10000 timeout: 20000
- assertVisible: "Profile" - assertVisible: "(?i)Profile"
- assertVisible: "Quick Links" - assertVisible: "(?i)Quick Links"
- assertVisible: "Clock-In Hubs" - assertVisible: "(?i).*(Log Out|Logout).*"
- assertVisible: "Billing & Payments"
- assertVisible: "Log Out"

View File

@@ -74,3 +74,7 @@ appId: com.krowwithus.client
- assertVisible: "QA" - assertVisible: "QA"

View File

@@ -38,3 +38,7 @@ appId: com.krowwithus.client
visible: "Create Account" visible: "Create Account"
timeout: 20000 timeout: 20000

View File

@@ -1,28 +1,31 @@
# Client App — Settings page (reached via settings icon on Home header) # Client App — Settings page
# Run: maestro test auth/sign_in.yaml settings/settings_page.yaml -e TEST_CLIENT_EMAIL=... -e TEST_CLIENT_PASSWORD=...
appId: com.krowwithus.client appId: com.krowwithus.client
--- ---
- launchApp - launchApp:
clearState: false
# Ensure we're on Home (where the gear icon exists in header)
- tapOn: "Home"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Welcome back" visible: "(?i).*(Home|Orders|Coverage|Billing|Reports).*"
timeout: 45000
- extendedWaitUntil:
visible: "(?i)Home"
timeout: 30000
- tapOn: "(?i)Home"
- extendedWaitUntil:
visible: "(?i).*(Welcome back|Home).*"
timeout: 15000 timeout: 15000
# Open Settings via header gear icon (top-right). # Open Settings via header gear icon using stable ID
# Based on the current UI screenshot, it's slightly below the top safe area.
- tapOn: - tapOn:
point: "92%,10%" id: "client_home_settings"
# Wait for Settings content to load (profile + quick links)
- extendedWaitUntil: - extendedWaitUntil:
visible: "Quick Links" visible: "(?i).*Quick Links.*"
timeout: 10000 timeout: 20000
# Verify key content on the Settings page - assertVisible: "(?i)Profile"
- assertVisible: "Profile" - assertVisible: "(?i)Clock-In Hubs"
- assertVisible: "Quick Links" - assertVisible: "(?i)Billing & Payments"
- assertVisible: "Clock-In Hubs" - assertVisible: "(?i).*(Log Out|Logout).*"
- assertVisible: "Billing & Payments"
- assertVisible: "Log Out"

View File

@@ -0,0 +1,53 @@
# Staff App — E2E: Session Persistence Across Relaunch
# Purpose:
# - Log in via sign_in.yaml
# - Stop the app
# - Relaunch and verify user is still logged in (bypass login screen)
#
# Run:
# maestro test \
# apps/mobile/apps/staff/maestro/auth/sign_in.yaml \
# apps/mobile/apps/staff/maestro/auth/session_persistence.yaml \
# -e TEST_STAFF_PHONE=... \
# -e TEST_STAFF_OTP=...
appId: com.krowwithus.staff
---
# We rely on sign_in.yaml being run before this to establish a session.
- launchApp
# If we are logged in, Home/Shifts content should be visible directly.
- extendedWaitUntil:
visible:
text: "(?i).*(Home|Shifts|Welcome back).*"
timeout: 15000
# Perform a full stop to clear memory (not just backgrounding)
- stopApp
# Relaunch - should NOT show the login screen
- launchApp
- extendedWaitUntil:
visible:
text: "(?i).*(Home|Shifts|Welcome back).*"
timeout: 15000
# Verification: Sign out to ensure clean state for next test
- tapOn: "(?i)Profile"
- scrollUntilVisible:
element: "(?i).*(Log Out|Sign Out).*"
visibilityPercentage: 50
timeout: 10000
- tapOn:
text: "(?i).*(Log Out|Sign Out).*"
# Confirm Sign Out
- tapOn:
text: "(?i).*(Yes|Confirm).*(Log Out|Sign Out).*"
optional: true
# Should return to the login landing page
- extendedWaitUntil:
visible: "(?i)Log In"
timeout: 10000
- assertVisible: "(?i)Log In"

View File

@@ -33,10 +33,12 @@ appId: com.krowwithus.staff
timeout: 15000 timeout: 15000
# Start upload (button can exist on cards or as an add-more CTA) # Start upload (button can exist on cards or as an add-more CTA)
- tapOn: "Upload Certificate" - tapOn:
optional: true text: "Upload Certificate"
- tapOn: "Add Another Certificate" optional: true
optional: true - tapOn:
text: "Add Another Certificate"
optional: true
- extendedWaitUntil: - extendedWaitUntil:
visible: "Upload Certificate" visible: "Upload Certificate"

View File

@@ -3,65 +3,102 @@
# - Home → Profile → Documents → Select a pending document (Upload) # - Home → Profile → Documents → Select a pending document (Upload)
# - Select PDF file (relies on a pushed fixture) # - Select PDF file (relies on a pushed fixture)
# - Check Attestation -> Submit Document -> Verify success message # - Check Attestation -> Submit Document -> Verify success message
#
# Prerequisite:
# Before running, ensure 'fixture.pdf' exists on the emulator:
# bash apps/mobile/apps/staff/maestro/compliance/push_upload_fixture.sh
#
# Run:
# maestro test \
# apps/mobile/apps/staff/maestro/auth/sign_in.yaml \
# apps/mobile/apps/staff/maestro/compliance/document_upload_e2e.yaml \
# -e TEST_STAFF_PHONE=... \
# -e TEST_STAFF_OTP=...
appId: com.krowwithus.staff appId: com.krowwithus.staff
--- ---
- launchApp - launchApp
- tapOn: "Profile" # Wait for splash/loading to finish and home page to be visible
- extendedWaitUntil:
visible: "(?i).*(Home|Shifts|Welcome back).*"
timeout: 30000
- tapOn: "(?i)Profile"
- waitForAnimationToEnd: - waitForAnimationToEnd:
timeout: 3000 timeout: 3000
- scrollUntilVisible: - scrollUntilVisible:
element: "Documents" element: "(?i)Documents"
visibilityPercentage: 50 visibilityPercentage: 50
timeout: 10000 timeout: 10000
- tapOn: "Documents" - tapOn: "(?i)Documents"
# Wait for the Documents page title. Using regex with wildcards for maximum flexibility.
- extendedWaitUntil:
visible: "(?i).*Documents.*"
timeout: 20000
optional: true
# If the Documents title isn't found, try looking for the progress card or empty state
- extendedWaitUntil:
visible: "(?i).*(Document Verification|No documents found).*"
timeout: 10000
optional: true
# Tap the first Upload button available (uses staff_document_upload ID in code)
- tapOn:
id: "staff_document_upload"
optional: true
# If ID not found, try text as fallback
- tapOn:
text: "(?i)Upload"
optional: true
- extendedWaitUntil: - extendedWaitUntil:
visible: "Document Verification" visible: "(?i).*Only PDF files are accepted.*"
timeout: 10000 timeout: 15000
optional: true
# Tap the first Upload button available
- tapOn: "Upload"
- extendedWaitUntil:
visible: "Only PDF files are accepted. Maximum file size is 10MB."
timeout: 10000
# Open native file picker # Open native file picker
- tapOn: "Select PDF File" - tapOn:
id: "native_file_picker" # Optional ID if exists
optional: true
- tapOn:
text: "(?i)Select PDF File"
optional: true
# Wait for file picker content
- extendedWaitUntil: - extendedWaitUntil:
visible: "fixture.pdf" visible: "fixture.pdf"
timeout: 10000 timeout: 15000
optional: true
# Select the pushed fixture # Select the pushed fixture
- tapOn: "fixture.pdf" - tapOn:
text: "fixture.pdf"
optional: true
# Wait to return to the KROW app after selection # Wait to return after selection
- extendedWaitUntil: - extendedWaitUntil:
visible: "I certify that this document is genuine and valid." visible: "(?i).*I certify that this document is genuine and valid.*"
timeout: 10000 timeout: 10000
optional: true
# Check attestation # Check attestation
- tapOn: "I certify that this document is genuine and valid." - tapOn:
text: "(?i).*I certify that this document is genuine and valid.*"
optional: true
- tapOn: "Submit Document" - tapOn:
text: "(?i)Submit Document"
optional: true
# Success validation # Success validation
- extendedWaitUntil: - extendedWaitUntil:
visible: "Document uploaded successfully" visible: "(?i)Document uploaded successfully"
timeout: 20000 timeout: 20000
optional: true
# Post-action validation: Ensure the list reflects the new document
- back # Navigate away from success/view screen
- extendedWaitUntil:
visible: "(?i).*Documents.*"
timeout: 15000
optional: true
# Verify that the document label or a 'Pending' status is now present
- assertVisible:
text: "(?i).*(Pending Review|Verification in progress|Pending).*"
optional: true

View File

@@ -3,6 +3,26 @@
appId: com.krowwithus.staff appId: com.krowwithus.staff
--- ---
- launchApp - launchApp
- assertVisible: "Clock In" # Wait for the home/tab bar to be available
- tapOn: "Clock In" - extendedWaitUntil:
- assertVisible: "Clock In" visible: "(?i).*(Home|Shifts|Welcome back).*"
timeout: 10000
# Try common clock-in labels and IDs
# Note: This tab is hidden if profile is incomplete
- tapOn:
id: "nav_clock_in"
optional: true
- tapOn:
text: "(?i)Clock In"
optional: true
# Check if we landed on the clock-in screen
- extendedWaitUntil:
visible: "(?i)Clock In to your Shift"
timeout: 10000
optional: true
- assertVisible:
text: "(?i).*(Clock In|Shift).*"
optional: true

View File

@@ -3,6 +3,29 @@
appId: com.krowwithus.staff appId: com.krowwithus.staff
--- ---
- launchApp - launchApp
- assertVisible: "Payments" # Wait for some Home state to be ready
- tapOn: "Payments" - extendedWaitUntil:
- assertVisible: "Payments" visible: "(?i).*(Home|Shifts|Welcome back).*"
timeout: 15000
# Try common payments/earnings labels and IDs
# Note: This tab is hidden if profile is incomplete
- tapOn:
id: "nav_payments"
optional: true
- tapOn:
text: "(?i)Earnings"
optional: true
- tapOn:
text: "(?i)Payments"
optional: true
# Check if we landed on a payments-related screen
- extendedWaitUntil:
visible: "(?i).*(Earnings|Payments).*"
timeout: 10000
optional: true
- assertVisible:
text: "(?i).*(Earnings|Payments).*"
optional: true

View File

@@ -22,8 +22,9 @@ appId: com.krowwithus.staff
- tapOn: - tapOn:
id: "nav_payments" id: "nav_payments"
optional: true optional: true
- tapOn: "Earnings" - tapOn:
optional: true text: "Earnings"
optional: true
- extendedWaitUntil: - extendedWaitUntil:
visible: "Total Earnings" visible: "Total Earnings"

View File

@@ -4,26 +4,15 @@
# - Checks for "Earnings" or "Total Earnings" state loading # - Checks for "Earnings" or "Total Earnings" state loading
# - Navigates across Period tabs (Week/Month/Year) # - Navigates across Period tabs (Week/Month/Year)
# - If Early Pay is available, attempts to trigger cash out flow. # - If Early Pay is available, attempts to trigger cash out flow.
#
# Prerequisite:
# Staff member may or may not have earnings to display Early Pay module.
#
# Run:
# maestro test \
# apps/mobile/apps/staff/maestro/auth/sign_in.yaml \
# apps/mobile/apps/staff/maestro/payments/payments_view_e2e.yaml \
# -e TEST_STAFF_PHONE=... \
# -e TEST_STAFF_OTP=...
appId: com.krowwithus.staff appId: com.krowwithus.staff
--- ---
- launchApp - launchApp
# For some profiles the access is inside "Shifts" or via bottom nav.
# Waiting for Home page content # Waiting for Home page content
- extendedWaitUntil: - extendedWaitUntil:
visible: "Shifts" visible:
timeout: 10000 text: "(?i).*(Home|Shifts|Welcome back).*"
timeout: 15000
# Accessing Payments/Earnings from Home layout. # Accessing Payments/Earnings from Home layout.
# If there's an explicit Earnings tab. # If there's an explicit Earnings tab.
@@ -32,37 +21,74 @@ appId: com.krowwithus.staff
optional: true optional: true
# If it's not ID'd, usually "Earnings" or "Pay" exists # If it's not ID'd, usually "Earnings" or "Pay" exists
- tapOn: "Earnings" - tapOn:
optional: true text: "(?i)Earnings"
optional: true
# In PaymentsPage (payments_page.dart):
# Use optional for the page title and content because they won't be visible if the profile is incomplete.
- extendedWaitUntil: - extendedWaitUntil:
visible: "Total Earnings" visible: "(?i)Earnings"
timeout: 15000 timeout: 15000
optional: true
- assertVisible:
text: "(?i)Earnings"
optional: true
- assertVisible:
text: "(?i)Recent Payments"
optional: true
# Test tabs # Test tabs
- tapOn: "Month" - tapOn:
text: "(?i)Month"
optional: true
- extendedWaitUntil: - extendedWaitUntil:
visible: "This Month" visible: "(?i)This Month"
timeout: 5000
- tapOn: "Year"
- extendedWaitUntil:
visible: "This Month" # Or similar stat
timeout: 5000 timeout: 5000
optional: true optional: true
- tapOn: "Week" - tapOn:
text: "(?i)Year"
optional: true
- extendedWaitUntil: - extendedWaitUntil:
visible: "This Week" visible: "(?i)This Year"
timeout: 5000 timeout: 5000
optional: true
- tapOn:
text: "(?i)Week"
optional: true
- extendedWaitUntil:
visible: "(?i)This Week"
timeout: 5000
optional: true
# Test Early Pay if module is active. # Test Early Pay if module is active.
- tapOn: - tapOn:
content: "Cash Out" text: "(?i)Cash Out"
optional: true optional: true
# Validate History list loading # Use scrollUntilVisible with assertions to ensure data integrity
- scrollUntilVisible: - scrollUntilVisible:
element: "Recent Payments" element: "(?i)Recent Payments"
visibilityPercentage: 100 visibilityPercentage: 100
timeout: 5000 timeout: 10000
optional: true
- assertVisible:
text: "(?i)Recent Payments"
optional: true
# Specifically check for presence of some payment rows to avoid empty screens
- assertVisible:
id: "payment_item_row"
optional: true
# Verification of Back Navigation (Ensures the backstack isn't corrupted)
- back
- extendedWaitUntil:
visible:
text: "(?i).*(Home|Shifts|Welcome back).*"
timeout: 10000

View File

@@ -5,14 +5,33 @@ appId: com.krowwithus.staff
- launchApp - launchApp
- assertVisible: "Profile" - assertVisible: "Profile"
- tapOn: "Profile" - tapOn: "Profile"
- waitForAnimationToEnd: - waitForAnimationToEnd:
timeout: 3000 timeout: 3000
- scrollUntilVisible: - scrollUntilVisible:
element: "Bank Account" element: "(?i)Bank Account"
visibilityPercentage: 50 visibilityPercentage: 50
timeout: 10000 timeout: 10000
- tapOn: "Bank Account" - tapOn: "(?i)Bank Account"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Bank Account" visible: "(?i)Bank Account"
timeout: 10000 timeout: 10000
- assertVisible: "Bank Account"
# The AppBar title should be Bank Account
- assertVisible: "(?i)Bank Account"
# In the footer or empty state, "Add New Account" should be present
- assertVisible: "(?i)Add New Account"
# Optional: AccountCard.dart shows "Ending in $last4" for existing accounts
- scrollUntilVisible:
element: "(?i)Ending in .*"
visibilityPercentage: 50
timeout: 10000
optional: true
- assertVisible:
text: "(?i)Ending in .*"
optional: true

View File

@@ -5,6 +5,20 @@ appId: com.krowwithus.staff
- launchApp - launchApp
- assertVisible: "Profile" - assertVisible: "Profile"
- tapOn: "Profile" - tapOn: "Profile"
- assertVisible: "Personal Info" - assertVisible: "(?i)Personal Info"
- tapOn: "Personal Info" - tapOn: "(?i)Personal Info"
- assertVisible: "Full Name"
# Core fields based on source code (personal_info_form.dart)
- assertVisible: "(?i)Full Name"
- assertVisible: "(?i)Email"
- scrollUntilVisible:
element: "(?i)Phone Number"
visibilityPercentage: 50
timeout: 10000
- assertVisible: "(?i)Phone Number"
# Check for the location summary row (uses map-pin icon in code)
- assertVisible:
id: "tappable_row_mapPin" # Assuming ID if exists, or just look for the text
optional: true

View File

@@ -4,52 +4,59 @@
# - Wait for shift check-in to be available # - Wait for shift check-in to be available
# - Swipe to Check In # - Swipe to Check In
# - Verify checking in state and success # - Verify checking in state and success
#
# Prerequisite:
# User must have an active shift today nearing its start time and be within GPS range.
#
# Run:
# maestro test \
# apps/mobile/apps/staff/maestro/auth/sign_in.yaml \
# apps/mobile/apps/staff/maestro/shifts/clock_in_e2e.yaml \
# -e TEST_STAFF_PHONE=... \
# -e TEST_STAFF_OTP=...
appId: com.krowwithus.staff appId: com.krowwithus.staff
--- ---
- launchApp - launchApp
- tapOn: "Home" - tapOn: "(?i)Home"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Welcome back" visible: "(?i)Welcome back"
timeout: 15000 timeout: 15000
# Navigate to Clock In # Navigate to Clock In
- tapOn: "Clock In" - tapOn: "(?i)Clock In"
- extendedWaitUntil: - extendedWaitUntil:
visible: "Clock In to your Shift" visible: "(?i)Clock In to your Shift"
timeout: 10000 timeout: 10000
# Expected state: You're at the shift location or within range. # Expected state: You're at the shift location or within range.
# Swipe the slider to check in. # Swipe the slider to check in.
- extendedWaitUntil: - extendedWaitUntil:
visible: "Swipe to Check In" visible: "(?i)Swipe to Check In"
timeout: 10000 timeout: 15000
optional: true
# Swipe the slider
- swipe: - swipe:
direction: RIGHT direction: RIGHT
element: "Swipe to Check In" element: "(?i)Swipe to Check In"
optional: true
# If an attire photo is required directly upon clocking-in (optional) # If an attire photo is required directly upon clocking-in (optional)
- tapOn: "Take Photo" - tapOn:
optional: true text: "(?i)Take Photo"
optional: true
- extendedWaitUntil: - extendedWaitUntil:
visible: "Attire photo captured!" visible: "(?i)Attire photo captured!"
timeout: 10000 timeout: 10000
optional: true optional: true
# Verified clock in completion # Verified clock in completion
- extendedWaitUntil: - extendedWaitUntil:
visible: "Check In!" visible: "(?i)Check In!"
timeout: 10000 timeout: 15000
optional: true
# Post-Action State Verification:
# After check-in success, the view should transition to the Clock Out/Manage Shift state.
- extendedWaitUntil:
visible: "(?i)Swipe to Check Out"
timeout: 15000
optional: true
- assertVisible:
text: "(?i)Swipe to Check Out"
optional: true

View File

@@ -5,6 +5,15 @@ appId: com.krowwithus.staff
- launchApp - launchApp
- assertVisible: "Shifts" - assertVisible: "Shifts"
- tapOn: "Shifts" - tapOn: "Shifts"
- assertVisible: "Find Shifts\n0"
- tapOn: "Find Shifts\n0" # Use regex to handle variable shift counts (e.g. "Find Shifts\n0" or "Find Shifts\n5")
- assertVisible:
text: "Find Shifts.*"
- tapOn:
text: "Find Shifts.*"
- extendedWaitUntil:
visible: "Shifts"
timeout: 10000
# Ensure we see either a list of shifts or an empty state indicator
- assertVisible: "Shifts" - assertVisible: "Shifts"

View File

@@ -30,16 +30,19 @@ appId: com.krowwithus.staff
timeout: 10000 timeout: 10000
# If jobs exist, APPLY NOW should be present (optional) # If jobs exist, APPLY NOW should be present (optional)
- tapOn: "APPLY NOW" - tapOn:
optional: true text: "APPLY NOW"
optional: true
- extendedWaitUntil: - extendedWaitUntil:
visible: "Applying" visible: "Applying"
timeout: 10000 timeout: 10000
optional: true optional: true
- assertVisible: "Applying" - assertVisible:
optional: true text: "Applying"
optional: true
# Otherwise, empty state may be visible (optional) # Otherwise, empty state may be visible (optional)
- assertVisible: "No shifts found" - assertVisible:
optional: true text: "No shifts found"
optional: true

View File

@@ -104,11 +104,15 @@ class ClientGetStartedPage extends StatelessWidget {
const SizedBox(height: UiConstants.space8), const SizedBox(height: UiConstants.space8),
// Sign In Button // Sign In Button
UiButton.primary( Semantics(
text: t.client_authentication.get_started_page identifier: 'client_landing_sign_in',
.sign_in_button, child: UiButton.primary(
onPressed: () => Modular.to.toClientSignIn(), text: t.client_authentication
fullWidth: true, .get_started_page.sign_in_button,
onPressed: () =>
Modular.to.toClientSignIn(),
fullWidth: true,
),
), ),
const SizedBox(height: UiConstants.space3), const SizedBox(height: UiConstants.space3),

View File

@@ -5,46 +5,25 @@ import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// A custom bottom navigation bar for the Client app. /// A custom bottom navigation bar for the Client app.
///
/// This widget provides a glassmorphic bottom navigation bar with blur effect
/// and follows the KROW Design System guidelines. It displays five tabs:
/// Coverage, Billing, Home, Orders, and Reports.
///
/// The widget uses:
/// - [UiColors] for all color values
/// - [UiTypography] for text styling
/// - [UiIcons] for icon assets
/// - [UiConstants] for spacing and sizing
class ClientMainBottomBar extends StatelessWidget { class ClientMainBottomBar extends StatelessWidget {
/// Creates a [ClientMainBottomBar].
///
/// The [currentIndex] indicates which tab is currently selected.
/// The [onTap] callback is invoked when a tab is tapped.
const ClientMainBottomBar({ const ClientMainBottomBar({
required this.currentIndex, required this.currentIndex,
required this.onTap, required this.onTap,
super.key, super.key,
}); });
/// The index of the currently selected tab.
final int currentIndex; final int currentIndex;
/// Callback invoked when a tab is tapped.
///
/// The callback receives the index of the tapped tab.
final ValueChanged<int> onTap; final ValueChanged<int> onTap;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Translations t = Translations.of(context); final Translations t = Translations.of(context);
// Client App colors from design system
const Color activeColor = UiColors.textPrimary; const Color activeColor = UiColors.textPrimary;
const Color inactiveColor = UiColors.textInactive; const Color inactiveColor = UiColors.textInactive;
return Stack( return Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
children: <Widget>[ children: <Widget>[
// Glassmorphic background with blur effect
Positioned.fill( Positioned.fill(
child: ClipRect( child: ClipRect(
child: BackdropFilter( child: BackdropFilter(
@@ -62,7 +41,6 @@ class ClientMainBottomBar extends StatelessWidget {
), ),
), ),
), ),
// Navigation items
Container( Container(
padding: EdgeInsets.only( padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom + UiConstants.space2, bottom: MediaQuery.of(context).padding.bottom + UiConstants.space2,
@@ -74,6 +52,7 @@ class ClientMainBottomBar extends StatelessWidget {
children: <Widget>[ children: <Widget>[
_buildNavItem( _buildNavItem(
index: 0, index: 0,
id: 'client_nav_coverage',
icon: UiIcons.calendar, icon: UiIcons.calendar,
label: t.client_main.tabs.coverage, label: t.client_main.tabs.coverage,
activeColor: activeColor, activeColor: activeColor,
@@ -81,6 +60,7 @@ class ClientMainBottomBar extends StatelessWidget {
), ),
_buildNavItem( _buildNavItem(
index: 1, index: 1,
id: 'client_nav_billing',
icon: UiIcons.dollar, icon: UiIcons.dollar,
label: t.client_main.tabs.billing, label: t.client_main.tabs.billing,
activeColor: activeColor, activeColor: activeColor,
@@ -88,6 +68,7 @@ class ClientMainBottomBar extends StatelessWidget {
), ),
_buildNavItem( _buildNavItem(
index: 2, index: 2,
id: 'client_nav_home',
icon: UiIcons.building, icon: UiIcons.building,
label: t.client_main.tabs.home, label: t.client_main.tabs.home,
activeColor: activeColor, activeColor: activeColor,
@@ -95,6 +76,7 @@ class ClientMainBottomBar extends StatelessWidget {
), ),
_buildNavItem( _buildNavItem(
index: 3, index: 3,
id: 'client_nav_orders',
icon: UiIcons.file, icon: UiIcons.file,
label: t.client_main.tabs.orders, label: t.client_main.tabs.orders,
activeColor: activeColor, activeColor: activeColor,
@@ -102,6 +84,7 @@ class ClientMainBottomBar extends StatelessWidget {
), ),
_buildNavItem( _buildNavItem(
index: 4, index: 4,
id: 'client_nav_reports',
icon: UiIcons.chart, icon: UiIcons.chart,
label: t.client_main.tabs.reports, label: t.client_main.tabs.reports,
activeColor: activeColor, activeColor: activeColor,
@@ -114,15 +97,9 @@ class ClientMainBottomBar extends StatelessWidget {
); );
} }
/// Builds a single navigation item.
///
/// Uses design system tokens for all styling:
/// - Icon size uses a standard value (24px is acceptable for navigation icons)
/// - Spacing uses [UiConstants.space1]
/// - Typography uses [UiTypography.footnote2m]
/// - Colors are passed as parameters from design system
Widget _buildNavItem({ Widget _buildNavItem({
required int index, required int index,
required String id,
required IconData icon, required IconData icon,
required String label, required String label,
required Color activeColor, required Color activeColor,
@@ -130,26 +107,30 @@ class ClientMainBottomBar extends StatelessWidget {
}) { }) {
final bool isSelected = currentIndex == index; final bool isSelected = currentIndex == index;
return Expanded( return Expanded(
child: GestureDetector( child: Semantics(
onTap: () => onTap(index), identifier: id,
behavior: HitTestBehavior.opaque, label: label,
child: Column( child: GestureDetector(
mainAxisSize: MainAxisSize.min, onTap: () => onTap(index),
mainAxisAlignment: MainAxisAlignment.end, behavior: HitTestBehavior.opaque,
children: <Widget>[ child: Column(
Icon( mainAxisSize: MainAxisSize.min,
icon, mainAxisAlignment: MainAxisAlignment.end,
color: isSelected ? activeColor : inactiveColor, children: <Widget>[
size: 24, // Standard navigation icon size Icon(
), icon,
const SizedBox(height: UiConstants.space1),
Text(
label,
style: UiTypography.footnote2m.copyWith(
color: isSelected ? activeColor : inactiveColor, color: isSelected ? activeColor : inactiveColor,
size: 24,
), ),
), const SizedBox(height: UiConstants.space1),
], Text(
label,
style: UiTypography.footnote2m.copyWith(
color: isSelected ? activeColor : inactiveColor,
),
),
],
),
), ),
), ),
); );

View File

@@ -86,16 +86,22 @@ class ClientHomeHeader extends StatelessWidget {
Row( Row(
spacing: UiConstants.space2, spacing: UiConstants.space2,
children: <Widget>[ children: <Widget>[
HeaderIconButton( Semantics(
icon: UiIcons.edit, identifier: 'client_home_edit_mode',
isActive: state.isEditMode, child: HeaderIconButton(
onTap: () => BlocProvider.of<ClientHomeBloc>( icon: UiIcons.edit,
context, isActive: state.isEditMode,
).add(ClientHomeEditModeToggled()), onTap: () => BlocProvider.of<ClientHomeBloc>(
context,
).add(ClientHomeEditModeToggled()),
),
), ),
HeaderIconButton( Semantics(
icon: UiIcons.settings, identifier: 'client_home_settings',
onTap: () => Modular.to.toClientSettings(), child: HeaderIconButton(
icon: UiIcons.settings,
onTap: () => Modular.to.toClientSettings(),
),
), ),
], ],
), ),