Die Tagesauswahl liegt lokal pro Fahrer und wurde ungeprüft wiederhergestellt. Durch den alten Session-Fehler hatte 414 auf dem Gerät das Fahrzeug von 423 gespeichert — das erschien weiter, obwohl „Fahrzeug verwalten" (frisch vom Server) leer war. CarSelectBloc lädt beim Wiederherstellen die Fahrzeuge des Accounts vom Server und übernimmt die Auswahl nur, wenn das Fahrzeug dazugehört und aktiv ist; sonst wird sie verworfen und neu abgefragt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
137 lines
4.5 KiB
Dart
137 lines
4.5 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:hl_lieferservice/data/network/auth_session_event.dart';
|
|
import 'package:hl_lieferservice/data/network/keycloak_oidc_token_provider.dart';
|
|
import 'package:hl_lieferservice/domain/entity/payment_method.dart';
|
|
import 'package:hl_lieferservice/domain/repository/payment_methods_repository.dart';
|
|
import 'package:hl_lieferservice/feature/authentication/bloc/auth_bloc.dart';
|
|
import 'package:hl_lieferservice/feature/car_selection/bloc/bloc.dart';
|
|
import 'package:hl_lieferservice/feature/delivery/bloc/tour_date_cubit.dart';
|
|
import 'package:hl_lieferservice/feature/payment_methods/bloc/payment_methods_cubit.dart';
|
|
import 'package:hl_lieferservice/main.dart' show locator;
|
|
import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart';
|
|
import 'package:hl_lieferservice/widget/session_scope.dart';
|
|
import 'package:holzleitner_api/holzleitner_api.dart' show HolzleitnerApi;
|
|
|
|
/// Token-Provider ohne Keycloak: der Test steuert Login/Logout über [emit].
|
|
class _FakeTokenProvider implements KeycloakOidcTokenProvider {
|
|
final _events = StreamController<AuthSessionEvent>.broadcast();
|
|
|
|
void emit(AuthSessionEvent event) => _events.add(event);
|
|
|
|
@override
|
|
Stream<AuthSessionEvent> get events => _events.stream;
|
|
|
|
@override
|
|
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
|
}
|
|
|
|
class _CountingPaymentMethods implements PaymentMethodsRepository {
|
|
int loads = 0;
|
|
|
|
@override
|
|
Future<List<PaymentMethod>> list({bool includeInactive = false}) async {
|
|
loads++;
|
|
return const [];
|
|
}
|
|
|
|
@override
|
|
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
|
}
|
|
|
|
AuthLoggedIn _login(int personalnummer) =>
|
|
AuthLoggedIn({'personalnummer': personalnummer, 'name': 'Fahrer'});
|
|
|
|
void main() {
|
|
// Session-Blocs bauen ihre Repositories gegen den API-Client; im Test
|
|
// reicht ein unbenutzter Client (es wird nichts geladen).
|
|
setUpAll(() {
|
|
if (!locator.isRegistered<HolzleitnerApi>()) {
|
|
locator.registerSingleton<HolzleitnerApi>(HolzleitnerApi());
|
|
}
|
|
});
|
|
|
|
late _FakeTokenProvider provider;
|
|
late _CountingPaymentMethods payments;
|
|
late List<CarSelectBloc> carSelections;
|
|
late List<TourDateCubit> tourDates;
|
|
|
|
Future<void> pumpApp(WidgetTester tester) async {
|
|
provider = _FakeTokenProvider();
|
|
payments = _CountingPaymentMethods();
|
|
carSelections = [];
|
|
tourDates = [];
|
|
await tester.pumpWidget(
|
|
MultiBlocProvider(
|
|
providers: [
|
|
BlocProvider(create: (_) => OperationBloc()),
|
|
BlocProvider(
|
|
create: (context) => AuthBloc(
|
|
tokenProvider: provider,
|
|
operationBloc: context.read<OperationBloc>(),
|
|
),
|
|
),
|
|
BlocProvider(
|
|
create: (_) => PaymentMethodsCubit(repository: payments),
|
|
),
|
|
],
|
|
child: SessionScope(
|
|
environmentId: 'test',
|
|
child: MaterialApp(
|
|
home: Builder(
|
|
builder: (context) {
|
|
carSelections.add(context.read<CarSelectBloc>());
|
|
tourDates.add(context.read<TourDateCubit>());
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> send(WidgetTester tester, AuthSessionEvent event) async {
|
|
provider.emit(event);
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
testWidgets('jede Anmeldung bekommt frische Fahrer-Blocs', (tester) async {
|
|
await pumpApp(tester);
|
|
|
|
await send(tester, _login(423));
|
|
final fuer423 = carSelections.last;
|
|
expect(payments.loads, 1);
|
|
|
|
// Abmelden und anderer Fahrer: nichts von 423 darf übrig bleiben.
|
|
await send(tester, const AuthLoggedOut());
|
|
await send(tester, _login(414));
|
|
expect(carSelections.last, isNot(same(fuer423)));
|
|
expect(tourDates.last, isNot(same(tourDates.first)));
|
|
expect(payments.loads, 2);
|
|
|
|
// Auch derselbe Fahrer nach erneutem Login lädt neu.
|
|
final fuer414 = carSelections.last;
|
|
await send(tester, const AuthLoggedOut());
|
|
await send(tester, _login(414));
|
|
expect(carSelections.last, isNot(same(fuer414)));
|
|
expect(payments.loads, 3);
|
|
});
|
|
|
|
testWidgets('Token-Refresh desselben Fahrers behält die Blocs',
|
|
(tester) async {
|
|
await pumpApp(tester);
|
|
await send(tester, _login(423));
|
|
final vorher = carSelections.last;
|
|
|
|
await send(tester, _login(423));
|
|
|
|
expect(carSelections.last, same(vorher));
|
|
expect(payments.loads, 1);
|
|
});
|
|
}
|