
* Update project.pbxproj files to say Flutter rather than Chromium Also, the templates now have an empty organization so that we don't cause people to give their apps a Flutter copyright. * Update the copyright notice checker to require a standard notice on all files * Update copyrights on Dart files. (This was a mechanical commit.) * Fix weird license headers on Dart files that deviate from our conventions; relicense Shrine. Some were already marked "The Flutter Authors", not clear why. Their dates have been normalized. Some were missing the blank line after the license. Some were randomly different in trivial ways for no apparent reason (e.g. missing the trailing period). * Clean up the copyrights in non-Dart files. (Manual edits.) Also, make sure templates don't have copyrights. * Fix some more ORGANIZATIONNAMEs
1086 lines
44 KiB
Dart
1086 lines
44 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
import 'dart:convert';
|
|
|
|
import 'package:build_daemon/client.dart';
|
|
import 'package:dwds/dwds.dart';
|
|
import 'package:flutter_tools/src/base/common.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/build_info.dart';
|
|
import 'package:flutter_tools/src/build_runner/resident_web_runner.dart';
|
|
import 'package:flutter_tools/src/build_runner/web_fs.dart';
|
|
import 'package:flutter_tools/src/compile.dart';
|
|
import 'package:flutter_tools/src/devfs.dart';
|
|
import 'package:flutter_tools/src/device.dart';
|
|
import 'package:flutter_tools/src/features.dart';
|
|
import 'package:flutter_tools/src/globals.dart';
|
|
import 'package:flutter_tools/src/project.dart';
|
|
import 'package:flutter_tools/src/reporting/reporting.dart';
|
|
import 'package:flutter_tools/src/resident_runner.dart';
|
|
import 'package:flutter_tools/src/web/chrome.dart';
|
|
import 'package:flutter_tools/src/web/web_device.dart';
|
|
import 'package:meta/meta.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:vm_service/vm_service.dart';
|
|
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
|
|
|
|
import '../src/common.dart';
|
|
import '../src/context.dart';
|
|
import '../src/testbed.dart';
|
|
|
|
void main() {
|
|
Testbed testbed;
|
|
MockFlutterWebFs mockWebFs;
|
|
ResidentWebRunner residentWebRunner;
|
|
MockDebugConnection mockDebugConnection;
|
|
MockVmService mockVmService;
|
|
MockChromeDevice mockChromeDevice;
|
|
MockAppConnection mockAppConnection;
|
|
MockFlutterDevice mockFlutterDevice;
|
|
MockWebDevFS mockWebDevFS;
|
|
MockResidentCompiler mockResidentCompiler;
|
|
MockChrome mockChrome;
|
|
MockChromeConnection mockChromeConnection;
|
|
MockChromeTab mockChromeTab;
|
|
MockWipConnection mockWipConnection;
|
|
MockWipDebugger mockWipDebugger;
|
|
MockWebServerDevice mockWebServerDevice;
|
|
bool didSkipDwds;
|
|
|
|
setUp(() {
|
|
resetChromeForTesting();
|
|
mockWebFs = MockFlutterWebFs();
|
|
mockDebugConnection = MockDebugConnection();
|
|
mockVmService = MockVmService();
|
|
mockChromeDevice = MockChromeDevice();
|
|
mockAppConnection = MockAppConnection();
|
|
mockFlutterDevice = MockFlutterDevice();
|
|
mockWebDevFS = MockWebDevFS();
|
|
mockResidentCompiler = MockResidentCompiler();
|
|
mockChrome = MockChrome();
|
|
mockChromeConnection = MockChromeConnection();
|
|
mockChromeTab = MockChromeTab();
|
|
mockWipConnection = MockWipConnection();
|
|
mockWipDebugger = MockWipDebugger();
|
|
mockWebServerDevice = MockWebServerDevice();
|
|
when(mockFlutterDevice.device).thenReturn(mockChromeDevice);
|
|
testbed = Testbed(
|
|
setup: () {
|
|
residentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
|
|
ipv6: true,
|
|
stayResident: true,
|
|
dartDefines: const <String>[],
|
|
) as ResidentWebRunner;
|
|
},
|
|
overrides: <Type, Generator>{
|
|
WebFsFactory: () => ({
|
|
@required String target,
|
|
@required FlutterProject flutterProject,
|
|
@required BuildInfo buildInfo,
|
|
@required bool skipDwds,
|
|
@required bool initializePlatform,
|
|
@required String hostname,
|
|
@required String port,
|
|
@required List<String> dartDefines,
|
|
}) async {
|
|
didSkipDwds = skipDwds;
|
|
return mockWebFs;
|
|
},
|
|
},
|
|
);
|
|
});
|
|
|
|
void _setupMocks() {
|
|
fs.file('pubspec.yaml').createSync();
|
|
fs.file(fs.path.join('lib', 'main.dart')).createSync(recursive: true);
|
|
fs.file(fs.path.join('web', 'index.html')).createSync(recursive: true);
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
when(mockWebFs.recompile()).thenAnswer((Invocation _) {
|
|
return Future<bool>.value(false);
|
|
});
|
|
when(mockWebFs.uri).thenReturn('http://localhost:8765/app/');
|
|
when(mockDebugConnection.vmService).thenReturn(mockVmService);
|
|
when(mockDebugConnection.onDone).thenAnswer((Invocation invocation) {
|
|
return Completer<void>().future;
|
|
});
|
|
when(mockVmService.onStdoutEvent).thenAnswer((Invocation _) {
|
|
return const Stream<Event>.empty();
|
|
});
|
|
when(mockVmService.onDebugEvent).thenAnswer((Invocation _) {
|
|
return const Stream<Event>.empty();
|
|
});
|
|
when(mockDebugConnection.uri).thenReturn('ws://127.0.0.1/abcd/');
|
|
when(mockFlutterDevice.devFS).thenReturn(mockWebDevFS);
|
|
when(mockWebDevFS.sources).thenReturn(<Uri>[]);
|
|
when(mockFlutterDevice.generator).thenReturn(mockResidentCompiler);
|
|
when(mockChrome.chromeConnection).thenReturn(mockChromeConnection);
|
|
when(mockChromeConnection.getTab(any)).thenAnswer((Invocation invocation) async {
|
|
return mockChromeTab;
|
|
});
|
|
when(mockChromeTab.connect()).thenAnswer((Invocation invocation) async {
|
|
return mockWipConnection;
|
|
});
|
|
when(mockWipConnection.debugger).thenReturn(mockWipDebugger);
|
|
}
|
|
|
|
test('runner with web server device does not support debugging without --start-paused', () => testbed.run(() {
|
|
when(mockFlutterDevice.device).thenReturn(WebServerDevice());
|
|
final ResidentRunner profileResidentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
|
|
ipv6: true,
|
|
stayResident: true,
|
|
dartDefines: const <String>[],
|
|
) as ResidentWebRunner;
|
|
|
|
expect(profileResidentWebRunner.debuggingEnabled, false);
|
|
|
|
when(mockFlutterDevice.device).thenReturn(MockChromeDevice());
|
|
expect(residentWebRunner.debuggingEnabled, true);
|
|
}));
|
|
|
|
test('runner with web server device does not initialize dwds', () => testbed.run(() async {
|
|
_setupMocks();
|
|
when(mockFlutterDevice.device).thenReturn(WebServerDevice());
|
|
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
|
|
expect(didSkipDwds, true);
|
|
}));
|
|
|
|
test('runner with web server device supports debugging with --start-paused', () => testbed.run(() {
|
|
when(mockFlutterDevice.device).thenReturn(WebServerDevice());
|
|
final ResidentRunner profileResidentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, startPaused: true),
|
|
ipv6: true,
|
|
stayResident: true,
|
|
dartDefines: <String>[],
|
|
);
|
|
|
|
expect(profileResidentWebRunner.debuggingEnabled, true);
|
|
}));
|
|
|
|
test('runner with web server device uses debug extension with --start-paused', () => testbed.run(() async {
|
|
_setupMocks();
|
|
when(mockFlutterDevice.device).thenReturn(WebServerDevice());
|
|
final ResidentWebRunner runner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, startPaused: true),
|
|
ipv6: true,
|
|
stayResident: true,
|
|
dartDefines: <String>[],
|
|
) as ResidentWebRunner;
|
|
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(runner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
|
|
// Check connect() was told to use the debug extension.
|
|
verify(mockWebFs.connect(true)).called(1);
|
|
// And ensure the debug services was started.
|
|
expect(testLogger.statusText, contains('Debug service listening on'));
|
|
}));
|
|
|
|
test('profile does not supportsServiceProtocol', () => testbed.run(() {
|
|
when(mockFlutterDevice.device).thenReturn(mockChromeDevice);
|
|
final ResidentRunner profileResidentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile),
|
|
ipv6: true,
|
|
stayResident: true,
|
|
dartDefines: const <String>[],
|
|
);
|
|
|
|
expect(profileResidentWebRunner.supportsServiceProtocol, false);
|
|
expect(residentWebRunner.supportsServiceProtocol, true);
|
|
}));
|
|
|
|
test('Exits on run if application does not support the web', () => testbed.run(() async {
|
|
fs.file('pubspec.yaml').createSync();
|
|
|
|
expect(await residentWebRunner.run(), 1);
|
|
expect(testLogger.errorText, contains('This application is not configured to build on the web'));
|
|
}));
|
|
|
|
test('Exits on run if target file does not exist', () => testbed.run(() async {
|
|
fs.file('pubspec.yaml').createSync();
|
|
fs.file(fs.path.join('web', 'index.html')).createSync(recursive: true);
|
|
|
|
expect(await residentWebRunner.run(), 1);
|
|
final String absoluteMain = fs.path.absolute(fs.path.join('lib', 'main.dart'));
|
|
expect(testLogger.errorText, contains('Tried to run $absoluteMain, but that file does not exist.'));
|
|
}));
|
|
|
|
test('Can successfully run and connect to vmservice', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final DelegateLogger delegateLogger = logger as DelegateLogger;
|
|
final BufferLogger bufferLogger = delegateLogger.delegate as BufferLogger;
|
|
final MockStatus status = MockStatus();
|
|
delegateLogger.status = status;
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
final DebugConnectionInfo debugConnectionInfo = await connectionInfoCompleter.future;
|
|
|
|
verify(mockAppConnection.runMain()).called(1);
|
|
verify(mockVmService.registerService('reloadSources', 'FlutterTools')).called(1);
|
|
verify(status.stop()).called(2);
|
|
|
|
expect(bufferLogger.statusText, contains('Debug service listening on ws://127.0.0.1/abcd/'));
|
|
expect(debugConnectionInfo.wsUri.toString(), 'ws://127.0.0.1/abcd/');
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => DelegateLogger(BufferLogger()),
|
|
}));
|
|
|
|
test('Can successfully run and disconnect with --no-resident', () => testbed.run(() async {
|
|
_setupMocks();
|
|
residentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
|
|
ipv6: true,
|
|
stayResident: false,
|
|
dartDefines: const <String>[],
|
|
) as ResidentWebRunner;
|
|
|
|
expect(await residentWebRunner.run(), 0);
|
|
}));
|
|
|
|
test('Listens to stdout streams before running main', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final StreamController<Event> controller = StreamController<Event>.broadcast();
|
|
when(mockVmService.onStdoutEvent).thenAnswer((Invocation _) {
|
|
return controller.stream;
|
|
});
|
|
when(mockAppConnection.runMain()).thenAnswer((Invocation invocation) {
|
|
controller.add(Event.parse(<String, Object>{
|
|
'type': 'Event',
|
|
'kind': 'WriteEvent',
|
|
'timestamp': 1569473488296,
|
|
'bytes': base64.encode('THIS MESSAGE IS IMPORTANT'.codeUnits),
|
|
}));
|
|
});
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
|
|
expect(testLogger.statusText, contains('THIS MESSAGE IS IMPORTANT'));
|
|
}));
|
|
|
|
test('Does not run main with --start-paused', () => testbed.run(() async {
|
|
residentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, startPaused: true),
|
|
ipv6: true,
|
|
stayResident: true,
|
|
dartDefines: const <String>[],
|
|
) as ResidentWebRunner;
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final StreamController<Event> controller = StreamController<Event>.broadcast();
|
|
when(mockVmService.onStdoutEvent).thenAnswer((Invocation _) {
|
|
return controller.stream;
|
|
});
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
|
|
verifyNever(mockAppConnection.runMain());
|
|
}));
|
|
|
|
test('Can hot reload after attaching', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockWebFs.recompile()).thenAnswer((Invocation invocation) async {
|
|
return true;
|
|
});
|
|
when(mockVmService.callServiceExtension('hotRestart')).thenAnswer((Invocation _) async {
|
|
return Response.parse(<String, Object>{'type': 'Success'});
|
|
});
|
|
final OperationResult result = await residentWebRunner.restart(fullRestart: false);
|
|
|
|
expect(testLogger.statusText, contains('Reloaded application in'));
|
|
expect(result.code, 0);
|
|
// ensure that analytics are sent.
|
|
verify(Usage.instance.sendEvent('hot', 'restart', parameters: <String, String>{
|
|
'cd27': 'web-javascript',
|
|
'cd28': null,
|
|
'cd29': 'false',
|
|
'cd30': 'true',
|
|
})).called(1);
|
|
verify(Usage.instance.sendTiming('hot', 'web-restart', any)).called(1);
|
|
verify(Usage.instance.sendTiming('hot', 'web-refresh', any)).called(1);
|
|
verify(Usage.instance.sendTiming('hot', 'web-recompile', any)).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Usage: () => MockFlutterUsage(),
|
|
}));
|
|
|
|
test('Can hot reload after attaching - experimental', () => testbed.run(() async {
|
|
_setupMocks();
|
|
launchChromeInstance(mockChrome);
|
|
when(mockWebDevFS.update(
|
|
mainPath: anyNamed('mainPath'),
|
|
target: anyNamed('target'),
|
|
bundle: anyNamed('bundle'),
|
|
firstBuildTime: anyNamed('firstBuildTime'),
|
|
bundleFirstUpload: anyNamed('bundleFirstUpload'),
|
|
generator: anyNamed('generator'),
|
|
fullRestart: anyNamed('fullRestart'),
|
|
dillOutputPath: anyNamed('dillOutputPath'),
|
|
trackWidgetCreation: anyNamed('trackWidgetCreation'),
|
|
projectRootPath: anyNamed('projectRootPath'),
|
|
pathToReload: anyNamed('pathToReload'),
|
|
invalidatedFiles: anyNamed('invalidatedFiles'),
|
|
)).thenAnswer((Invocation invocation) async {
|
|
return UpdateFSReport(success: true)
|
|
..invalidatedModules = <String>['example'];
|
|
});
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
final OperationResult result = await residentWebRunner.restart(fullRestart: false);
|
|
|
|
expect(testLogger.statusText, contains('Reloaded application in'));
|
|
expect(result.code, 0);
|
|
verify(mockResidentCompiler.accept()).called(2);
|
|
// ensure that analytics are sent.
|
|
verify(Usage.instance.sendEvent('hot', 'restart', parameters: <String, String>{
|
|
'cd27': 'web-javascript',
|
|
'cd28': null,
|
|
'cd29': 'false',
|
|
'cd30': 'true',
|
|
})).called(1);
|
|
verify(Usage.instance.sendTiming('hot', 'web-incremental-restart', any)).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Usage: () => MockFlutterUsage(),
|
|
FeatureFlags: () => TestFeatureFlags(isWebIncrementalCompilerEnabled: true),
|
|
}));
|
|
|
|
test('Can hot restart after attaching - experimental', () => testbed.run(() async {
|
|
_setupMocks();
|
|
launchChromeInstance(mockChrome);
|
|
when(mockWebDevFS.update(
|
|
mainPath: anyNamed('mainPath'),
|
|
target: anyNamed('target'),
|
|
bundle: anyNamed('bundle'),
|
|
firstBuildTime: anyNamed('firstBuildTime'),
|
|
bundleFirstUpload: anyNamed('bundleFirstUpload'),
|
|
generator: anyNamed('generator'),
|
|
fullRestart: anyNamed('fullRestart'),
|
|
dillOutputPath: anyNamed('dillOutputPath'),
|
|
trackWidgetCreation: anyNamed('trackWidgetCreation'),
|
|
projectRootPath: anyNamed('projectRootPath'),
|
|
pathToReload: anyNamed('pathToReload'),
|
|
invalidatedFiles: anyNamed('invalidatedFiles'),
|
|
)).thenAnswer((Invocation invocation) async {
|
|
return UpdateFSReport(success: true)
|
|
..invalidatedModules = <String>['example'];
|
|
});
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
final OperationResult result = await residentWebRunner.restart(fullRestart: true);
|
|
|
|
expect(testLogger.statusText, contains('Restarted application in'));
|
|
expect(result.code, 0);
|
|
verify(mockResidentCompiler.accept()).called(2);
|
|
// ensure that analytics are sent.
|
|
verify(Usage.instance.sendEvent('hot', 'restart', parameters: <String, String>{
|
|
'cd27': 'web-javascript',
|
|
'cd28': null,
|
|
'cd29': 'false',
|
|
'cd30': 'true',
|
|
})).called(1);
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-incremental-restart', any));
|
|
}, overrides: <Type, Generator>{
|
|
Usage: () => MockFlutterUsage(),
|
|
FeatureFlags: () => TestFeatureFlags(isWebIncrementalCompilerEnabled: true),
|
|
}));
|
|
|
|
test('Can hot restart after attaching - experimental with web-server device', () => testbed.run(() async {
|
|
_setupMocks();
|
|
when(mockFlutterDevice.device).thenReturn(mockWebServerDevice);
|
|
when(mockWebDevFS.update(
|
|
mainPath: anyNamed('mainPath'),
|
|
target: anyNamed('target'),
|
|
bundle: anyNamed('bundle'),
|
|
firstBuildTime: anyNamed('firstBuildTime'),
|
|
bundleFirstUpload: anyNamed('bundleFirstUpload'),
|
|
generator: anyNamed('generator'),
|
|
fullRestart: anyNamed('fullRestart'),
|
|
dillOutputPath: anyNamed('dillOutputPath'),
|
|
trackWidgetCreation: anyNamed('trackWidgetCreation'),
|
|
projectRootPath: anyNamed('projectRootPath'),
|
|
pathToReload: anyNamed('pathToReload'),
|
|
invalidatedFiles: anyNamed('invalidatedFiles'),
|
|
)).thenAnswer((Invocation invocation) async {
|
|
return UpdateFSReport(success: true)
|
|
..invalidatedModules = <String>['example'];
|
|
});
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
final OperationResult result = await residentWebRunner.restart(fullRestart: true);
|
|
|
|
expect(testLogger.statusText, contains('Restarted application in'));
|
|
expect(result.code, 0);
|
|
verify(mockResidentCompiler.accept()).called(2);
|
|
// ensure that analytics are sent.
|
|
verify(Usage.instance.sendEvent('hot', 'restart', parameters: <String, String>{
|
|
'cd27': 'web-javascript',
|
|
'cd28': null,
|
|
'cd29': 'false',
|
|
'cd30': 'true',
|
|
})).called(1);
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-incremental-restart', any));
|
|
}, overrides: <Type, Generator>{
|
|
Usage: () => MockFlutterUsage(),
|
|
FeatureFlags: () => TestFeatureFlags(isWebIncrementalCompilerEnabled: true),
|
|
}));
|
|
|
|
test('Can hot restart after attaching', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockWebFs.recompile()).thenAnswer((Invocation invocation) async {
|
|
return true;
|
|
});
|
|
when(mockVmService.callServiceExtension('fullReload')).thenAnswer((Invocation _) async {
|
|
return Response.parse(<String, Object>{'type': 'Success'});
|
|
});
|
|
final OperationResult result = await residentWebRunner.restart(fullRestart: true);
|
|
|
|
expect(testLogger.statusText, contains('Restarted application in'));
|
|
expect(result.code, 0);
|
|
// ensure that analytics are sent.
|
|
verify(Usage.instance.sendEvent('hot', 'restart', parameters: <String, String>{
|
|
'cd27': 'web-javascript',
|
|
'cd28': null,
|
|
'cd29': 'false',
|
|
'cd30': 'true',
|
|
})).called(1);
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-restart', any));
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-refresh', any));
|
|
verify(Usage.instance.sendTiming('hot', 'web-recompile', any)).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Usage: () => MockFlutterUsage(),
|
|
}));
|
|
|
|
test('Selects Dwds runner in profile mode with incremental compiler enabled', () => testbed.run(() async {
|
|
final ResidentWebRunner residentWebRunner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile),
|
|
ipv6: true,
|
|
stayResident: true,
|
|
dartDefines: const <String>[],
|
|
) as ResidentWebRunner;
|
|
|
|
expect(residentWebRunner.runtimeType.toString(), '_DwdsResidentWebRunner');
|
|
}, overrides: <Type, Generator>{
|
|
FeatureFlags: () => TestFeatureFlags(isWebIncrementalCompilerEnabled: true),
|
|
}));
|
|
|
|
test('Fails on compilation errors in hot restart', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockWebFs.recompile()).thenAnswer((Invocation _) async {
|
|
return false;
|
|
});
|
|
final OperationResult result = await residentWebRunner.restart(fullRestart: true);
|
|
|
|
expect(result.code, 1);
|
|
expect(result.message, contains('Failed to recompile application.'));
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-restart', any));
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-refresh', any));
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-recompile', any));
|
|
}, overrides: <Type, Generator>{
|
|
Usage: () => MockFlutterUsage(),
|
|
}));
|
|
|
|
test('Fails on vmservice response error for hot restart', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockWebFs.recompile()).thenAnswer((Invocation _) async {
|
|
return true;
|
|
});
|
|
when(mockVmService.callServiceExtension('fullReload')).thenAnswer((Invocation _) async {
|
|
return Response.parse(<String, Object>{'type': 'Failed'});
|
|
});
|
|
final OperationResult result = await residentWebRunner.restart(fullRestart: true);
|
|
|
|
expect(result.code, 1);
|
|
expect(result.message, contains('Failed'));
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-restart', any));
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-refresh', any));
|
|
verify(Usage.instance.sendTiming('hot', 'web-recompile', any)).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Usage: () => MockFlutterUsage(),
|
|
}));
|
|
|
|
test('Fails on vmservice response error for hot reload', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockWebFs.recompile()).thenAnswer((Invocation _) async {
|
|
return true;
|
|
});
|
|
when(mockVmService.callServiceExtension('hotRestart')).thenAnswer((Invocation _) async {
|
|
return Response.parse(<String, Object>{'type': 'Failed'});
|
|
});
|
|
final OperationResult result = await residentWebRunner.restart(fullRestart: false);
|
|
|
|
expect(result.code, 1);
|
|
expect(result.message, contains('Failed'));
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-restart', any));
|
|
verifyNever(Usage.instance.sendTiming('hot', 'web-refresh', any));
|
|
verify(Usage.instance.sendTiming('hot', 'web-recompile', any)).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Usage: () => MockFlutterUsage(),
|
|
}));
|
|
|
|
test('Fails on vmservice RpcError', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockWebFs.recompile()).thenAnswer((Invocation _) async {
|
|
return true;
|
|
});
|
|
when(mockVmService.callServiceExtension('hotRestart')).thenThrow(RPCError('', 2, '123'));
|
|
final OperationResult result = await residentWebRunner.restart(fullRestart: false);
|
|
|
|
expect(result.code, 1);
|
|
expect(result.message, contains('Page requires refresh'));
|
|
}));
|
|
|
|
test('printHelp without details has web warning', () => testbed.run(() async {
|
|
residentWebRunner.printHelp(details: false);
|
|
|
|
expect(testLogger.statusText, contains('Warning'));
|
|
expect(testLogger.statusText, contains('https://flutter.dev/web'));
|
|
expect(testLogger.statusText, isNot(contains('https://flutter.dev/web.')));
|
|
}));
|
|
|
|
test('debugDumpApp', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
await residentWebRunner.debugDumpApp();
|
|
|
|
verify(mockVmService.callServiceExtension('ext.flutter.debugDumpApp')).called(1);
|
|
}));
|
|
|
|
test('debugDumpLayerTree', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
await residentWebRunner.debugDumpLayerTree();
|
|
|
|
verify(mockVmService.callServiceExtension('ext.flutter.debugDumpLayerTree')).called(1);
|
|
}));
|
|
|
|
test('debugDumpRenderTree', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
await residentWebRunner.debugDumpRenderTree();
|
|
|
|
verify(mockVmService.callServiceExtension('ext.flutter.debugDumpRenderTree')).called(1);
|
|
}));
|
|
|
|
test('debugDumpSemanticsTreeInTraversalOrder', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
await residentWebRunner.debugDumpSemanticsTreeInTraversalOrder();
|
|
|
|
verify(mockVmService.callServiceExtension('ext.flutter.debugDumpSemanticsTreeInTraversalOrder')).called(1);
|
|
}));
|
|
|
|
test('debugDumpSemanticsTreeInInverseHitTestOrder', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
await residentWebRunner.debugDumpSemanticsTreeInInverseHitTestOrder();
|
|
|
|
verify(mockVmService.callServiceExtension('ext.flutter.debugDumpSemanticsTreeInInverseHitTestOrder')).called(1);
|
|
}));
|
|
|
|
test('debugToggleDebugPaintSizeEnabled', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockVmService.callServiceExtension('ext.flutter.debugPaint'))
|
|
.thenAnswer((Invocation _) async {
|
|
return Response.parse(<String, Object>{'enabled': false});
|
|
});
|
|
await residentWebRunner.debugToggleDebugPaintSizeEnabled();
|
|
|
|
verify(mockVmService.callServiceExtension('ext.flutter.debugPaint',
|
|
args: <String, Object>{'enabled': true})).called(1);
|
|
}));
|
|
|
|
|
|
test('debugTogglePerformanceOverlayOverride', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockVmService.callServiceExtension('ext.flutter.showPerformanceOverlay'))
|
|
.thenAnswer((Invocation _) async {
|
|
return Response.parse(<String, Object>{'enabled': false});
|
|
});
|
|
|
|
await residentWebRunner.debugTogglePerformanceOverlayOverride();
|
|
|
|
verify(mockVmService.callServiceExtension('ext.flutter.showPerformanceOverlay',
|
|
args: <String, Object>{'enabled': true})).called(1);
|
|
}));
|
|
|
|
test('debugToggleWidgetInspector', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockVmService.callServiceExtension('ext.flutter.debugToggleWidgetInspector'))
|
|
.thenAnswer((Invocation _) async {
|
|
return Response.parse(<String, Object>{'enabled': false});
|
|
});
|
|
|
|
await residentWebRunner.debugToggleWidgetInspector();
|
|
|
|
verify(mockVmService.callServiceExtension('ext.flutter.debugToggleWidgetInspector',
|
|
args: <String, Object>{'enabled': true})).called(1);
|
|
}));
|
|
|
|
test('debugToggleProfileWidgetBuilds', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockVmService.callServiceExtension('ext.flutter.profileWidgetBuilds'))
|
|
.thenAnswer((Invocation _) async {
|
|
return Response.parse(<String, Object>{'enabled': false});
|
|
});
|
|
|
|
await residentWebRunner.debugToggleProfileWidgetBuilds();
|
|
|
|
verify(mockVmService.callServiceExtension('ext.flutter.profileWidgetBuilds',
|
|
args: <String, Object>{'enabled': true})).called(1);
|
|
}));
|
|
|
|
test('debugTogglePlatform', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
when(mockVmService.callServiceExtension('ext.flutter.platformOverride'))
|
|
.thenAnswer((Invocation _) async {
|
|
return Response.parse(<String, Object>{'value': 'iOS'});
|
|
});
|
|
|
|
await residentWebRunner.debugTogglePlatform();
|
|
|
|
expect(testLogger.statusText, contains('Switched operating system to android'));
|
|
verify(mockVmService.callServiceExtension('ext.flutter.platformOverride',
|
|
args: <String, Object>{'value': 'android'})).called(1);
|
|
}));
|
|
|
|
test('cleanup of resources is safe to call multiple times', () => testbed.run(() async {
|
|
_setupMocks();
|
|
bool debugClosed = false;
|
|
when(mockChromeDevice.stopApp(any)).thenAnswer((Invocation invocation) async {
|
|
if (debugClosed) {
|
|
throw StateError('debug connection closed twice');
|
|
}
|
|
debugClosed = true;
|
|
return true;
|
|
});
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
|
|
await residentWebRunner.exit();
|
|
await residentWebRunner.exit();
|
|
|
|
verifyNever(mockDebugConnection.close());
|
|
}));
|
|
|
|
test('cleans up Chrome if tab is closed', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<void> onDone = Completer<void>();
|
|
when(mockDebugConnection.onDone).thenAnswer((Invocation invocation) {
|
|
return onDone.future;
|
|
});
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Future<int> result = residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
);
|
|
await connectionInfoCompleter.future;
|
|
onDone.complete();
|
|
|
|
await result;
|
|
verify(mockWebFs.stop()).called(1);
|
|
}));
|
|
|
|
test('Prints target and device name on run', () => testbed.run(() async {
|
|
_setupMocks();
|
|
when(mockChromeDevice.name).thenReturn('Chromez');
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
|
|
expect(testLogger.statusText, contains('Launching ${fs.path.join('lib', 'main.dart')} on Chromez in debug mode'));
|
|
}));
|
|
|
|
test('Sends launched app.webLaunchUrl event for Chrome device', () => testbed.run(() async {
|
|
_setupMocks();
|
|
when(mockFlutterDevice.device).thenReturn(ChromeDevice());
|
|
|
|
final DelegateLogger delegateLogger = logger as DelegateLogger;
|
|
final MockStatus mockStatus = MockStatus();
|
|
delegateLogger.status = mockStatus;
|
|
final ResidentWebRunner runner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
|
|
ipv6: true,
|
|
stayResident: true,
|
|
dartDefines: const <String>[],
|
|
) as ResidentWebRunner;
|
|
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(runner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
|
|
// Ensure we got the URL and that it was already launched.
|
|
verify(logger.sendEvent(
|
|
'app.webLaunchUrl',
|
|
argThat(allOf(
|
|
containsPair('url', 'http://localhost:8765/app/'),
|
|
containsPair('launched', true),
|
|
))
|
|
));
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => DelegateLogger(MockLogger()),
|
|
ChromeLauncher: () => MockChromeLauncher(),
|
|
}));
|
|
|
|
test('Sends unlaunched app.webLaunchUrl event for Web Server device', () => testbed.run(() async {
|
|
_setupMocks();
|
|
when(mockFlutterDevice.device).thenReturn(WebServerDevice());
|
|
|
|
final DelegateLogger delegateLogger = logger as DelegateLogger;
|
|
final MockStatus mockStatus = MockStatus();
|
|
delegateLogger.status = mockStatus;
|
|
final ResidentWebRunner runner = DwdsWebRunnerFactory().createWebRunner(
|
|
mockFlutterDevice,
|
|
flutterProject: FlutterProject.current(),
|
|
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
|
|
ipv6: true,
|
|
stayResident: true,
|
|
dartDefines: const <String>[],
|
|
) as ResidentWebRunner;
|
|
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
unawaited(runner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
));
|
|
await connectionInfoCompleter.future;
|
|
|
|
// Ensure we got the URL and that it was not already launched.
|
|
verify(logger.sendEvent(
|
|
'app.webLaunchUrl',
|
|
argThat(allOf(
|
|
containsPair('url', 'http://localhost:8765/app/'),
|
|
containsPair('launched', false),
|
|
))
|
|
));
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => DelegateLogger(MockLogger())
|
|
}));
|
|
|
|
test('Successfully turns WebSocketException into ToolExit', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Completer<void> unhandledErrorCompleter = Completer<void>();
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
unawaited(unhandledErrorCompleter.future.then((void value) {
|
|
throw const WebSocketException();
|
|
}));
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
|
|
final Future<void> expectation = expectLater(() => residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
), throwsA(isInstanceOf<ToolExit>()));
|
|
|
|
unhandledErrorCompleter.complete();
|
|
await expectation;
|
|
}));
|
|
|
|
test('Successfully turns AppConnectionException into ToolExit', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Completer<void> unhandledErrorCompleter = Completer<void>();
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
unawaited(unhandledErrorCompleter.future.then((void value) {
|
|
throw AppConnectionException('Could not connect to application with appInstanceId: c0ae0750-ee91-11e9-cea6-35d95a968356');
|
|
}));
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
|
|
final Future<void> expectation = expectLater(() => residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
), throwsA(isInstanceOf<ToolExit>()));
|
|
|
|
unhandledErrorCompleter.complete();
|
|
await expectation;
|
|
}));
|
|
|
|
test('Successfully turns ChromeDebugError into ToolExit', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Completer<void> unhandledErrorCompleter = Completer<void>();
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
unawaited(unhandledErrorCompleter.future.then((void value) {
|
|
throw ChromeDebugException(<String, dynamic>{});
|
|
}));
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
|
|
final Future<void> expectation = expectLater(() => residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
), throwsA(isInstanceOf<ToolExit>()));
|
|
|
|
unhandledErrorCompleter.complete();
|
|
await expectation;
|
|
}));
|
|
|
|
test('Successfully turns OptionsSkew error into ToolExit', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Completer<void> unhandledErrorCompleter = Completer<void>();
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
unawaited(unhandledErrorCompleter.future.then((void value) {
|
|
throw OptionsSkew();
|
|
}));
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
|
|
final Future<void> expectation = expectLater(() => residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
), throwsA(isInstanceOf<ToolExit>()));
|
|
|
|
unhandledErrorCompleter.complete();
|
|
await expectation;
|
|
}));
|
|
|
|
test('Successfully turns VersionSkew error into ToolExit', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Completer<void> unhandledErrorCompleter = Completer<void>();
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
unawaited(unhandledErrorCompleter.future.then((void value) {
|
|
throw VersionSkew();
|
|
}));
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
|
|
final Future<void> expectation = expectLater(() => residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
), throwsA(isInstanceOf<ToolExit>()));
|
|
|
|
unhandledErrorCompleter.complete();
|
|
await expectation;
|
|
}));
|
|
|
|
test('Successfully turns failed startup StateError error into ToolExit', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Completer<void> unhandledErrorCompleter = Completer<void>();
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
unawaited(unhandledErrorCompleter.future.then((void value) {
|
|
throw StateError('Unable to start build daemon');
|
|
}));
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
|
|
final Future<void> expectation = expectLater(() => residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
), throwsA(isInstanceOf<ToolExit>()));
|
|
|
|
unhandledErrorCompleter.complete();
|
|
await expectation;
|
|
}));
|
|
|
|
|
|
test('Rethrows Exception type', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Completer<void> unhandledErrorCompleter = Completer<void>();
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
unawaited(unhandledErrorCompleter.future.then((void value) {
|
|
throw Exception('Something went wrong');
|
|
}));
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
|
|
final Future<void> expectation = expectLater(() => residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
), throwsA(isInstanceOf<Exception>()));
|
|
|
|
unhandledErrorCompleter.complete();
|
|
await expectation;
|
|
}));
|
|
|
|
test('Successfully turns MissingPortFile error into ToolExit', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Completer<void> unhandledErrorCompleter = Completer<void>();
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
unawaited(unhandledErrorCompleter.future.then((void value) {
|
|
throw MissingPortFile();
|
|
}));
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
|
|
final Future<void> expectation = expectLater(() => residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
), throwsA(isInstanceOf<ToolExit>()));
|
|
|
|
unhandledErrorCompleter.complete();
|
|
await expectation;
|
|
}));
|
|
|
|
test('Rethrows unknown exception type from web tooling', () => testbed.run(() async {
|
|
_setupMocks();
|
|
final DelegateLogger delegateLogger = logger as DelegateLogger;
|
|
final MockStatus mockStatus = MockStatus();
|
|
delegateLogger.status = mockStatus;
|
|
final Completer<DebugConnectionInfo> connectionInfoCompleter = Completer<DebugConnectionInfo>();
|
|
final Completer<void> unhandledErrorCompleter = Completer<void>();
|
|
when(mockWebFs.connect(any)).thenAnswer((Invocation _) async {
|
|
unawaited(unhandledErrorCompleter.future.then((void value) {
|
|
throw StateError('Something went wrong');
|
|
}));
|
|
return ConnectionResult(mockAppConnection, mockDebugConnection);
|
|
});
|
|
|
|
final Future<void> expectation = expectLater(() => residentWebRunner.run(
|
|
connectionInfoCompleter: connectionInfoCompleter,
|
|
), throwsA(isInstanceOf<StateError>()));
|
|
|
|
unhandledErrorCompleter.complete();
|
|
await expectation;
|
|
verify(mockStatus.stop()).called(2);
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => DelegateLogger(BufferLogger())
|
|
}));
|
|
}
|
|
|
|
class MockChromeLauncher extends Mock implements ChromeLauncher {}
|
|
class MockFlutterUsage extends Mock implements Usage {}
|
|
class MockChromeDevice extends Mock implements ChromeDevice {}
|
|
class MockBuildDaemonCreator extends Mock implements BuildDaemonCreator {}
|
|
class MockFlutterWebFs extends Mock implements WebFs {}
|
|
class MockDebugConnection extends Mock implements DebugConnection {}
|
|
class MockAppConnection extends Mock implements AppConnection {}
|
|
class MockVmService extends Mock implements VmService {}
|
|
class MockStatus extends Mock implements Status {}
|
|
class MockFlutterDevice extends Mock implements FlutterDevice {}
|
|
class MockWebDevFS extends Mock implements DevFS {}
|
|
class MockResidentCompiler extends Mock implements ResidentCompiler {}
|
|
class MockChrome extends Mock implements Chrome {}
|
|
class MockChromeConnection extends Mock implements ChromeConnection {}
|
|
class MockChromeTab extends Mock implements ChromeTab {}
|
|
class MockWipConnection extends Mock implements WipConnection {}
|
|
class MockWipDebugger extends Mock implements WipDebugger {}
|
|
class MockLogger extends Mock implements Logger {}
|
|
class MockWebServerDevice extends Mock implements WebServerDevice {}
|