Implement Maestro E2E Tests for Mobile Happy Paths & Document #572
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# Maestro Integration Tests — Client App
|
||||
|
||||
Auth flows for the KROW Client app.
|
||||
See [docs/research/flutter-testing-tools.md](/docs/research/flutter-testing-tools.md) and [maestro-test-run-instructions.md](/docs/research/maestro-test-run-instructions.md).
|
||||
Auth flows and E2E happy paths for the KROW Client app.
|
||||
See [docs/research/flutter-testing-tools.md](/docs/research/flutter-testing-tools.md), [maestro-test-run-instructions.md](/docs/research/maestro-test-run-instructions.md), and [docs/testing/maestro-e2e-happy-paths.md](/docs/testing/maestro-e2e-happy-paths.md) (#572).
|
||||
|
||||
## Structure
|
||||
|
||||
@@ -10,6 +10,8 @@ maestro/
|
||||
auth/
|
||||
sign_in.yaml
|
||||
sign_up.yaml
|
||||
sign_out.yaml
|
||||
sign_in_invalid_password.yaml
|
||||
navigation/
|
||||
home.yaml
|
||||
orders.yaml
|
||||
@@ -20,8 +22,22 @@ maestro/
|
||||
view_orders.yaml
|
||||
completed_no_edit_icon.yaml # #492
|
||||
create_order_entry.yaml
|
||||
create_order_one_time_e2e.yaml
|
||||
hubs/
|
||||
create_hub_e2e.yaml
|
||||
manage_hubs_from_settings.yaml
|
||||
billing/
|
||||
billing_overview.yaml
|
||||
invoice_approval_e2e.yaml
|
||||
reports/
|
||||
reports_dashboard.yaml
|
||||
home/
|
||||
home_dashboard_widgets.yaml
|
||||
tab_bar_roundtrip.yaml
|
||||
settings/
|
||||
settings_page.yaml
|
||||
edit_profile.yaml
|
||||
logout_flow.yaml
|
||||
```
|
||||
|
||||
## Credentials (env, never hardcoded)
|
||||
@@ -37,7 +53,9 @@ maestro/
|
||||
|
||||
```bash
|
||||
# Via Makefile (export vars first)
|
||||
make test-e2e-client
|
||||
make test-e2e-client # Auth only
|
||||
make test-e2e-client-extended # Auth + nav + orders + settings
|
||||
make test-e2e-client-happy-path # Auth + hubs + create order E2E + billing + reports + logout (#572)
|
||||
|
||||
# Direct
|
||||
maestro test apps/mobile/apps/client/maestro/auth/sign_in.yaml \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maestro Integration Tests — Staff App
|
||||
|
||||
Auth flows for the KROW Staff app.
|
||||
See [docs/research/flutter-testing-tools.md](/docs/research/flutter-testing-tools.md) and [maestro-test-run-instructions.md](/docs/research/maestro-test-run-instructions.md).
|
||||
Auth flows and E2E happy paths for the KROW Staff app.
|
||||
See [docs/research/flutter-testing-tools.md](/docs/research/flutter-testing-tools.md), [maestro-test-run-instructions.md](/docs/research/maestro-test-run-instructions.md), and [docs/testing/maestro-e2e-happy-paths.md](/docs/testing/maestro-e2e-happy-paths.md) (#572).
|
||||
|
||||
## Structure
|
||||
|
||||
@@ -10,23 +10,38 @@ maestro/
|
||||
auth/
|
||||
sign_in.yaml
|
||||
sign_up.yaml
|
||||
sign_out.yaml
|
||||
sign_in_invalid_otp.yaml
|
||||
navigation/
|
||||
home.yaml
|
||||
shifts.yaml
|
||||
profile.yaml
|
||||
payments.yaml
|
||||
clock_in.yaml
|
||||
availability.yaml
|
||||
profile/
|
||||
personal_info.yaml
|
||||
documents_list.yaml
|
||||
certificates_list.yaml
|
||||
time_card.yaml
|
||||
bank_account.yaml
|
||||
faqs.yaml
|
||||
privacy_security.yaml
|
||||
emergency_contact.yaml
|
||||
compliance/
|
||||
document_upload_banner.yaml # #550
|
||||
certificate_upload_banner.yaml # #551
|
||||
attire_upload_banner.yaml # #552
|
||||
document_upload_e2e.yaml
|
||||
shifts/
|
||||
find_shifts.yaml
|
||||
clock_in_e2e.yaml
|
||||
clock_out_e2e.yaml
|
||||
incomplete_profile_banner.yaml # #549 (requires incomplete-profile user)
|
||||
availability/
|
||||
set_availability_e2e.yaml
|
||||
payments/
|
||||
payments_view_e2e.yaml
|
||||
home/
|
||||
benefits.yaml # #524
|
||||
```
|
||||
@@ -49,7 +64,9 @@ maestro/
|
||||
|
||||
```bash
|
||||
# Via Makefile (export vars first)
|
||||
make test-e2e-staff
|
||||
make test-e2e-staff # Auth only
|
||||
make test-e2e-staff-extended # Auth + nav + profile + compliance + shifts + benefits
|
||||
make test-e2e-staff-happy-path # Auth + clock in/out + availability + document upload + payments + sign out (#572)
|
||||
|
||||
# Direct
|
||||
maestro test apps/mobile/apps/staff/maestro/auth/sign_in.yaml \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// ignore_for_file: always_specify_types, depend_on_referenced_packages, dead_code, dead_null_aware_expression, unused_local_variable, unused_import, sort_constructors_first, prefer_final_fields, prefer_const_constructors, deprecated_member_use, implicit_call_tearoffs
|
||||
// ignore_for_file: always_specify_types, depend_on_referenced_packages, dead_code, dead_null_aware_expression, unused_local_variable, unused_import, sort_constructors_first, prefer_final_fields, prefer_const_constructors, deprecated_member_use, implicit_call_tearoffs
|
||||
import 'package:firebase_data_connect/src/core/ref.dart';
|
||||
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
@@ -247,51 +247,59 @@ class BillingConnectorRepositoryImpl implements BillingConnectorRepository {
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
// Fallback: If roles is empty, try to get workers from shift applications
|
||||
else if (invoice.shift != null &&
|
||||
invoice.shift.applications_on_shift != null) {
|
||||
final List<dynamic> apps = invoice.shift.applications_on_shift;
|
||||
workers = apps.map((dynamic app) {
|
||||
final String name = app.staff?.fullName ?? 'Unknown';
|
||||
final String roleTitle = app.shiftRole?.role?.name ?? 'Staff';
|
||||
final double amount =
|
||||
(app.shiftRole?.totalValue as num?)?.toDouble() ?? 0.0;
|
||||
final double hours = (app.shiftRole?.hours as num?)?.toDouble() ?? 0.0;
|
||||
// Fallback: If roles is empty, try to get workers from shift applications.
|
||||
// Only when the invoice type has a 'shift' field (e.g. getInvoiceById); listInvoicesByBusinessId
|
||||
// generated type has shiftId but no shift getter, so we guard with try/catch.
|
||||
else {
|
||||
try {
|
||||
final dynamic shift = (invoice as dynamic).shift;
|
||||
if (shift != null && shift.applications_on_shift != null) {
|
||||
final List<dynamic> apps = shift.applications_on_shift;
|
||||
workers = apps.map((dynamic app) {
|
||||
final String name = app.staff?.fullName ?? 'Unknown';
|
||||
final String roleTitle = app.shiftRole?.role?.name ?? 'Staff';
|
||||
final double amount =
|
||||
(app.shiftRole?.totalValue as num?)?.toDouble() ?? 0.0;
|
||||
final double hours = (app.shiftRole?.hours as num?)?.toDouble() ?? 0.0;
|
||||
|
||||
// Calculate rate if not explicitly provided
|
||||
double rate = 0.0;
|
||||
if (hours > 0) {
|
||||
rate = amount / hours;
|
||||
// Calculate rate if not explicitly provided
|
||||
double rate = 0.0;
|
||||
if (hours > 0) {
|
||||
rate = amount / hours;
|
||||
}
|
||||
|
||||
// Map break type to minutes
|
||||
int breakMin = 0;
|
||||
final String? breakType = app.shiftRole?.breakType?.toString();
|
||||
if (breakType != null) {
|
||||
if (breakType.contains('10'))
|
||||
breakMin = 10;
|
||||
else if (breakType.contains('15'))
|
||||
breakMin = 15;
|
||||
else if (breakType.contains('30'))
|
||||
breakMin = 30;
|
||||
else if (breakType.contains('45'))
|
||||
breakMin = 45;
|
||||
else if (breakType.contains('60'))
|
||||
breakMin = 60;
|
||||
}
|
||||
|
||||
return InvoiceWorker(
|
||||
name: name,
|
||||
role: roleTitle,
|
||||
amount: amount,
|
||||
hours: hours,
|
||||
rate: rate,
|
||||
checkIn: _service.toDateTime(app.checkInTime),
|
||||
checkOut: _service.toDateTime(app.checkOutTime),
|
||||
breakMinutes: breakMin,
|
||||
avatarUrl: app.staff?.photoUrl,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// Map break type to minutes
|
||||
int breakMin = 0;
|
||||
final String? breakType = app.shiftRole?.breakType?.toString();
|
||||
if (breakType != null) {
|
||||
if (breakType.contains('10'))
|
||||
breakMin = 10;
|
||||
else if (breakType.contains('15'))
|
||||
breakMin = 15;
|
||||
else if (breakType.contains('30'))
|
||||
breakMin = 30;
|
||||
else if (breakType.contains('45'))
|
||||
breakMin = 45;
|
||||
else if (breakType.contains('60'))
|
||||
breakMin = 60;
|
||||
}
|
||||
|
||||
return InvoiceWorker(
|
||||
name: name,
|
||||
role: roleTitle,
|
||||
amount: amount,
|
||||
hours: hours,
|
||||
rate: rate,
|
||||
checkIn: _service.toDateTime(app.checkInTime),
|
||||
checkOut: _service.toDateTime(app.checkOutTime),
|
||||
breakMinutes: breakMin,
|
||||
avatarUrl: app.staff?.photoUrl,
|
||||
);
|
||||
}).toList();
|
||||
} catch (_) {
|
||||
// Invoice type has no 'shift' getter (e.g. ListInvoicesByBusinessIdInvoices). Skip.
|
||||
}
|
||||
}
|
||||
|
||||
return Invoice(
|
||||
|
||||
Reference in New Issue
Block a user