diff --git a/pkg/dds/test/devtools_server/server_connection_common.dart b/pkg/dds/test/devtools_server/server_connection_common.dart index a7a7da27f47..a153334fee7 100644 --- a/pkg/dds/test/devtools_server/server_connection_common.dart +++ b/pkg/dds/test/devtools_server/server_connection_common.dart @@ -3,8 +3,10 @@ // found in the LICENSE file. import 'dart:convert'; +import 'dart:io'; -import 'package:devtools_shared/devtools_test_utils.dart'; +import 'package:browser_launcher/browser_launcher.dart'; +import 'package:devtools_shared/devtools_test_utils.dart' hide Chrome; import 'package:test/test.dart'; import 'utils/server_driver.dart'; @@ -84,36 +86,60 @@ void runTest({required bool useVmService}) { // Spawn our own Chrome process so we can terminate it. final devToolsUri = 'http://${event['params']['host']}:${event['params']['port']}'; - final chrome = await Chrome.locate()!.start(url: devToolsUri); + + // Create a temporary directory for an isolated user profile. + final tempDir = Directory.systemTemp.createTempSync('devtools_chrome_profile'); + + final chromeProcess = await Chrome.start([devToolsUri], args: [ + '--user-data-dir=${tempDir.path}', // Ensures process isolation + '--no-first-run', // Prevents welcome dialogs + '--no-default-browser-check', // Prevents default browser prompts + if (useChromeHeadless && headlessModeIsSupported) ...[ + '--headless', + '--disable-gpu', + '--no-sandbox', + ], + if (Platform.isMacOS) '--use-mock-keychain', + ]); + final stdoutSub = - chrome.process.stdout.transform(utf8.decoder).listen((e) { + chromeProcess.stdout.transform(utf8.decoder).listen((e) { print('[CHROME STDOUT]: $e'); }); final stderrSub = - chrome.process.stderr.transform(utf8.decoder).listen((e) { + chromeProcess.stderr.transform(utf8.decoder).listen((e) { print('[CHROME STDERR]: $e'); }); - // Wait for DevTools to inform server that it's connected. - print('Waiting for clients...'); - await testController.waitForClients(); + try { + // Wait for DevTools to inform server that it's connected. + print('Waiting for clients...'); + await testController.waitForClients(); - // Close the browser, which will disconnect DevTools SSE connection - // back to the server. - print('Killing Chrome...'); - chrome.kill(); - await chrome.onExit; - await Future.wait([stdoutSub.cancel(), stderrSub.cancel()]); + // Close the browser, which will disconnect DevTools SSE connection + // back to the server. + print('Killing Chrome...'); + chromeProcess.kill(); + await chromeProcess.exitCode; + await Future.wait([stdoutSub.cancel(), stderrSub.cancel()]); - // Await a long delay to wait for the SSE client to close. - print('Delaying to wait for SSE connection to cleanup...'); - await delay(duration: const Duration(seconds: 15)); + // Await a long delay to wait for the SSE client to close. + print('Delaying to wait for SSE connection to cleanup...'); + await delay(duration: const Duration(seconds: 15)); - // Ensure the client is completely removed from the list. - print('Expecting no clients...'); - await testController.waitForClients(expectNone: true); + // Ensure the client is completely removed from the list. + print('Expecting no clients...'); + await testController.waitForClients(expectNone: true); - print('Done!'); + print('Done!'); + } finally { + // Clean up the temporary profile directory. + try { + await tempDir.delete(recursive: true); + } catch (_) { + // Ignore cleanup errors since the OS temp dir is eventually cleaned up. + } + } }, timeout: const Timeout.factor(20)); }); }