diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart index 19077cd6ab2..cef1026f36b 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -383,6 +383,10 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). appFailedToStart(); _logger.printError('$error', stackTrace: stackTrace); throwToolExit(kExitMessage); + } on HttpException catch (error, stackTrace) { + appFailedToStart(); + _logger.printError('$error', stackTrace: stackTrace); + throwToolExit(kExitMessage); } on Exception { appFailedToStart(); rethrow; diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 563b0eac303..f318ec26898 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -1317,6 +1317,59 @@ flutter: ProcessManager: () => processManager, }); + testUsingContext('Turns HttpException from ChromeTab::connect into ToolExit', () async { + final BufferLogger logger = BufferLogger.test(); + final ResidentRunner residentWebRunner = setUpResidentRunner( + flutterDevice, + logger: logger, + ); + fakeVmServiceHost = FakeVmServiceHost(requests: []); + setupMocks(); + final FakeChromeConnection chromeConnection = FakeChromeConnection(); + final TestChromiumLauncher chromiumLauncher = TestChromiumLauncher(); + final FakeProcess process = FakeProcess(); + final Chromium chrome = Chromium( + 1, + chromeConnection, + chromiumLauncher: chromiumLauncher, + process: process, + logger: logger, + ); + chromiumLauncher.setInstance(chrome); + + flutterDevice.device = GoogleChromeDevice( + fileSystem: fileSystem, + chromiumLauncher: chromiumLauncher, + logger: logger, + platform: FakePlatform(), + processManager: FakeProcessManager.any(), + ); + webDevFS.baseUri = Uri.parse('http://localhost:8765/app/'); + + final FakeChromeTab chromeTab = FakeChromeTab( + 'index.html', + connectException: HttpException( + 'Connection closed before full header was received', + uri: Uri( + path: 'http://localhost:50094/devtools/page/3036A94908353E86E183B6A40F54104B', + ), + ), + ); + chromeConnection.tabs.add(chromeTab); + + await expectLater( + residentWebRunner.run, + throwsToolExit( + message: 'Failed to establish connection with the application instance in Chrome.', + ), + ); + expect(logger.errorText, contains('HttpException')); + expect(fakeVmServiceHost.hasRemainingExpectations, isFalse); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }); + testUsingContext('Successfully turns AppConnectionException into ToolExit', () async { final ResidentRunner residentWebRunner = setUpResidentRunner(flutterDevice); @@ -1596,14 +1649,21 @@ class FakeChromeConnection extends Fake implements ChromeConnection { } class FakeChromeTab extends Fake implements ChromeTab { - FakeChromeTab(this.url); + FakeChromeTab(this.url, { + Exception? connectException, + }): _connectException = connectException; @override final String url; + + final Exception? _connectException; final FakeWipConnection connection = FakeWipConnection(); @override Future connect({Function? onError}) async { + if (_connectException != null) { + throw _connectException; + } return connection; } }