import 'dart:async';
import 'package:consumer_app/core/errors/api_error_code.dart';
import 'package:consumer_app/features/image_suggestion/image_suggestion_status_page.dart';
import 'package:consumer_app/l10n/app_localizations.dart';
import 'package:consumer_app/models/image_suggestion_models.dart';
import 'package:consumer_app/repositories/image_suggestion_repository.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('renders the localized empty status state', (tester) async {
await tester.pumpWidget(
_app(ImageSuggestionStatusPage(repository: _EmptyRepository())),
);
await tester.pumpAndSettle();
expect(
find.text('Du hast noch keine Bilder vorgeschlagen.'),
findsOneWidget,
);
});
testWidgets('renders all public moderation status labels', (tester) async {
await tester.pumpWidget(
_app(ImageSuggestionStatusPage(repository: _StatusRepository())),
);
await tester.pumpAndSettle();
expect(find.textContaining('Status: Eingereicht'), findsOneWidget);
expect(find.textContaining('Status: In Prüfung'), findsOneWidget);
expect(find.textContaining('Status: Akzeptiert'), findsOneWidget);
expect(find.textContaining('Status: Abgelehnt'), findsOneWidget);
expect(
find.textContaining('Status: Rückfrage erforderlich'),
findsOneWidget,
);
expect(find.textContaining('Eingereicht:'), findsWidgets);
expect(find.byTooltip('Rückfrage beantworten'), findsOneWidget);
});
testWidgets('renders the authentication state for private status access', (
tester,
) async {
await tester.pumpWidget(
_app(
ImageSuggestionStatusPage(repository: _PermissionDeniedRepository()),
),
);
await tester.pumpAndSettle();
expect(find.text('Anmeldung erforderlich'), findsOneWidget);
});
testWidgets('pull to refresh waits for the new status response', (
tester,
) async {
final repository = _RefreshRepository();
await tester.pumpWidget(
_app(ImageSuggestionStatusPage(repository: repository)),
);
await tester.pumpAndSettle();
expect(find.textContaining('Status: Eingereicht'), findsOneWidget);
expect(repository.calls, 1);
final refreshIndicator = tester.widget<RefreshIndicator>(
find.byType(RefreshIndicator),
);
final refresh = refreshIndicator.onRefresh();
await tester.pump();
expect(repository.calls, 2);
expect(find.byType(CircularProgressIndicator), findsOneWidget);
repository.complete(ImageSuggestionList([_item(1, 'accepted')]));
await refresh;
await tester.pumpAndSettle();
expect(find.textContaining('Status: Akzeptiert'), findsOneWidget);
});
}
Widget _app(Widget child) {
return MaterialApp(
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
locale: const Locale('de'),
home: child,
);
}
class _EmptyRepository extends _BaseRepository {
@override
Future<ImageSuggestionList> own({String? status}) async {
return const ImageSuggestionList([]);
}
}
class _StatusRepository extends _BaseRepository {
@override
Future<ImageSuggestionList> own({String? status}) async {
return ImageSuggestionList([
_item(1, 'submitted'),
_item(2, 'in_review'),
_item(3, 'accepted'),
_item(4, 'rejected'),
_item(5, 'needs_info'),
]);
}
}
class _PermissionDeniedRepository extends _BaseRepository {
@override
Future<ImageSuggestionList> own({String? status}) async {
throw const ApiException(
ApiErrorCode.permissionDenied,
statusCode: 401,
serverCode: 'meinweimar_auth_required',
);
}
}
class _RefreshRepository extends _BaseRepository {
int calls = 0;
Completer<ImageSuggestionList>? _pending;
@override
Future<ImageSuggestionList> own({String? status}) {
calls++;
if (calls == 1) {
return Future.value(ImageSuggestionList([_item(1, 'submitted')]));
}
_pending = Completer<ImageSuggestionList>();
return _pending!.future;
}
void complete(ImageSuggestionList result) {
_pending?.complete(result);
}
}
abstract class _BaseRepository implements ImageSuggestionRepository {
@override
Future<ImageSuggestionData> submit({
required String targetType,
required int targetId,
required List<int> bytes,
required String filename,
required bool rightsHolderConfirmed,
required bool lawfulSourceConfirmed,
required bool personsConsentConfirmed,
required bool platformLicenseConfirmed,
required String idempotencyKey,
String source = '',
String license = '',
String photographer = '',
String description = '',
}) => throw UnimplementedError();
@override
Future<ImageSuggestionData> respond({
required int suggestionId,
required String response,
required String idempotencyKey,
}) => throw UnimplementedError();
}
ImageSuggestionData _item(int id, String status) {
return ImageSuggestionData(
id: id,
targetType: 'places',
targetId: 453,
status: status,
originalFilename: 'place-$id.jpg',
createdAt: '2026-01-02T03:04:00Z',
updatedAt: '2026-01-02T03:04:00Z',
reasonCode: status,
mediaCandidateId: status == 'accepted' ? 11 : 0,
technicalStatus: 'passed',
malwareStatus: 'passed',
requestMessage: status == 'needs_info' ? 'Bitte ergänze die Quelle.' : '',
);
}
