Cloud Functions 서버 기반과 앱 서버 연동 계층 — 계정 생성 트리거 · 약관 동의 기록 · 운영자 권한 · Admin 쓰기 관문 · Firestore·Functions 클라이언트 · 오류 코드 전달

This commit is contained in:
Sn-Kinos
2026-09-01 00:20:45 +09:00
parent 2037b6d573
commit 1d462ebe31
21 changed files with 21578 additions and 12 deletions
+68
View File
@@ -0,0 +1,68 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fake_cloud_firestore/fake_cloud_firestore.dart';
import 'package:fancake/core/data/backend.dart';
import 'package:firebase_auth_mocks/firebase_auth_mocks.dart';
import 'package:flutter_test/flutter_test.dart';
/// 서버 연동 계층 — 로그인 강제와 문서 값 읽기 규칙.
///
/// 문서 값 읽기가 틀리면 화면은 조용히 0 이나 빈 칸을 그리므로 눈으로는 잡히지 않는다.
void main() {
group('로그인 강제', () {
test('로그인하지 않았으면 카탈로그 코드 E-AUTH-03 으로 끊는다', () {
final backend = Backend(
firestore: FakeFirebaseFirestore(),
auth: MockFirebaseAuth(),
);
expect(backend.uid, isNull);
expect(
() => backend.requireUid,
throwsA(isA<BackendException>().having((e) => e.code, 'code', 'E-AUTH-03')),
);
});
test('로그인했으면 UID 를 돌려준다', () {
final backend = Backend(
firestore: FakeFirebaseFirestore(),
auth: MockFirebaseAuth(signedIn: true, mockUser: MockUser(uid: 'u-test')),
);
expect(backend.requireUid, 'u-test');
});
});
group('문서 값 읽기', () {
test('없는 필드는 기본값으로 받는다', () {
final doc = <String, dynamic>{};
expect(doc.intOr('pop'), 0);
expect(doc.strOr('name', '이름 없음'), '이름 없음');
expect(doc.boolOr('active'), isFalse);
expect(doc.mapsOr('items'), isEmpty);
});
test('실수는 반올림해 정수로 받는다', () {
expect(<String, dynamic>{'pop': 12.6}.intOr('pop'), 13);
});
test('빈 문자열은 없는 값으로 본다', () {
expect(<String, dynamic>{'name': ''}.strOr('name', '팬'), '팬');
});
test('서버 시각은 DateTime 으로 옮긴다', () {
final at = DateTime(2026, 9, 1, 9);
final doc = <String, dynamic>{'createdAt': Timestamp.fromDate(at)};
expect(doc.dateOr('createdAt', DateTime(2000)), at);
expect(doc.dateOr('missing', DateTime(2000)), DateTime(2000));
});
test('목록 안의 맵만 골라 받는다', () {
final doc = <String, dynamic>{
'items': [
{'id': 1},
'x',
{'id': 2},
],
};
expect(doc.mapsOr('items').map((m) => m['id']), [1, 2]);
});
});
}