229 lines
7.5 KiB
Dart
229 lines
7.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:motorcycle_dash/features/routes/route_planner_screen.dart';
|
|
import 'package:motorcycle_dash/services/auth/auth_providers.dart';
|
|
import 'package:motorcycle_dash/services/auth/auth_user.dart';
|
|
import 'package:motorcycle_dash/services/entitlements/entitlement_providers.dart';
|
|
|
|
void main() {
|
|
testWidgets('RoutePlannerScreen renders title, empty state, and stop controls', (tester) async {
|
|
await tester.binding.setSurfaceSize(const Size(360, 640));
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => const AuthUser(
|
|
uid: 'alice',
|
|
isAnonymous: false,
|
|
)),
|
|
isProSubscriberProvider.overrideWith((ref) => false),
|
|
],
|
|
child: const MaterialApp(
|
|
home: RoutePlannerScreen(),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
// Verify AppBar title
|
|
expect(find.text('ROUTE PLANNER'), findsOneWidget);
|
|
expect(find.text('SAVE'), findsOneWidget);
|
|
|
|
// Verify Empty state message
|
|
expect(find.text('No stops added yet.'), findsOneWidget);
|
|
expect(find.text('ADD STOP'), findsOneWidget);
|
|
expect(find.text('CURRENT GPS'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('RoutePlannerScreen handles adding a stop', (tester) async {
|
|
await tester.binding.setSurfaceSize(const Size(360, 640));
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => const AuthUser(
|
|
uid: 'alice',
|
|
isAnonymous: false,
|
|
)),
|
|
isProSubscriberProvider.overrideWith((ref) => false),
|
|
],
|
|
child: const MaterialApp(
|
|
home: RoutePlannerScreen(),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
// Tap ADD STOP
|
|
await tester.tap(find.text('ADD STOP'));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Dialog appears
|
|
expect(find.text('Add Route Stop'), findsOneWidget);
|
|
|
|
// Enter name, lat, lng
|
|
final dialogTextFields = find.descendant(
|
|
of: find.byType(AlertDialog),
|
|
matching: find.byType(TextField),
|
|
);
|
|
await tester.enterText(dialogTextFields.at(0), 'Alice\'s Restaurant');
|
|
await tester.enterText(dialogTextFields.at(1), '37.3861');
|
|
await tester.enterText(dialogTextFields.at(2), '-122.2641');
|
|
|
|
// Tap ADD button in dialog
|
|
await tester.tap(find.text('ADD'));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Verify stop is added in list
|
|
expect(find.text('Alice\'s Restaurant'), findsOneWidget);
|
|
expect(find.text('1/25 STOPS'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('RoutePlannerScreen responsive layout on narrow 320dp screen', (tester) async {
|
|
// 320dp narrow device test
|
|
await tester.binding.setSurfaceSize(const Size(320, 568));
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => const AuthUser(
|
|
uid: 'alice',
|
|
isAnonymous: false,
|
|
)),
|
|
isProSubscriberProvider.overrideWith((ref) => false),
|
|
],
|
|
child: const MaterialApp(
|
|
home: RoutePlannerScreen(),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
// On narrow screen, compact labels 'ADD' and 'GPS' are shown
|
|
expect(find.text('ADD'), findsOneWidget);
|
|
expect(find.text('GPS'), findsOneWidget);
|
|
|
|
// No RenderFlex overflow
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('RoutePlannerScreen handles title editing under Pixel 8a IME keyboard inset without overflow', (tester) async {
|
|
// Pixel 8a viewport with keyboard open (height reduced from 857 to 440)
|
|
await tester.binding.setSurfaceSize(const Size(385, 440));
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => const AuthUser(
|
|
uid: 'alice',
|
|
isAnonymous: false,
|
|
)),
|
|
isProSubscriberProvider.overrideWith((ref) => false),
|
|
],
|
|
child: const MaterialApp(
|
|
home: RoutePlannerScreen(),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
// Find Route Title TextField
|
|
final titleField = find.byType(TextField).first;
|
|
expect(titleField, findsOneWidget);
|
|
|
|
// Enter title text while constrained
|
|
await tester.enterText(titleField, 'Marionette Route Validation');
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Marionette Route Validation'), findsOneWidget);
|
|
|
|
// Verify SAVE button in AppBar and stop controls remain visible and reachable
|
|
expect(find.text('SAVE'), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('route_planner_add_stop_button')), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('route_planner_current_gps_button')), findsOneWidget);
|
|
expect(find.text('No stops added yet.'), findsOneWidget);
|
|
|
|
// No RenderFlex overflow
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('RoutePlannerScreen handles constrained 360x360 and 320x320 dimensions without overflow', (tester) async {
|
|
// Severely constrained 360x360 viewport
|
|
await tester.binding.setSurfaceSize(const Size(360, 360));
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => const AuthUser(
|
|
uid: 'alice',
|
|
isAnonymous: false,
|
|
)),
|
|
isProSubscriberProvider.overrideWith((ref) => false),
|
|
],
|
|
child: const MaterialApp(
|
|
home: RoutePlannerScreen(),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
final titleField = find.byType(TextField).first;
|
|
await tester.enterText(titleField, 'Constrained 360');
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Constrained 360'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
|
|
// Extremely constrained 320x320 viewport
|
|
await tester.binding.setSurfaceSize(const Size(320, 320));
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.enterText(titleField, 'Constrained 320');
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Constrained 320'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('RoutePlannerScreen landscape layout (800x360) renders without RenderFlex overflow', (tester) async {
|
|
// Landscape orientation on wide screen
|
|
await tester.binding.setSurfaceSize(const Size(800, 360));
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [
|
|
currentUserProvider.overrideWith((ref) => const AuthUser(
|
|
uid: 'alice',
|
|
isAnonymous: false,
|
|
)),
|
|
isProSubscriberProvider.overrideWith((ref) => false),
|
|
],
|
|
child: const MaterialApp(
|
|
home: RoutePlannerScreen(),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
// Verify title field and controls render properly
|
|
final titleField = find.byType(TextField).first;
|
|
await tester.enterText(titleField, 'Skyline Ridge Landscape');
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Skyline Ridge Landscape'), findsOneWidget);
|
|
expect(find.text('SAVE'), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('route_planner_add_stop_button')), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('route_planner_current_gps_button')), findsOneWidget);
|
|
|
|
// No RenderFlex overflow
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
}
|