import 'dart:async';
import 'package:consumer_app/core/location/location_controller.dart';
import 'package:consumer_app/core/location/location_service.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:geolocator/geolocator.dart';
void main() {
test(
'persists the granted coordinate for the next discovery surface',
() async {
final storage = _MemoryLocationStorage();
final controller = LocationController(
storage: storage,
service: LocationService(provider: _FakeProvider()),
);
final result = await controller.requestLocation();
await controller.markStartupPromptCompleted();
expect(result.access, LocationAccess.granted);
expect(controller.coordinate?.latitude, 50.9795);
expect(controller.startupPromptCompleted, isTrue);
final restored = LocationController(storage: storage);
await restored.restore();
expect(restored.access, LocationAccess.granted);
expect(restored.coordinate?.longitude, 11.3235);
expect(restored.startupPromptCompleted, isTrue);
},
);
test('denied access clears a previously persisted coordinate', () async {
final storage = _MemoryLocationStorage(
state: const LocationPersistedState(
access: LocationAccess.granted,
coordinate: LocationCoordinate(latitude: 50.98, longitude: 11.32),
),
);
final controller = LocationController(
storage: storage,
service: LocationService(
provider: _FakeProvider(permission: LocationPermission.deniedForever),
),
);
final result = await controller.requestLocation();
expect(result.access, LocationAccess.denied);
expect(controller.coordinate, isNull);
expect(storage.state.coordinate, isNull);
});
test(
'a hanging browser geolocation request falls back and stops loading',
() async {
final controller = LocationController(
storage: _MemoryLocationStorage(),
service: LocationService(provider: _HangingProvider()),
requestTimeout: const Duration(milliseconds: 20),
);
final result = await controller.requestLocation();
expect(result.access, LocationAccess.unavailable);
expect(controller.access, LocationAccess.unavailable);
expect(controller.coordinate, isNull);
expect(controller.isLoading, isFalse);
},
);
test(
'a silent refresh keeps the last coordinate when geolocation is unavailable',
() async {
final storage = _MemoryLocationStorage(
state: const LocationPersistedState(
access: LocationAccess.granted,
coordinate: LocationCoordinate(latitude: 50.98, longitude: 11.32),
),
);
final controller = LocationController(
storage: storage,
service: LocationService(provider: _HangingProvider()),
requestTimeout: const Duration(milliseconds: 20),
);
final result = await controller.requestLocation(
preserveOnUnavailable: true,
);
expect(result.access, LocationAccess.unavailable);
expect(controller.access, LocationAccess.granted);
expect(controller.coordinate?.latitude, 50.98);
expect(controller.coordinate?.longitude, 11.32);
expect(storage.state.access, LocationAccess.granted);
},
);
}
class _MemoryLocationStorage implements LocationStorage {
_MemoryLocationStorage({LocationPersistedState? state})
: state = state ?? const LocationPersistedState();
LocationPersistedState state;
@override
Future<LocationPersistedState> read() async => state;
@override
Future<void> write(LocationPersistedState value) async => state = value;
}
class _FakeProvider implements LocationProvider {
_FakeProvider({this.permission = LocationPermission.whileInUse});
final LocationPermission permission;
@override
Future<bool> isLocationServiceEnabled() async => true;
@override
Future<LocationPermission> checkPermission() async => permission;
@override
Future<LocationPermission> requestPermission() async => permission;
@override
Future<Position> getCurrentPosition() async => Position(
latitude: 50.9795,
longitude: 11.3235,
timestamp: DateTime.utc(2026, 9, 30),
accuracy: 5,
altitude: 0,
altitudeAccuracy: 1,
heading: 0,
headingAccuracy: 1,
speed: 0,
speedAccuracy: 0,
);
}
class _HangingProvider implements LocationProvider {
@override
Future<bool> isLocationServiceEnabled() async => true;
@override
Future<LocationPermission> checkPermission() async =>
LocationPermission.whileInUse;
@override
Future<LocationPermission> requestPermission() async =>
LocationPermission.whileInUse;
@override
Future<Position> getCurrentPosition() => Completer<Position>().future;
}
