Tour, Datum, Fahrzeuge, Fahrzeugauswahl und Phase lebten bisher pro Server-Umgebung, nicht pro Anmeldung. Nach Abmelden von 423 und Anmelden von 414 lieferte der gecachte CarsBloc weiter die Fahrzeuge von 423. Neu: SessionScope unter dem AuthBloc legt diese Blocs bei jeder Anmeldung (neuer Fahrer oder Re-Login) komplett neu an; alles wird frisch vom Server geholt. Token-Refresh desselben Fahrers zählt nicht als neue Anmeldung. Zahlungsmethoden werden ebenfalls nach jeder Anmeldung neu geladen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
127 lines
4.1 KiB
Dart
127 lines
4.1 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/widget/operations/bloc/operation_bloc.dart';
|
|
import 'package:hl_lieferservice/widget/session_scope.dart';
|
|
|
|
/// 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() {
|
|
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);
|
|
});
|
|
}
|