사용자 화면 문구·표본 데이터 · 퀘스트 참여 흐름 · HOME 진입 구획 · 미니맵 · 공통 확인 창 배치 수정
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
import 'package:fake_cloud_firestore/fake_cloud_firestore.dart';
|
||||
import 'package:fancake/core/data/backend.dart';
|
||||
import 'package:fancake/core/theme/app_theme.dart';
|
||||
import 'package:fancake/core/ui/section_header.dart';
|
||||
import 'package:fancake/features/campaign/campaign_create_screen.dart';
|
||||
import 'package:fancake/features/campaign/campaign_list_screen.dart';
|
||||
import 'package:fancake/features/home/home_data.dart';
|
||||
import 'package:fancake/features/home/home_repository_firestore.dart';
|
||||
import 'package:fancake/features/home/home_screen.dart';
|
||||
import 'package:fancake/features/quest/quest_data.dart';
|
||||
import 'package:firebase_auth_mocks/firebase_auth_mocks.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'eclipse_stubs.dart';
|
||||
|
||||
/// 실기기 판정(2026-10-04) HOME 결함 — HOT ARCHIVE 진입 · 브리핑 · 인기 K-INSIDE · 상태 표시줄.
|
||||
|
||||
const _uid = 'u-home';
|
||||
|
||||
class _Backend extends Backend {
|
||||
_Backend(FakeFirebaseFirestore db)
|
||||
: super(
|
||||
firestore: db,
|
||||
auth: MockFirebaseAuth(signedIn: true, mockUser: MockUser(uid: _uid)),
|
||||
);
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> call(
|
||||
String name, [
|
||||
Map<String, dynamic> payload = const {},
|
||||
]) async => {'code': 'ABCDEFGH23'};
|
||||
}
|
||||
|
||||
/// 모금 중 캠페인이 없는 HOME.
|
||||
class _NoCampaignRepo extends SampleHomeRepository {
|
||||
const _NoCampaignRepo();
|
||||
|
||||
@override
|
||||
Stream<PlanetGrowth> watchGrowth(String fandomId) => const Stream.empty();
|
||||
|
||||
@override
|
||||
Future<HomeSnapshot> load() async {
|
||||
final base = await const SampleHomeRepository().load();
|
||||
return HomeSnapshot(
|
||||
popBalance: base.popBalance,
|
||||
liveTicker: base.liveTicker,
|
||||
growth: base.growth,
|
||||
quests: base.quests,
|
||||
briefings: base.briefings,
|
||||
campaign: null,
|
||||
insides: base.insides,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _pump(WidgetTester tester, HomeRepository repo) async {
|
||||
tester.view.physicalSize = const Size(1080, 2400);
|
||||
tester.view.devicePixelRatio = 2;
|
||||
addTearDown(tester.view.reset);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: buildAppTheme(),
|
||||
home: MediaQuery(
|
||||
// 노치 단말 — 상태 표시줄 47.
|
||||
data: const MediaQueryData(
|
||||
size: Size(540, 1200),
|
||||
padding: EdgeInsets.only(top: 47),
|
||||
),
|
||||
child: HomeScreen(
|
||||
repository: repo,
|
||||
questRepository: const SampleQuestRepository(),
|
||||
eclipse: const NoEclipseRepository(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
Finder get _hotArchive => find.byWidgetPredicate(
|
||||
(w) => w is SectionHeader && w.title == 'HOT ARCHIVE',
|
||||
);
|
||||
|
||||
void main() {
|
||||
setUp(() => SharedPreferences.setMockInitialValues({}));
|
||||
|
||||
group('HOT ARCHIVE — 모금 중 캠페인 0건(명세 §2.114-6)', () {
|
||||
testWidgets('구획과 「더 보기」가 남아 캠페인 목록으로 간다', (tester) async {
|
||||
await _pump(tester, const _NoCampaignRepo());
|
||||
await tester.scrollUntilVisible(
|
||||
_hotArchive,
|
||||
220,
|
||||
scrollable: find.byType(Scrollable).first,
|
||||
);
|
||||
await tester.tap(
|
||||
find.descendant(of: _hotArchive, matching: find.text('더 보기')),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(CampaignListScreen), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('카드 자리의 「새 캠페인」이 개설 화면을 연다', (tester) async {
|
||||
await _pump(tester, const _NoCampaignRepo());
|
||||
final create = find.text('새 캠페인');
|
||||
await tester.scrollUntilVisible(
|
||||
create,
|
||||
220,
|
||||
scrollable: find.byType(Scrollable).first,
|
||||
);
|
||||
await tester.tap(create);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(CampaignCreateScreen), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('스크롤하면 상태 표시줄 자리를 가린다(머리글 겹침 방지)', (tester) async {
|
||||
await _pump(tester, const _NoCampaignRepo());
|
||||
final scrim = find.byKey(const ValueKey('home-status-scrim'));
|
||||
// 맨 위에서는 히어로 배경이 상태 표시줄 뒤까지 보여야 한다.
|
||||
expect(scrim, findsNothing);
|
||||
await tester.drag(find.byType(Scrollable).first, const Offset(0, -400));
|
||||
await tester.pumpAndSettle();
|
||||
expect(scrim, findsOneWidget);
|
||||
expect(tester.getSize(scrim).height, 47);
|
||||
await tester.drag(find.byType(Scrollable).first, const Offset(0, 2000));
|
||||
await tester.pumpAndSettle();
|
||||
expect(scrim, findsNothing);
|
||||
});
|
||||
|
||||
group('FirestoreHomeRepository', () {
|
||||
late FakeFirebaseFirestore db;
|
||||
setUp(() async {
|
||||
db = FakeFirebaseFirestore();
|
||||
await db.doc('users/$_uid').set({'fandomId': 'fanuzu-demo'});
|
||||
});
|
||||
|
||||
Future<void> brief(String id, String section, String status) =>
|
||||
db.doc('briefings/$id').set({
|
||||
'fandomId': 'fanuzu-demo',
|
||||
'dayKey': kstDayKey(),
|
||||
'status': status,
|
||||
'section': section,
|
||||
'rank': 1,
|
||||
'headline': id,
|
||||
'sourceName': '출처',
|
||||
'sourceUrl': 'https://example.com/s',
|
||||
'articleUrl': 'https://example.com/a',
|
||||
'aiSummary': '요약',
|
||||
'sourceAt': DateTime(2026, 10, 4),
|
||||
});
|
||||
|
||||
test('브리핑 section 은 서버 값(News·SNS)만 그린다 — 시연 시드 소문자 결함', () async {
|
||||
await brief('news', 'News', 'published');
|
||||
await brief('sns', 'SNS', 'published');
|
||||
await brief('draft', 'News', 'draft');
|
||||
// 수정 전 시드(`tools/demo/fs.mjs`)가 쓰던 값 — 앱은 모르는 구획이라 버린다.
|
||||
await brief('lower', 'news', 'published');
|
||||
final home = await FirestoreHomeRepository(_Backend(db)).load();
|
||||
expect(
|
||||
home.briefings.map((b) => b.headline),
|
||||
unorderedEquals(['news', 'sns']),
|
||||
);
|
||||
});
|
||||
|
||||
test('인기 K-INSIDE 는 미해결 먼저, 그 안에서 현상금 큰 순(명세 §2.114-7)', () async {
|
||||
final at = DateTime(2026, 10, 4);
|
||||
final rows = {
|
||||
'new-0-answers': ('open', 100, at.add(const Duration(hours: 1))),
|
||||
'solved-big': ('accepted', 900, at),
|
||||
'open-500': ('open', 500, at),
|
||||
'open-300': ('open', 300, at),
|
||||
'open-200': ('open', 200, at),
|
||||
};
|
||||
for (final MapEntry(key: id, value: (status, bounty, createdAt))
|
||||
in rows.entries) {
|
||||
await db.doc('questions/$id').set({
|
||||
'title': id,
|
||||
'status': status,
|
||||
'bountyPop': bounty,
|
||||
'createdAt': createdAt,
|
||||
});
|
||||
}
|
||||
final home = await FirestoreHomeRepository(_Backend(db)).load();
|
||||
expect(home.insides.map((i) => i.title), [
|
||||
'open-500',
|
||||
'open-300',
|
||||
'open-200',
|
||||
]);
|
||||
});
|
||||
|
||||
test('미해결이 3건보다 적으면 해결된 고액 질문으로 채운다', () {
|
||||
expect(
|
||||
popularInsides([
|
||||
{'title': 'a', 'status': 'accepted'},
|
||||
{'title': 'b', 'status': 'open'},
|
||||
{'title': 'c', 'status': 'expired'},
|
||||
]).map((q) => q['title']),
|
||||
['b', 'a', 'c'],
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user