128 lines
4.5 KiB
Dart
128 lines
4.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'package:fuel_tax_tracker/models/vehicle.dart';
|
|
import 'package:fuel_tax_tracker/screens/add_edit_vehicle_screen.dart';
|
|
import 'package:fuel_tax_tracker/screens/vehicle_detail_screen.dart';
|
|
import 'package:fuel_tax_tracker/services/app_state.dart';
|
|
|
|
/// Covers the "VIN already belongs to another vehicle" dialog on the Add
|
|
/// Vehicle form — [AddEditVehicleScreen] driven directly against an
|
|
/// [AppState] whose in-memory `vehicles` list is seeded by hand (no
|
|
/// database/cloud wiring needed, since the dialog only reads
|
|
/// [AppState.vehicleByVin]).
|
|
void main() {
|
|
final existingVehicle = Vehicle(
|
|
id: 'existing-id',
|
|
vin: '1FMPU18L1TLB51349',
|
|
nickname: 'Red Truck',
|
|
updatedAt: DateTime.utc(2026, 1, 1),
|
|
);
|
|
|
|
Future<AppState> pumpAddVehicleScreen(WidgetTester tester) async {
|
|
final appState = AppState()
|
|
..isLoading = false
|
|
..vehicles = [existingVehicle];
|
|
|
|
await tester.pumpWidget(
|
|
ChangeNotifierProvider.value(
|
|
value: appState,
|
|
child: const MaterialApp(home: AddEditVehicleScreen()),
|
|
),
|
|
);
|
|
return appState;
|
|
}
|
|
|
|
testWidgets('entering a VIN that already exists shows the dialog', (tester) async {
|
|
await pumpAddVehicleScreen(tester);
|
|
|
|
await tester.enterText(find.widgetWithText(TextFormField, 'VIN *'), existingVehicle.vin);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Vehicle already exists'), findsOneWidget);
|
|
expect(
|
|
find.text(
|
|
'Vehicle with the VIN ${existingVehicle.vin} already exists, would you like to open that vehicle?',
|
|
),
|
|
findsOneWidget,
|
|
);
|
|
});
|
|
|
|
testWidgets('tapping No dismisses the dialog and stays on the create screen', (tester) async {
|
|
await pumpAddVehicleScreen(tester);
|
|
|
|
await tester.enterText(find.widgetWithText(TextFormField, 'VIN *'), existingVehicle.vin);
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.tap(find.widgetWithText(TextButton, 'No'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Vehicle already exists'), findsNothing);
|
|
expect(find.text('Add Vehicle'), findsWidgets);
|
|
expect(
|
|
find.text('A vehicle with VIN "${existingVehicle.vin}" already exists.'),
|
|
findsOneWidget,
|
|
reason: 'the field itself should be flagged invalid after declining to open the existing vehicle',
|
|
);
|
|
});
|
|
|
|
testWidgets('tapping Yes opens the existing vehicle', (tester) async {
|
|
await pumpAddVehicleScreen(tester);
|
|
|
|
await tester.enterText(find.widgetWithText(TextFormField, 'VIN *'), existingVehicle.vin);
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.tap(find.widgetWithText(TextButton, 'Yes'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byType(VehicleDetailScreen), findsOneWidget);
|
|
expect(find.text(existingVehicle.displayLabel), findsOneWidget);
|
|
expect(find.byType(AddEditVehicleScreen), findsNothing,
|
|
reason: 'the create screen should be popped, not left underneath');
|
|
});
|
|
|
|
testWidgets('editing a vehicle with its own VIN does not trigger the dialog', (tester) async {
|
|
final appState = AppState()
|
|
..isLoading = false
|
|
..vehicles = [existingVehicle];
|
|
|
|
await tester.pumpWidget(
|
|
ChangeNotifierProvider.value(
|
|
value: appState,
|
|
child: MaterialApp(home: AddEditVehicleScreen(vehicle: existingVehicle)),
|
|
),
|
|
);
|
|
|
|
// The field already starts pre-filled with its own VIN; nudge it to
|
|
// fire onChanged the same way a real edit would.
|
|
await tester.enterText(find.widgetWithText(TextFormField, 'VIN *'), existingVehicle.vin);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Vehicle already exists'), findsNothing);
|
|
});
|
|
|
|
testWidgets(
|
|
'tapping the VIN scan icon shows "VIN From" with an info button explaining where to find one',
|
|
(tester) async {
|
|
await pumpAddVehicleScreen(tester);
|
|
|
|
await tester.tap(find.byTooltip('Scan VIN from a photo'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('VIN From'), findsOneWidget);
|
|
expect(find.text('Take Photo'), findsOneWidget);
|
|
expect(find.text('Choose from Gallery'), findsOneWidget);
|
|
|
|
await tester.tap(find.byIcon(Icons.info_outline));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Where to find the VIN'), findsOneWidget);
|
|
expect(find.byType(Image), findsNWidgets(2), reason: 'door jamb + windshield examples');
|
|
|
|
await tester.tap(find.text('Close'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Where to find the VIN'), findsNothing);
|
|
});
|
|
}
|