import 'dart:io'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:jj_mkvmaker/app/i18n_controller.dart'; import 'package:jj_mkvmaker/ui/explorer/marks_bar.dart' show PatternDialog; import 'package:jj_mkvmaker/ui/schedule_editor.dart'; import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:path/path.dart' as p; /// W JjField (관리자 10/24): 글 칸을 모을 때 캡처가 없던 곳을 찍는다 - 패턴으로 고르기 창 · 동기화 일정 창 (cron 글 칸의 도움 글). /// 412 · 960 × ko · ja. 모으기 전 판과 뒤 판을 같은 이름으로 찍어 견준다 (JJ_SHOT_DIR) void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); // 글 칸 커서가 깜빡여 캡처가 실행마다 달라지지 않게 (시험 쪽에서만) EditableText.debugDeterministicCursor = true; final out = Platform.environment['JJ_SHOT_DIR'] ?? p.join(Directory.systemTemp.path, 'jj_shots_field'); for (final (w, h) in [(412, 900), (960, 700)]) { for (final lang in ['ko', 'ja']) { testWidgets('글 칸 자리 $lang ${w}x$h', (t) async { t.view.physicalSize = Size(w.toDouble(), h.toDouble()); t.view.devicePixelRatio = 1; addTearDown(t.view.reset); await t.runAsync(() => i18n.apply(lang, save: false)); addTearDown(() => i18n.apply('ko', save: false)); final key = GlobalKey(); final nav = GlobalKey(); await t.pumpWidget(RepaintBoundary( key: key, child: MaterialApp( theme: buildTheme(), debugShowCheckedModeBanner: false, navigatorKey: nav, home: const Scaffold(body: SizedBox.expand())), )); Future settle() async { for (var i = 0; i < 6; i++) { await t.runAsync(() => Future.delayed(const Duration(milliseconds: 40))); await t.pump(const Duration(milliseconds: 100)); } } Future shot(String name) async { expect(t.takeException(), isNull, reason: '$name 넘침'); final b = key.currentContext!.findRenderObject()! as RenderRepaintBoundary; final img = await t.runAsync(() => b.toImage()); final bytes = await t.runAsync(() => img!.toByteData(format: ui.ImageByteFormat.png)); Directory(out).createSync(recursive: true); File(p.join(out, 'field_${name}_${lang}_$w.png')).writeAsBytesSync(bytes!.buffer.asUint8List()); } // 1. 패턴으로 고르기 final pattern = showDialog(context: nav.currentContext!, builder: (_) => const PatternDialog()); await settle(); await shot('pattern'); Navigator.of(nav.currentContext!).pop(); await settle(); await pattern; // 2. 동기화 일정 (시간 지정 - cron 글 칸과 도움 글이 보이게) final schedule = editSchedule(nav.currentContext!, const ['0 9-17 * * 1-5']); await settle(); final scroll = find.byType(Scrollable).last; await t.scrollUntilVisible(find.byIcon(Icons.check), 200, scrollable: scroll); await settle(); await shot('schedule'); Navigator.of(nav.currentContext!).pop(); await settle(); await schedule; }); } } }