import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:timezone/data/latest.dart' as tzdata; import 'package:hepan_everyday/app/hepan_app.dart'; import 'package:hepan_everyday/services/app_update_service.dart'; import '../services/app_update_service_test.dart' show TestUpdateTransport; import 'navigation_test.dart' show uiController; Future updateTile(WidgetTester tester) async { await tester.tap(find.bySemanticsLabel('个人设置')); await tester.pumpAndSettle(); await tester.scrollUntilVisible( find.byKey(const Key('check-app-update')), 250, scrollable: find.byType(Scrollable).first, ); await tester.pumpAndSettle(); } void main() { setUpAll(tzdata.initializeTimeZones); testWidgets( 'startup checks after home and update opens the supplied browser link', (tester) async { final controller = uiController(); await controller.initialize(); final transport = TestUpdateTransport(); Uri? opened; await tester.pumpWidget( HepanApp( controller: controller, updateService: AppUpdateService( transport: transport, currentBuild: 24, ), openUpdateDownload: (uri) async { opened = uri; return true; }, ), ); expect(transport.calls, 0); expect(find.byType(AlertDialog), findsNothing); await tester.pump(const Duration(seconds: 2)); await tester.pumpAndSettle(); expect(find.text('发现新版本 0.8.0'), findsOneWidget); expect(find.text('新增更新检查\n修复导入'), findsOneWidget); await tester.tap(find.text('立即更新')); await tester.pumpAndSettle(); expect( opened.toString(), 'https://app.glowtps.cn/downloads/TPSchedule.apk', ); expect(transport.calls, 1); await tester.pumpWidget(const SizedBox()); controller.dispose(); }, ); testWidgets( 'startup failure is quiet while manual checks report failure and latest version', (tester) async { final controller = uiController(); await controller.initialize(); final transport = TestUpdateTransport() ..response = const UpdateHttpResponse(503, []); await tester.pumpWidget( HepanApp( controller: controller, updateService: AppUpdateService( transport: transport, currentBuild: 26, ), ), ); await tester.pump(const Duration(seconds: 2)); await tester.pumpAndSettle(); expect(find.byType(AlertDialog), findsNothing); expect(find.byType(SnackBar), findsNothing); await updateTile(tester); await tester.tap(find.byKey(const Key('check-app-update'))); await tester.pumpAndSettle(); expect(find.textContaining('暂时无法获取更新'), findsOneWidget); transport.response = TestUpdateTransport().response; await tester.pump(const Duration(seconds: 5)); await tester.tap(find.byKey(const Key('check-app-update'))); await tester.pumpAndSettle(); expect(find.text('当前已是最新版本'), findsOneWidget); expect(transport.calls, 3); await tester.pumpWidget(const SizedBox()); controller.dispose(); }, ); testWidgets( 'later dismisses startup prompt and manual check can show it again', (tester) async { final controller = uiController(); await controller.initialize(); var launches = 0; final transport = TestUpdateTransport(); await tester.pumpWidget( HepanApp( controller: controller, updateService: AppUpdateService( transport: transport, currentBuild: 24, ), openUpdateDownload: (_) async { launches++; return false; }, ), ); await tester.pump(const Duration(seconds: 2)); await tester.pumpAndSettle(); await tester.tap(find.text('稍后')); await tester.pumpAndSettle(); expect(launches, 0); await updateTile(tester); await tester.tap(find.byKey(const Key('check-app-update'))); await tester.pumpAndSettle(); await tester.tap(find.text('立即更新')); await tester.pumpAndSettle(); expect(find.text('未能打开浏览器'), findsOneWidget); expect(find.byType(SelectableText), findsOneWidget); expect(launches, 1); await tester.pumpWidget(const SizedBox()); controller.dispose(); }, ); testWidgets('disposing before the startup delay cancels checks', ( tester, ) async { final controller = uiController(); await controller.initialize(); final transport = TestUpdateTransport(); await tester.pumpWidget( HepanApp( controller: controller, updateService: AppUpdateService(transport: transport), ), ); await tester.pumpWidget(const SizedBox()); await tester.pump(const Duration(seconds: 3)); expect(transport.calls, 0); controller.dispose(); }); testWidgets('long release notes remain scrollable on a small phone', ( tester, ) async { tester.view.physicalSize = const Size(360, 640); tester.view.devicePixelRatio = 1; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); final controller = uiController(); await controller.initialize(); final transport = TestUpdateTransport(); final body = jsonDecode( utf8.decode(transport.response.body), ) as Map; (body['latest'] as Map)['notes'] = List.filled( 300, '更新功能说明,修复课程显示问题。', ).join('\n'); transport.response = UpdateHttpResponse(200, utf8.encode(jsonEncode(body))); await tester.pumpWidget( HepanApp( controller: controller, updateService: AppUpdateService(transport: transport, currentBuild: 24), ), ); await tester.pump(const Duration(seconds: 2)); await tester.pumpAndSettle(); expect(tester.takeException(), isNull); expect(find.text('立即更新'), findsOneWidget); await tester.tap(find.text('稍后')); await tester.pumpAndSettle(); await tester.pumpWidget(const SizedBox()); controller.dispose(); }); }