Files
fanuzu/app/integration_test/capture_common.dart
T

62 lines
2.7 KiB
Dart

// 구현 확인물 캡처 공용 도구 — 화면군마다 `capture_f*_test.dart` 가 이것을 쓴다.
//
// **앱 코드를 고치지 않는다.** 앱이 쓰는 위젯과 테마를 그대로 기기 위에 띄우고
// 화면마다 PNG 를 한 장씩 뽑는다. `adb shell input` 으로 41 화면을 눌러 다니는
// 방식은 이 에뮬레이터에서 한 번 누르는 데 최대 60초가 걸려 재현되지 않았다.
//
// 화면군을 파일로 나눈 이유 — 한 실행이 중간에 끊기면 드라이버가 그때까지 모은
// 캡처를 통째로 잃는다. 군마다 실행을 나누면 한 군이 실패해도 나머지는 남는다.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:fancake/core/theme/app_theme.dart';
/// 캡처 도구 한 벌. `main()` 첫 줄에서 만든다.
class Capture {
Capture() : binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final IntegrationTestWidgetsFlutterBinding binding;
/// Android 는 이걸 부르지 않으면 화면을 이미지로 뜨지 못한다.
Future<void> prepare() => binding.convertFlutterSurfaceToImage();
/// 정해진 시간만큼 프레임을 돌린다.
///
/// `pumpAndSettle` 은 로딩 스피너처럼 끝나지 않는 애니메이션이 하나라도 있으면
/// 던진다. 캡처는 그런 화면에서도 나와야 하고, 저장소를 읽고 다시 그리는
/// 시간도 필요하므로 고정 프레임 수로 돌린다.
Future<void> settle(WidgetTester tester, {int frames = 16}) async {
for (var i = 0; i < frames; i++) {
await tester.pump(const Duration(milliseconds: 100));
}
}
/// 화면 하나를 앱 테마 그대로 띄운다.
///
/// [tag] 로 키를 준다. **없으면 안 된다** — 같은 종류의 화면을 연달아 띄우면
/// Flutter 가 앞 화면의 State 를 그대로 재사용해 새 인자가 무시되고
/// 앞 화면이 한 번 더 찍힌다(q1 상세가 q4 상세 자리에 찍히는 식).
Future<void> open(WidgetTester tester, String tag, Widget screen) async {
await tester.pumpWidget(
MaterialApp(
debugShowCheckedModeBanner: false,
theme: buildAppTheme(),
darkTheme: buildAppTheme(),
themeMode: ThemeMode.dark,
home: KeyedSubtree(key: ValueKey(tag), child: screen),
),
);
await settle(tester);
}
Future<void> shot(String name) => binding.takeScreenshot(name);
/// 띄우고 찍기.
Future<void> capture(WidgetTester tester, String name, Widget screen) async {
await open(tester, name, screen);
await shot(name);
}
}