import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:friendly_map/modules/app/app.dart'; import 'package:friendly_map/modules/storage/storage.dart'; import 'package:friendly_map/modules/transport/transport.dart'; import 'package:friendly_map/modules/ui/src/screens/person_screen.dart'; import 'package:friendly_map/modules/ui/ui.dart'; import 'support/app_device.dart'; import 'support/fake_cipher.dart'; import 'support/storage_contract.dart' show FakeProbe; /// 키·저장소를 어떻게 여는지는 화면이 모른다. 시험에서는 메모리 기기로 대신한다. class FakeBootstrap implements Bootstrap { FakeBootstrap({this.keys = false, this.app}); bool keys; final FriendlyApp? app; @override Future hasKeys() async => keys; @override Future createKeys() async { keys = true; return 'one two three four five six seven eight nine ten eleven twelve'; } @override Future restoreKeys(String phrase) async => false; @override Future> splitRecovery(int n, int k) async => [for (var i = 1; i <= n; i++) 'fmr1.$k.0000.$i:00']; @override Future openApp() async => app!; @override Future recoveryPhrase() async => null; } void main() { Future openWithFriend(WidgetTester tester) async { final device = await tester.runAsync(() => AppDevice.create(MemoryHub(), '010-1111-2222', '+821011112222', '이미영', start: false)); await tester.pumpWidget(FriendlyMapApp(bootstrap: FakeBootstrap(keys: true, app: device!.app))); await tester.pumpAndSettle(); return device.app; } Future tab(WidgetTester tester, String label) async { await tester.tap(find.descendant(of: find.byType(NavigationBar), matching: find.text(label))); await tester.pumpAndSettle(); } testWidgets('처음 시작: 복구 코드 없이 이름·번호만 넣으면 바로 채팅 화면', (tester) async { final app = FriendlyApp(AppDeps( storage: Storage.memory(), transport: MemoryTransport('+821011112222', MemoryHub()), cipher: FakeCipher('K'), identity: FakeIdentity('K'), probe: FakeProbe(10), )); final boot = FakeBootstrap(app: app); await tester.pumpWidget(FriendlyMapApp(bootstrap: boot)); await tester.pumpAndSettle(); expect(find.text('시작하기'), findsOneWidget); expect(find.textContaining('복구'), findsNothing); await tester.enterText(find.byType(TextField).at(0), '이미영'); await tester.enterText(find.byType(TextField).at(1), '010-1111-2222'); await tester.pump(); await tester.tap(find.text('시작하기')); await tester.runAsync(() => Future.delayed(const Duration(milliseconds: 50))); await tester.pumpAndSettle(); expect(boot.keys, isTrue, reason: '키는 조용히 만들어진다'); expect(find.byType(NavigationBar), findsOneWidget); expect(find.text('아직 대화가 없어요'), findsOneWidget); }); testWidgets('아래 메뉴: 채팅 · 관계 · 업무 · 명함 · 나', (tester) async { await openWithFriend(tester); for (final l in ['채팅', '관계', '업무', '명함', '나']) { expect(find.descendant(of: find.byType(NavigationBar), matching: find.text(l)), findsOneWidget); } await tab(tester, '명함'); expect(find.text('내 명함'), findsWidgets); await tab(tester, '나'); expect(find.text('010-1111-2222'), findsOneWidget, reason: '번호는 010 형식으로'); }); testWidgets('관계 탭: 그룹 네 개, 새 그룹 더하기, 학교 안에 하위 그룹', (tester) async { await openWithFriend(tester); await tab(tester, '관계'); for (final n in ['가족', '학교', '회사', '그룹·여행']) { expect(find.text(n), findsOneWidget); } await tester.tap(find.text('새 그룹')); await tester.pumpAndSettle(); await tester.enterText(find.byType(TextField).last, '등산 모임'); await tester.tap(find.text('확인')); await tester.runAsync(() => Future.delayed(const Duration(milliseconds: 50))); await tester.pumpAndSettle(); await tester.scrollUntilVisible(find.text('등산 모임'), 200, scrollable: find.byType(Scrollable).first); expect(find.text('등산 모임'), findsOneWidget); await tester.scrollUntilVisible(find.text('학교'), -200, scrollable: find.byType(Scrollable).first); await tester.tap(find.text('학교')); await tester.pumpAndSettle(); expect(find.text('고등학교'), findsOneWidget); expect(find.text('대학원'), findsOneWidget); }); testWidgets('사람 화면의 관계 버튼으로 학교 › 고등학교에 넣으면 들어간 그룹이 보인다', (tester) async { final device = await tester.runAsync(() => AppDevice.create(MemoryHub(), '010-1111-2222', '+821011112222', '이미영', start: false)); final app = device!.app; final friend = await tester.runAsync(() => app.friends.add('+821033334444', '김민수')); await tester.pumpWidget(FriendlyMapApp(bootstrap: FakeBootstrap(keys: true, app: app))); await tester.pumpAndSettle(); tester.state(find.byType(Navigator).first).push(MaterialPageRoute(builder: (_) => PersonScreen(personId: friend!.id))); await tester.pumpAndSettle(); expect(find.text('010-3333-4444'), findsOneWidget); expect(find.textContaining('관계 정하기 —'), findsOneWidget); await tester.tap(find.text('관계')); await tester.pumpAndSettle(); await tester.tap(find.textContaining('학교 동문')); await tester.pumpAndSettle(); await tester.tap(find.text('고등학교')); await tester.runAsync(() => Future.delayed(const Duration(milliseconds: 50))); await tester.pumpAndSettle(); expect(find.text('학교 › 고등학교'), findsOneWidget); }); }