iop/apps/client/test/notification_integration_test.dart
toki 01dc2ef78b refactor: readability baseline 및 테스트 구조 개선
- agent-readable-repository-refactor 완료: 기존 테스트 파일 아카이브 이동
- 새 테스트 파일 추가 (edge, node, client, config, readability)
- readability_audit 스크립트 및 baseline 추가
- roadmap/SDD 문서 갱신
- agent-client/pi/extensions/openai-sampling-parameters 추가
2026-07-17 16:02:12 +09:00

124 lines
4 KiB
Dart

import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:iop_client/main.dart';
import 'package:iop_client/src/integrations/nexo/nexo_notification_host_integration.dart';
import 'support/client_test_harness.dart';
void main() {
testWidgets(
'notification stream from NexoNotificationHostIntegration connects to UI snackbar',
(WidgetTester tester) async {
final fakeClient = FakeClientWireClient(shouldSuccess: true);
final fakeStatusRepo = FakeControlPlaneStatusRepository();
// Create a fake NexoNotificationClient that emits a notification.
final notificationController = StreamController<Map<String, dynamic>>();
final fakeNexoClient = FakeNexoClientsForUiTest(notificationController);
final fakeHost = NexoNotificationHostIntegration(
pushClient: fakeNexoClient,
);
await tester.pumpWidget(
IopClientApp(
testClient: fakeClient,
statusRepository: fakeStatusRepo,
notificationHost: fakeHost,
),
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
// Verify wire status shows connected.
expect(find.text('CONNECTED'), findsOneWidget);
// Emit a notification message through the fake client.
notificationController.add(const {
'type': 'message',
'message': 'Hello from Nexo',
'channel_name': 'general',
'sender_name': 'test-user',
});
await tester.pump();
// Verify the SnackBar appears in the UI.
expect(find.textContaining('Hello from Nexo'), findsOneWidget);
await notificationController.close();
},
);
testWidgets(
'notification stream shows channel-only message when sender is empty',
(WidgetTester tester) async {
final fakeClient = FakeClientWireClient(shouldSuccess: true);
final fakeStatusRepo = FakeControlPlaneStatusRepository();
final notificationController = StreamController<Map<String, dynamic>>();
final fakeNexoClient = FakeNexoClientsForUiTest(notificationController);
final fakeHost = NexoNotificationHostIntegration(
pushClient: fakeNexoClient,
);
await tester.pumpWidget(
IopClientApp(
testClient: fakeClient,
statusRepository: fakeStatusRepo,
notificationHost: fakeHost,
),
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
expect(find.text('CONNECTED'), findsOneWidget);
// Emit notification with empty sender — should show just the message.
notificationController.add(const {
'type': 'message',
'message': 'Direct message content',
'channel_name': 'alerts',
'sender_name': '',
});
await tester.pump();
// When sender is empty, only message content is shown.
expect(find.textContaining('Direct message content'), findsOneWidget);
await notificationController.close();
},
);
testWidgets('notification stream ignores non-message events (e.g. system)', (
WidgetTester tester,
) async {
final fakeClient = FakeClientWireClient(shouldSuccess: true);
final fakeStatusRepo = FakeControlPlaneStatusRepository();
final notificationController = StreamController<Map<String, dynamic>>();
final fakeNexoClient = FakeNexoClientsForUiTest(notificationController);
final fakeHost = NexoNotificationHostIntegration(
pushClient: fakeNexoClient,
);
await tester.pumpWidget(
IopClientApp(
testClient: fakeClient,
statusRepository: fakeStatusRepo,
notificationHost: fakeHost,
),
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
// Emit a non-message type.
notificationController.add(const {
'type': 'system',
'message': 'System notification',
});
await tester.pump();
// No SnackBar should appear for non-message types.
expect(find.textContaining('System notification'), findsNothing);
await notificationController.close();
});
}