사용자 화면 문구·표본 데이터 · 퀘스트 참여 흐름 · HOME 진입 구획 · 미니맵 · 공통 확인 창 배치 수정

This commit is contained in:
Sn-Kinos
2026-10-05 00:44:39 +09:00
parent c8d29d032b
commit 8a0297eb92
66 changed files with 1812 additions and 959 deletions
+70 -5
View File
@@ -90,6 +90,29 @@ void main() {
expect(find.textContaining('광고 추가 보상'), findsNothing);
});
testWidgets('참여 조건 판정이 실패하면 광고 모달을 띄우지 않는다 (실기기 4-3)', (tester) async {
final repo = _AdRepo(
verifyError: const BackendException('E-QST-03', '기기의 위치 기능이 꺼져 있습니다.'),
);
await pumpWide(tester, QuestDetailScreen(questId: 'q2', repository: repo));
await tester.pump();
await tester.tap(find.widgetWithText(FilledButton, '보상받기'));
await tester.pumpAndSettle();
expect(find.text('광고 보고 추가 보상 받기'), findsNothing);
expect(find.text('기기의 위치 기능이 꺼져 있습니다.'), findsOneWidget);
expect(repo.claimed, isEmpty);
});
testWidgets('판정을 통과한 뒤에야 광고 모달을 띄운다', (tester) async {
final repo = _AdRepo();
await pumpWide(tester, QuestDetailScreen(questId: 'q2', repository: repo));
await tester.pump();
await tester.tap(find.widgetWithText(FilledButton, '보상받기'));
await tester.pumpAndSettle();
expect(repo.verified, 1);
expect(find.text('광고 보고 추가 보상 받기'), findsOneWidget);
});
testWidgets('일일 한도(E-AD-02)를 알리고 기본 보상은 그대로 띄운다', (tester) async {
final repo = _AdRepo(
claimError: const BackendException('E-AD-02', '오늘 광고 보상 한도를 모두 사용했습니다.'),
@@ -101,6 +124,21 @@ void main() {
});
});
group('목록 헤더 · 실패 (2026-10-04 실기기)', () {
testWidgets('헤더 보유 POP 은 목록을 읽을 때 지갑 값으로 다시 맞춘다', (tester) async {
await pumpWide(tester, QuestListScreen(repository: _BalanceRepo(), myPop: 12290));
await tester.pumpAndSettle();
expect(find.text('12,260'), findsOneWidget);
expect(find.text('12,290'), findsNothing);
});
testWidgets('목록 조회가 실패해도 로딩이 끝난다', (tester) async {
await pumpWide(tester, QuestListScreen(repository: _FailingList()));
await tester.pumpAndSettle();
expect(find.byType(CircularProgressIndicator), findsNothing);
});
});
group('진행 상태 (F4 · 518:88441)', () {
test('명세가 정한 다섯 상태의 버튼 문구를 그대로 쓴다', () {
expect(QuestStage.mine.buttonLabel, '자세히');
@@ -233,7 +271,8 @@ void main() {
await tester.tap(find.widgetWithText(FilledButton, '보상받기'));
await tester.pumpAndSettle();
// 별첨 B B-28 — 배수형 철회. 추가분은 고정형 운영값(C-02 초기 10 기여 POP).
expect(find.text('+10 POP'), findsOneWidget);
// 원장 C-116 — 「+N 기여 POP」 표기.
expect(find.text('+10 기여 POP'), findsOneWidget);
expect(find.textContaining('배'), findsNothing);
// 별첨1 ⑥ No-Force — 보지 않아도 기본 보상을 받는다.
expect(find.text('기본 보상 받기'), findsOneWidget);
@@ -270,14 +309,18 @@ void main() {
expect(find.text('광고 추가 보상 +10 POP'), findsOneWidget);
});
testWidgets('회신 대기 유형은 참여 버튼이 잠기고 MOCK 으로 알린다', (tester) async {
testWidgets('회신 대기 유형은 참여 버튼이 잠기고 사용자 문구로만 알린다', (tester) async {
await pumpWide(tester, const QuestDetailScreen(questId: 'q6', repository: _sample));
await tester.pump();
final button = tester.widget<FilledButton>(
find.widgetWithText(FilledButton, '발주사 확인 중'),
find.widgetWithText(FilledButton, '준비 중입니다.'),
);
expect(button.onPressed, isNull);
expect(find.textContaining('Q-QC-04'), findsOneWidget);
expect(find.text('이 퀘스트는 아직 참여할 수 없습니다.'), findsOneWidget);
// 내부 질의 번호 · 「발주사」 · MOCK 은 화면에 내보내지 않는다.
expect(find.textContaining('Q-QC-'), findsNothing);
expect(find.textContaining('발주사'), findsNothing);
expect(find.textContaining('MOCK'), findsNothing);
});
testWidgets('보상을 받고 나오면 보상완료가 되고 더 못 누른다', (tester) async {
@@ -464,14 +507,36 @@ void main() {
});
}
/// 지갑이 서버 값으로 바뀐 표본 — 생성 예치 · 수수료 뒤 헤더가 다시 맞는가.
class _BalanceRepo extends SampleQuestRepository {
@override
Future<int?> popBalance() async => 12260;
}
/// 목록이 실패하는 표본 — 로딩이 끝나지 않으면 탭 전체가 무한 로딩이다.
class _FailingList extends SampleQuestRepository {
@override
Future<List<QuestCard>> load({int limit = 10}) async =>
throw const BackendException('E-PERM-01', 'denied');
}
/// 광고 경계만 바꾼 표본 — B-03 「광고 실패 시 기본 보상 지급 · 추가 보상 없음」.
class _AdRepo extends SampleQuestRepository {
_AdRepo({this.loadError, this.impression = 'imp-1', this.claimError});
_AdRepo({this.loadError, this.impression = 'imp-1', this.claimError, this.verifyError});
final BackendException? loadError;
final String? impression;
final BackendException? claimError;
final BackendException? verifyError;
final claimed = <String>[];
var verified = 0;
@override
Future<QuestReward> verify(QuestCard card) async {
verified += 1;
if (verifyError case final error?) throw error;
return super.verify(card);
}
@override
Future<RewardedAdHandle> loadRewardedAd() async {