import 'package:consumer_app/features/notifications/notification_inbox_page.dart';
import 'package:consumer_app/core/errors/api_error_code.dart';
import 'package:consumer_app/l10n/app_localizations.dart';
import 'package:consumer_app/models/image_suggestion_models.dart';
import 'package:consumer_app/models/notification_models.dart';
import 'package:consumer_app/repositories/image_suggestion_repository.dart';
import 'package:consumer_app/repositories/notifications_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 state', (tester) async {
await tester.pumpWidget(
_app(
NotificationInboxPage(
repository: _FakeNotificationsRepository(initial: const []),
),
),
);
await tester.pumpAndSettle();
expect(find.text('Keine Benachrichtigungen'), findsOneWidget);
expect(
find.text('Hier erscheinen deine persönlichen Hinweise.'),
findsOneWidget,
);
});
testWidgets('renders an authentication state for a denied private read', (
tester,
) async {
await tester.pumpWidget(
_app(
NotificationInboxPage(
repository: _PermissionDeniedNotificationsRepository(),
),
),
);
await tester.pumpAndSettle();
expect(find.text('Anmeldung erforderlich'), findsOneWidget);
});
testWidgets('opens the own image suggestion from its notification', (
tester,
) async {
final notifications = _FakeNotificationsRepository();
final suggestions = _FakeImageSuggestionRepository();
await tester.pumpWidget(
_app(
NotificationInboxPage(
repository: notifications,
imageSuggestionRepository: suggestions,
),
),
);
await tester.pumpAndSettle();
expect(find.text('Bildvorschlag aktualisiert'), findsOneWidget);
await tester.tap(find.text('Bildvorschlag aktualisiert'));
await tester.pumpAndSettle();
expect(notifications.markedId, 1);
expect(find.text('Meine Bildvorschläge'), findsOneWidget);
expect(find.text('weimar.jpg'), findsOneWidget);
});
testWidgets('localizes status and acknowledges an unread notification', (
tester,
) async {
final notifications = _FakeNotificationsRepository();
await tester.pumpWidget(
_app(NotificationInboxPage(repository: notifications)),
);
await tester.pumpAndSettle();
expect(
find.text('Der Bildvorschlag hat den Status: Akzeptiert.'),
findsOneWidget,
);
await tester.tap(find.text('Bildvorschlag aktualisiert'));
await tester.pumpAndSettle();
expect(notifications.markedId, 1);
expect(find.byIcon(Icons.notifications_active_outlined), findsNothing);
expect(find.byIcon(Icons.notifications_none_outlined), findsNWidgets(2));
});
}
Widget _app(Widget home) {
return MaterialApp(
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('de')],
locale: const Locale('de'),
home: home,
);
}
class _FakeNotificationsRepository implements NotificationsRepository {
int? markedId;
_FakeNotificationsRepository({List<NotificationData>? initial})
: items =
initial ??
const [
NotificationData(
id: 1,
type: 'image_suggestion_status',
targetType: 'mw_place',
targetId: 453,
payload: {'suggestion_id': '8', 'status': 'accepted'},
status: 'unread',
createdAt: '',
readAt: '',
),
];
List<NotificationData> items;
@override
Future<NotificationList> list({String? status}) async {
final filtered = status == null
? items
: items.where((item) => item.status == status).toList(growable: false);
return NotificationList(filtered);
}
@override
Future<void> markRead(int id) async {
markedId = id;
items = items
.map(
(item) => item.id == id
? NotificationData(
id: item.id,
type: item.type,
targetType: item.targetType,
targetId: item.targetId,
payload: item.payload,
status: 'read',
createdAt: item.createdAt,
readAt: '2026-09-21T00:00:00Z',
)
: item,
)
.toList(growable: false);
}
}
class _PermissionDeniedNotificationsRepository
implements NotificationsRepository {
@override
Future<NotificationList> list({String? status}) =>
Future<NotificationList>.error(
const ApiException(ApiErrorCode.permissionDenied),
);
@override
Future<void> markRead(int id) async {}
}
class _FakeImageSuggestionRepository implements ImageSuggestionRepository {
@override
Future<ImageSuggestionList> own({String? status}) async {
return const ImageSuggestionList([
ImageSuggestionData(
id: 8,
targetType: 'mw_place',
targetId: 453,
status: 'accepted',
originalFilename: 'weimar.jpg',
createdAt: '',
updatedAt: '',
reasonCode: '',
mediaCandidateId: 0,
technicalStatus: 'passed',
malwareStatus: 'passed',
),
]);
}
@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();
}
