- Leer-Ansichten (Auswählen, Sortieren, Beladen, Ausliefern) nennen den gewählten Tag statt immer „heute": „Für den 02.09.2026 ist keine Tour zugewiesen." (TourDayText). - TourBloc: Loads/Refreshes laufen nebenläufig; bei schnellem Datumswechsel konnte die langsamere Antwort des vorigen Tages die Tour des gewählten Tages überschreiben. Jetzt schreibt nur die jüngste Anfrage ihr Ergebnis. - Kalender reicht 90 statt 14 Tage zurück (z. B. nachimportierte Touren vom Monatsanfang). - Test: neuer Fahrer startet auf „heute", auch wenn der vorige einen anderen Tag gewählt hatte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
141 lines
4.7 KiB
Dart
141 lines
4.7 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);
|
|
// 423 schaut sich einen anderen Tag an …
|
|
tourDates.last.pick(DateTime(2026, 9, 2));
|
|
|
|
// 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)));
|
|
// … der nächste Fahrer startet trotzdem auf „heute".
|
|
expect(tourDates.last.state, isNull);
|
|
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);
|
|
});
|
|
}
|