앱 단위·화면·통합 테스트
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
import 'package:fancake/core/ui/app_icons.dart';
|
||||
import 'package:fancake/features/notification/notification_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// F0 공통 — 화면 대조 원장 2화면.
|
||||
/// Bottom Navigation(`350:215853`)은 5탭 셸이라 `app_smoke_test` 가 검증한다.
|
||||
|
||||
Future<void> pumpWide(WidgetTester tester, Widget child) async {
|
||||
tester.view.physicalSize = const Size(1080, 2400);
|
||||
tester.view.devicePixelRatio = 3.0;
|
||||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(MaterialApp(home: child));
|
||||
await tester.pump();
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('날짜 머리글 (F0 · 518:88353)', () {
|
||||
final now = DateTime(2026, 9, 1, 12);
|
||||
|
||||
test('오늘과 어제만 이름으로 부른다', () {
|
||||
expect(notificationDayLabel(DateTime(2026, 9, 1, 3), now: now), '오늘');
|
||||
expect(notificationDayLabel(DateTime(2026, 8, 31, 23), now: now), '어제');
|
||||
expect(
|
||||
notificationDayLabel(DateTime(2026, 8, 30), now: now),
|
||||
'2026.08.30',
|
||||
);
|
||||
});
|
||||
|
||||
test('생성일시는 명세 형식을 그대로 쓴다', () {
|
||||
expect(
|
||||
notificationTimestamp(DateTime(2026, 1, 2, 3, 4)),
|
||||
'2026.01.02 03:04',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('날짜 그룹화', () {
|
||||
final now = DateTime(2026, 9, 1, 12);
|
||||
|
||||
test('날짜로 묶고 최신이 앞에 온다', () {
|
||||
final items = [
|
||||
AppNotification(
|
||||
id: 'a',
|
||||
kind: NotificationKind.like,
|
||||
title: 'a',
|
||||
at: DateTime(2026, 8, 30, 9),
|
||||
),
|
||||
AppNotification(
|
||||
id: 'b',
|
||||
kind: NotificationKind.like,
|
||||
title: 'b',
|
||||
at: DateTime(2026, 9, 1, 9),
|
||||
),
|
||||
AppNotification(
|
||||
id: 'c',
|
||||
kind: NotificationKind.like,
|
||||
title: 'c',
|
||||
at: DateTime(2026, 9, 1, 11),
|
||||
),
|
||||
];
|
||||
final groups = groupNotifications(items, now: now);
|
||||
expect(groups.map((g) => g.label).toList(), ['오늘', '2026.08.30']);
|
||||
expect(groups.first.items.map((i) => i.id).toList(), ['c', 'b']);
|
||||
});
|
||||
});
|
||||
|
||||
group('종류별 이동 (F0 · 518:88353)', () {
|
||||
test('이클립스와 아이템 사용은 이동하지 않는다', () {
|
||||
expect(NotificationKind.eclipse.navigable, isFalse);
|
||||
expect(NotificationKind.itemUsed.navigable, isFalse);
|
||||
});
|
||||
|
||||
test('나머지 넷은 갈 곳이 있다', () {
|
||||
for (final kind in const [
|
||||
NotificationKind.like,
|
||||
NotificationKind.comment,
|
||||
NotificationKind.campaign,
|
||||
NotificationKind.quest,
|
||||
]) {
|
||||
expect(kind.navigable, isTrue, reason: kind.label);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
group('알림 화면 (F0 · 229:11265)', () {
|
||||
testWidgets('날짜 머리글과 항목을 함께 보여 준다', (tester) async {
|
||||
// 표본은 DateTime.now() 기준이라 자정 전후로 「오늘/어제」가 갈린다.
|
||||
// 시각을 못박아 넣는다.
|
||||
final now = DateTime.now();
|
||||
await pumpWide(
|
||||
tester,
|
||||
NotificationScreen(
|
||||
repository: SampleNotificationRepository(
|
||||
items: [
|
||||
AppNotification(
|
||||
id: 'q',
|
||||
kind: NotificationKind.quest,
|
||||
title: '만보기 퀘스트를 완료했습니다',
|
||||
at: now,
|
||||
),
|
||||
AppNotification(
|
||||
id: 'o',
|
||||
kind: NotificationKind.like,
|
||||
title: '오래된 알림',
|
||||
at: now.subtract(const Duration(days: 9)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(find.text('오늘'), findsOneWidget);
|
||||
expect(find.textContaining('만보기 퀘스트를 완료'), findsOneWidget);
|
||||
expect(find.text('오래된 알림'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('이동하지 않는 알림에는 화살표를 그리지 않는다', (tester) async {
|
||||
await pumpWide(
|
||||
tester,
|
||||
NotificationScreen(
|
||||
repository: SampleNotificationRepository(
|
||||
items: [
|
||||
AppNotification(
|
||||
id: 'e',
|
||||
kind: NotificationKind.eclipse,
|
||||
title: '이클립스',
|
||||
at: DateTime.now(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(w) => w is ImageIcon && w.image == AppIcons.chevronRight,
|
||||
),
|
||||
findsNothing,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('누르면 읽음으로 바뀌고 뒤로가기가 읽은 목록을 돌려준다', (tester) async {
|
||||
final items = [
|
||||
AppNotification(
|
||||
id: 'n1',
|
||||
kind: NotificationKind.quest,
|
||||
title: '만보기 퀘스트를 완료했습니다',
|
||||
at: DateTime.now(),
|
||||
),
|
||||
];
|
||||
Set<String>? returned;
|
||||
await pumpWide(
|
||||
tester,
|
||||
Builder(
|
||||
builder: (context) => TextButton(
|
||||
onPressed: () async {
|
||||
returned = await Navigator.of(context).push<Set<String>>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => NotificationScreen(
|
||||
repository: SampleNotificationRepository(items: items),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('열기'),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.text('열기'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.textContaining('만보기 퀘스트를 완료'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(returned, contains('n1'));
|
||||
});
|
||||
|
||||
testWidgets('비어 있으면 그렇게 알린다', (tester) async {
|
||||
await pumpWide(
|
||||
tester,
|
||||
NotificationScreen(
|
||||
repository: const SampleNotificationRepository(items: []),
|
||||
),
|
||||
);
|
||||
expect(find.text('알림이 없습니다.'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('문구에 내부 경로가 새지 않는다', (tester) async {
|
||||
await pumpWide(
|
||||
tester,
|
||||
NotificationScreen(repository: const SampleNotificationRepository()),
|
||||
);
|
||||
await tester.pump();
|
||||
for (final text in tester.widgetList<Text>(find.byType(Text))) {
|
||||
final data = text.data ?? '';
|
||||
expect(data, isNot(contains('lib/')));
|
||||
expect(data, isNot(contains('.dart')));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user