import 'dart:io'; import 'package:drift/drift.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import '1_dashboard.dart'; import '2_workout.dart'; import '3_gym_mode.dart'; import '4_measurements.dart'; import '5_nutritional_plan.dart'; import '6_weight.dart'; /// Type of device /// /// For Apple: https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications /// For Android: https://support.google.com/googleplay/android-developer/answer/9866151#zippy=%2Cscreenshots enum DeviceType { androidPhone('phoneScreenshots'), androidTabletSmall('sevenInchScreenshots'), androidTabletBig('tenInchScreenshots'), androidTv('tvScreenshots'), androidWear('wearScreenshots'), iOSPhoneBig('iPhone 6.9', isAndroid: false), iOSPhoneSmall('iPhone 6.7', isAndroid: false); final String folderName; final bool isAndroid; const DeviceType(this.folderName, {this.isAndroid = true}); String fastlanePath(String language, String name) { final os = isAndroid ? 'android' : 'ios'; return 'fastlane/metadata/$os/$language/images/$folderName/$name.png'; } } const _deviceArg = String.fromEnvironment('DEVICE_TYPE', defaultValue: 'androidPhone'); // Determine the destination device type based on the provided argument final DeviceType destination = DeviceType.values.firstWhere( (d) => d.toString().split('.').last == _deviceArg || ((d.name ?? '') == _deviceArg), orElse: () { print('***** Unknown DEVICE_TYPE="$_deviceArg", defaulting to androidPhone *****'); return DeviceType.androidPhone; }, ); Future takeScreenshot( WidgetTester tester, IntegrationTestWidgetsFlutterBinding binding, String language, String name, ) async { if (Platform.isAndroid) { await tester.pumpAndSettle(); await binding.convertFlutterSurfaceToImage(); await tester.pumpAndSettle(); } final filename = destination.fastlanePath(language, name); await binding.takeScreenshot(filename); } // Available languages in weblate for the fastlane/metadata/android folder (not necessarily // those for which the application is translated) const languages = [ // Note: it seems if too many languages are processed at once, sometimes the process // disappear and no images are written. Doing this in smaller steps works fine 'ar', 'ca', 'cs-CZ', 'de-DE', 'el-GR', 'en-US', 'es-ES', 'fa-IR', 'fr-FR', 'hi-IN', 'hr', 'it-IT', 'iw-IL', 'ko-KR', 'nb-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sr', 'ta-IN', 'tr-TR', 'uk', 'zh-CN', 'zh-TW', ]; void main() { final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive; group('Generate screenshots', () { setUpAll(() async { // Suppress warnings about multiple database instances, it's ok during testing driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; }); for (final language in languages) { final split = language.split('-'); final languageCode = split.first; final countryCode = split.length > 1 ? split.last : null; final locale = Locale(languageCode, countryCode); testWidgets('dashboard screen - $language', (WidgetTester tester) async { await tester.pumpWidget(createDashboardScreen(locale: locale)); await tester.pumpAndSettle(); await takeScreenshot(tester, binding, language, '01 - dashboard'); }); testWidgets('workout detail screen - $language', (WidgetTester tester) async { await tester.pumpWidget(createWorkoutDetailScreen(locale: locale)); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); await takeScreenshot(tester, binding, language, '02 - workout detail'); }); // testWidgets('gym mode screen - $language', (WidgetTester tester) async { // await tester.pumpWidget(createGymModeScreen(locale: locale)); // await tester.tap(find.byType(TextButton)); // await tester.pumpAndSettle(); // await tester.tap(find.byKey(const ValueKey('gym-mode-options-tile'))); // await tester.pumpAndSettle(); // await tester.tap(find.byKey(const ValueKey('gym-mode-option-show-exercises'))); // await tester.pumpAndSettle(); // await takeScreenshot(tester, binding, language, '03 - gym mode'); // }); testWidgets('gym mode stats screen - $language', (WidgetTester tester) async { await tester.pumpWidget(createGymModeResultsScreen(locale: languageCode)); await tester.pumpAndSettle(); await takeScreenshot(tester, binding, language, '03 - gym mode'); }); testWidgets('measurement screen - $language', (WidgetTester tester) async { await tester.pumpWidget(createMeasurementScreen(locale: locale)); await tester.pumpAndSettle(); await takeScreenshot(tester, binding, language, '04 - measurements'); }); testWidgets('nutritional plan detail - $language', (WidgetTester tester) async { await tester.pumpWidget(createNutritionalPlanScreen(locale: locale)); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); await takeScreenshot(tester, binding, language, '05 - nutritional plan'); }); testWidgets('body weight screen - $language', (WidgetTester tester) async { await tester.pumpWidget(createWeightScreen(locale: locale)); await tester.pumpAndSettle(); await takeScreenshot(tester, binding, language, '06 - weight'); }); } }); }