From 703e12f524f7fe8e59fbdec0e24a5a138f2a6bba Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 24 Jan 2024 17:49:08 -0800 Subject: [PATCH] [ci] Adds test for web hot restart with const App. (#141824) This PR adds a test that reproduces the problem described in the linked issue: hot restart on the web seems to not update if the app being run is `const`. The new test is expected to fail, until the `const` issue with hot restart in the web is resolved. Expected failure mode is a 15s timeout in the following test: ``` 02:31 +3 ~1 -1: Hot reload (index.html: Default) (with `const MyApp()`)): newly added code executes during hot restart [E] TimeoutException after 0:00:15.000000: Future not completed dart:async _startMicrotaskLoop ... ``` (And then a bunch of output that I'm not 100% sure is intended :)) ## Issues * #141588 --- .../test_data/hot_reload_project.dart | 32 +++++++++++-------- .../test/web.shard/hot_reload_web_test.dart | 1 + 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart index 643832696e1..b9d4f33a8e2 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart @@ -6,7 +6,9 @@ import '../test_utils.dart'; import 'project.dart'; class HotReloadProject extends Project { - HotReloadProject({super.indexHtml}); + HotReloadProject({super.indexHtml, this.constApp = false}); + + final bool constApp; @override final String pubspec = ''' @@ -20,7 +22,7 @@ class HotReloadProject extends Project { '''; @override - final String main = r''' + String get main => ''' import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; @@ -31,20 +33,14 @@ class HotReloadProject extends Project { WidgetsFlutterBinding.ensureInitialized(); final ByteData message = const StringCodec().encodeMessage('AppLifecycleState.resumed')!; await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) { }); - // See https://github.com/flutter/flutter/issues/86202 - if (kIsWeb) { - while (true) { - runApp(MyApp()); - await Future.delayed(const Duration(seconds: 1)); - } - } else { - runApp(MyApp()); - } + runApp(${constApp ? 'const ': ''}MyApp()); } int count = 1; class MyApp extends StatelessWidget { + ${constApp ? 'const MyApp({super.key});': ''} + @override Widget build(BuildContext context) { // This method gets called each time we hot reload, during reassemble. @@ -53,7 +49,7 @@ class HotReloadProject extends Project { // hot reloading worked: // printHotReloadWorked(); - print('((((TICK $count))))'); + print('((((TICK \$count))))'); // tick 1 = startup warmup frame // tick 2 = hot reload warmup reassemble frame // after that there's a post-hot-reload frame scheduled by the tool that @@ -77,10 +73,20 @@ class HotReloadProject extends Project { } } - void printHotReloadWorked() { + Future printHotReloadWorked() async { // The call to this function is uncommented by a test to verify that hot // reloading worked. print('(((((RELOAD WORKED)))))'); + + // We need to insist here for `const` Apps, so print statements don't + // get lost between the browser and the test driver. + // See: https://github.com/flutter/flutter/issues/86202 + if (kIsWeb) { + while (true) { + await Future.delayed(const Duration(seconds: 1)); + print('(((((RELOAD WORKED)))))'); + } + } } '''; diff --git a/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart b/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart index 22d917bb388..e01e0b9e1ec 100644 --- a/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart +++ b/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart @@ -15,6 +15,7 @@ import 'test_data/hot_reload_index_html_samples.dart'; void main() async { await _testProject(HotReloadProject()); // default + await _testProject(HotReloadProject(constApp: true), name: 'Default) (with `const MyApp()`)'); // runApp(const MyApp()); await _testProject(HotReloadProject(indexHtml: indexHtmlFlutterJsCallback), name: 'flutter.js (callback)'); await _testProject(HotReloadProject(indexHtml: indexHtmlFlutterJsPromisesFull), name: 'flutter.js (promises)'); await _testProject(HotReloadProject(indexHtml: indexHtmlFlutterJsPromisesShort), name: 'flutter.js (promises, short)');