import 'package:fancake/features/quest/quest_data.dart'; import 'package:cloud_firestore/cloud_firestore.dart' show Timestamp; import 'package:fancake/features/quest/quest_repository_firestore.dart' show questTitle, questToday; import 'package:fancake/features/quest/widgets/quest_card_tile.dart' show questImage; import 'package:flutter_test/flutter_test.dart'; /// HOME 과 퀘스트 목록 · 상세가 같이 쓰는 오늘 판정(2026-10-04 실기기 4-1 · 4-9). void main() { // 2026-10-04 09:00 KST. final now = DateTime.utc(2026, 10, 4); const quest = {'dailyLimit': 1}; const policy = {}; test('지난 날의 진행 행은 오늘 0 회다 — 9/21 출석이 10/4 에 「보상 완료」로 남지 않는다', () { final r = questToday(QuestType.attend, quest, {'dayKey': '2026-09-21', 'count': 1}, policy, now); expect(r.count, 0); expect(r.done, isFalse); }); test('오늘(KST) 행이면 완료다', () { final r = questToday(QuestType.attend, quest, {'dayKey': '2026-10-04', 'count': 1}, policy, now); expect(r.done, isTrue); }); test('날짜 경계는 KST — UTC 10/3 15:00 은 KST 10/4 0 시다', () { final r = questToday(QuestType.attend, quest, {'dayKey': '2026-10-04', 'count': 1}, policy, DateTime.utc(2026, 10, 3, 15)); expect(r.done, isTrue); final before = questToday(QuestType.attend, quest, {'dayKey': '2026-10-04', 'count': 1}, policy, DateTime.utc(2026, 10, 3, 14, 59)); expect(before.done, isFalse); }); test('타임어택은 1인 1회라 날짜로 끊지 않는다', () { final r = questToday(QuestType.timeAttack, quest, {'dayKey': '2026-09-21', 'count': 1}, policy, now); expect(r.done, isTrue); }); test('걸음은 구간을 다 받아야 완료다(B-26)', () { const tiers = {'stepTiers': [{'steps': 1000}, {'steps': 5000}]}; final one = questToday(QuestType.steps, quest, {'dayKey': '2026-10-04', 'count': 1}, tiers, now); expect(one.done, isFalse); final two = questToday(QuestType.steps, quest, {'dayKey': '2026-10-04', 'count': 2}, tiers, now); expect(two.done, isTrue); }); test('유형 · 제목으로 못 고르는 퀘스트도 아이콘 칸이 비지 않는다', () { const card = QuestCard( id: 'daily-heart', title: '심박 기록 남기기', categoryName: 'c', author: QuestAuthor.admin, stage: QuestStage.notStarted, goal: 1, progress: 0, rewardPop: 80, participants: 0, ); expect(questImage(card), 'assets/figma/quest-img-bolt.png'); }); // 10/6 실기기 — 운영 Quest 제목은 언어별 지도라 HOME 카드 제목이 비었다. 타임어택은 회차 제목이 먼저다. test('Quest 제목 — 문자열 · 언어별 지도(앱 언어 → ko) · 열린 타임어택 회차 제목', () { expect(questTitle({'title': '만보기'}), '만보기'); expect(questTitle({'title': {'en': 'Stream', 'ko': '스트리밍'}}), '스트리밍'); expect(questTitle({'title': {'en': 'Stream'}}), 'Stream'); final round = { 'roundId': 'r1', 'title': '긴급 돌발', 'activeFrom': Timestamp.fromDate(DateTime.now().subtract(const Duration(minutes: 5))), 'activeTo': Timestamp.fromDate(DateTime.now().add(const Duration(minutes: 5))), }; expect(questTitle({'title': {'ko': '스트리밍'}, 'timeAttack': round}), '긴급 돌발'); expect(questTitle({'title': {'ko': '스트리밍'}, 'timeAttack': {...round, 'title': ''}}), '스트리밍'); }); }