66library ;
77
88import 'dart:async' ;
9- import 'dart:io' as io;
109
1110import 'package:file/file.dart' ;
12- import 'package:flutter_tools/src/web/chrome.dart' ;
13- import 'package:flutter_tools/src/web/web_device.dart' show WebServerDevice;
1411
1512import '../src/common.dart' ;
1613import 'test_data/hot_reload_project.dart' ;
14+ import 'test_data/websocket_dwds_test_common.dart' ;
1715import 'test_driver.dart' ;
1816import 'test_utils.dart' ;
1917import 'transition_test_utils.dart' ;
@@ -26,8 +24,6 @@ void testAll({List<String> additionalCommandArgs = const <String>[]}) {
2624 group ('WebSocket DWDS connection'
2725 '${additionalCommandArgs .isEmpty ? '' : ' with args: $additionalCommandArgs ' }' , () {
2826 // Test configuration constants
29- const debugUrlTimeout = Duration (seconds: 20 );
30- const appStartTimeout = Duration (seconds: 15 );
3127 const hotReloadTimeout = Duration (seconds: 10 );
3228
3329 late Directory tempDir;
@@ -48,62 +44,17 @@ void testAll({List<String> additionalCommandArgs = const <String>[]}) {
4844 testWithoutContext (
4945 'hot reload with headless Chrome WebSocket connection' ,
5046 () async {
51- debugPrint ('Starting WebSocket DWDS test with headless Chrome...' );
52-
53- // Set up listening for app output before starting
54- final stdout = StringBuffer ();
55- final sawDebugUrl = Completer <String >();
56- final StreamSubscription <String > subscription = flutter.stdout.listen ((String e) {
57- stdout.writeln (e);
58- // Extract the debug connection URL
59- if (e.contains ('Waiting for connection from Dart debug extension at http://' )) {
60- final debugUrlPattern = RegExp (
61- r'Waiting for connection from Dart debug extension at (http://[^\s]+)' ,
62- );
63- final Match ? match = debugUrlPattern.firstMatch (e);
64- if (match != null && ! sawDebugUrl.isCompleted) {
65- sawDebugUrl.complete (match.group (1 )! );
66- }
67- }
68- });
69-
70- io.Process ? chromeProcess;
71- try {
72- // Step 1: Start Flutter app with web-server device (will wait for debug connection)
73- debugPrint ('Step 1: Starting Flutter app with web-server device...' );
74- // Start the app but don't wait for it to complete - it won't complete until Chrome connects
75- final Future <void > appStartFuture = runFlutterWithWebServerDevice (
76- flutter,
77- additionalCommandArgs: [...additionalCommandArgs, '--no-web-resources-cdn' ],
78- );
47+ debugPrint ('Starting WebSocket DWDS test with headless Chrome for hot reload...' );
7948
80- // Step 2: Wait for DWDS debug URL to be available
81- debugPrint ('Step 2: Waiting for DWDS debug service URL...' );
82- final String debugUrl = await sawDebugUrl.future.timeout (
83- debugUrlTimeout,
84- onTimeout: () {
85- throw Exception ('DWDS debug URL not found - app may not have started correctly' );
86- },
87- );
88- debugPrint ('✓ DWDS debug service available at: $debugUrl ' );
89-
90- // Step 3: Launch headless Chrome to connect to DWDS
91- debugPrint ('Step 3: Launching headless Chrome to connect to DWDS...' );
92- chromeProcess = await _launchHeadlessChrome (debugUrl);
93- debugPrint ('✓ Headless Chrome launched and connecting to DWDS' );
94-
95- // Step 4: Wait for app to start (Chrome connection established)
96- debugPrint ('Step 4: Waiting for Flutter app to start after Chrome connection...' );
97- await appStartFuture.timeout (
98- appStartTimeout,
99- onTimeout: () {
100- throw Exception ('App startup did not complete after Chrome connection' );
101- },
102- );
103- debugPrint ('✓ Flutter app started successfully with WebSocket connection' );
49+ // Set up WebSocket connection
50+ final WebSocketDwdsTestSetup setup = await WebSocketDwdsTestUtils .setupWebSocketConnection (
51+ flutter,
52+ additionalCommandArgs: additionalCommandArgs,
53+ );
10454
105- // Step 5: Test hot reload functionality
106- debugPrint ('Step 5: Testing hot reload with WebSocket connection...' );
55+ try {
56+ // Test hot reload functionality
57+ debugPrint ('Step 6: Testing hot reload with WebSocket connection...' );
10758 await flutter.hotReload ().timeout (
10859 hotReloadTimeout,
10960 onTimeout: () {
@@ -114,80 +65,20 @@ void testAll({List<String> additionalCommandArgs = const <String>[]}) {
11465 // Give some time for logs to capture
11566 await Future <void >.delayed (const Duration (seconds: 2 ));
11667
117- final output = stdout.toString ();
68+ final output = setup. stdout.toString ();
11869 expect (output, contains ('Reloaded' ), reason: 'Hot reload should complete successfully' );
11970 debugPrint ('✓ Hot reload completed successfully with WebSocket connection' );
12071
12172 // Verify the correct infrastructure was used
122- expect (
123- output,
124- contains ('Waiting for connection from Dart debug extension' ),
125- reason: 'Should wait for debug connection (WebSocket infrastructure)' ,
126- );
127- expect (output, contains ('web-server' ), reason: 'Should use web-server device' );
73+ WebSocketDwdsTestUtils .verifyWebSocketInfrastructure (output);
12874
12975 debugPrint ('✓ WebSocket DWDS test completed successfully' );
13076 debugPrint ('✓ Verified: web-server device + DWDS + WebSocket connection + hot reload' );
13177 } finally {
132- await _cleanupResources ( chromeProcess, subscription);
78+ await cleanupWebSocketTestResources (setup. chromeProcess, setup. subscription);
13379 }
13480 },
13581 skip: ! platform.isMacOS, // Skip on non-macOS platforms where Chrome paths may differ
13682 );
13783 });
13884}
139-
140- /// Launches headless Chrome with the given debug URL.
141- /// Uses findChromeExecutable to locate Chrome on the current platform.
142- Future <io.Process > _launchHeadlessChrome (String debugUrl) async {
143- const chromeArgs = [
144- '--headless' ,
145- '--disable-gpu' ,
146- '--no-sandbox' ,
147- '--disable-extensions' ,
148- '--disable-dev-shm-usage' ,
149- '--remote-debugging-port=0' ,
150- ];
151-
152- final String chromePath = findChromeExecutable (platform, fileSystem);
153-
154- try {
155- return await io.Process .start (chromePath, [...chromeArgs, debugUrl]);
156- } on Exception catch (e) {
157- throw Exception (
158- 'Could not launch Chrome at $chromePath : $e . Please ensure Chrome is installed.' ,
159- );
160- }
161- }
162-
163- /// Cleans up test resources (Chrome process and stdout subscription).
164- Future <void > _cleanupResources (
165- io.Process ? chromeProcess,
166- StreamSubscription <String > subscription,
167- ) async {
168- if (chromeProcess != null ) {
169- try {
170- chromeProcess.kill ();
171- await chromeProcess.exitCode;
172- debugPrint ('Chrome process cleaned up' );
173- } on Exception catch (e) {
174- debugPrint ('Warning: Failed to clean up Chrome process: $e ' );
175- }
176- }
177- await subscription.cancel ();
178- }
179-
180- // Helper to run flutter with web-server device using WebSocket connection.
181- Future <void > runFlutterWithWebServerDevice (
182- FlutterRunTestDriver flutter, {
183- bool verbose = false ,
184- bool withDebugger = true , // Enable debugger by default for WebSocket connection
185- bool startPaused = false , // Don't start paused for this test
186- List <String > additionalCommandArgs = const < String > [],
187- }) => flutter.run (
188- verbose: verbose,
189- withDebugger: withDebugger, // Enable debugger to establish WebSocket connection
190- startPaused: startPaused, // Let the app start normally after debugger connects
191- device: WebServerDevice .kWebServerDeviceId,
192- additionalCommandArgs: additionalCommandArgs,
193- );
0 commit comments