New flag to `flutter drive` to skip installing fresh app on device (#30818)
* add a --build/--no-build flag to flutter drive command
diff --git a/packages/flutter_tools/lib/src/commands/drive.dart b/packages/flutter_tools/lib/src/commands/drive.dart
index 11df0d5..22232ab 100644
--- a/packages/flutter_tools/lib/src/commands/drive.dart
+++ b/packages/flutter_tools/lib/src/commands/drive.dart
@@ -64,6 +64,10 @@
'extension, so e.g. if the target is "lib/main.dart", the driver will be '
'"test_driver/main_test.dart".',
valueHelp: 'path',
+ )
+ ..addFlag('build',
+ defaultsTo: true,
+ help: 'Build the app before running.',
);
}
@@ -78,6 +82,7 @@
Device _device;
Device get device => _device;
+ bool get shouldBuild => argResults['build'];
/// Subscription to log messages printed on the device or simulator.
// ignore: cancel_subscriptions
@@ -234,12 +239,15 @@
printTrace('Stopping previously running application, if any.');
await appStopper(command);
- printTrace('Installing application package.');
final ApplicationPackage package = await command.applicationPackages
.getPackageForPlatform(await command.device.targetPlatform);
- if (await command.device.isAppInstalled(package))
- await command.device.uninstallApp(package);
- await command.device.installApp(package);
+
+ if (command.shouldBuild) {
+ printTrace('Installing application package.');
+ if (await command.device.isAppInstalled(package))
+ await command.device.uninstallApp(package);
+ await command.device.installApp(package);
+ }
final Map<String, dynamic> platformArgs = <String, dynamic>{};
if (command.traceStartup)
@@ -264,6 +272,7 @@
observatoryPort: command.observatoryPort,
),
platformArgs: platformArgs,
+ prebuiltApplication: !command.shouldBuild,
usesTerminalUi: false,
);
diff --git a/packages/flutter_tools/test/commands/drive_test.dart b/packages/flutter_tools/test/commands/drive_test.dart
index 81a435c..d7bf21b 100644
--- a/packages/flutter_tools/test/commands/drive_test.dart
+++ b/packages/flutter_tools/test/commands/drive_test.dart
@@ -291,6 +291,130 @@
Platform: macOsPlatform,
});
});
+
+ group('build arguments', () {
+ String testApp, testFile;
+
+ setUp(() {
+ restoreAppStarter();
+ });
+
+ Future<void> appStarterSetup() async {
+ withMockDevice();
+
+ final MockDeviceLogReader mockDeviceLogReader = MockDeviceLogReader();
+ when(mockDevice.getLogReader()).thenReturn(mockDeviceLogReader);
+ final MockLaunchResult mockLaunchResult = MockLaunchResult();
+ when(mockLaunchResult.started).thenReturn(true);
+ when(mockDevice.startApp(
+ null,
+ mainPath: anyNamed('mainPath'),
+ route: anyNamed('route'),
+ debuggingOptions: anyNamed('debuggingOptions'),
+ platformArgs: anyNamed('platformArgs'),
+ prebuiltApplication: anyNamed('prebuiltApplication'),
+ usesTerminalUi: false,
+ )).thenAnswer((_) => Future<LaunchResult>.value(mockLaunchResult));
+ when(mockDevice.isAppInstalled(any)).thenAnswer((_) => Future<bool>.value(false));
+
+ testApp = fs.path.join(tempDir.path, 'test', 'e2e.dart');
+ testFile = fs.path.join(tempDir.path, 'test_driver', 'e2e_test.dart');
+
+ testRunner = (List<String> testArgs, String observatoryUri) async {
+ throwToolExit(null, exitCode: 123);
+ };
+ appStopper = expectAsync1(
+ (DriveCommand command) async {
+ return true;
+ },
+ count: 2,
+ );
+
+ final MemoryFileSystem memFs = fs;
+ await memFs.file(testApp).writeAsString('main() {}');
+ await memFs.file(testFile).writeAsString('main() {}');
+ }
+
+ testUsingContext('does not use pre-built app if no build arg provided', () async {
+ await appStarterSetup();
+
+ final List<String> args = <String>[
+ 'drive',
+ '--target=$testApp',
+ ];
+ try {
+ await createTestCommandRunner(command).run(args);
+ } on ToolExit catch (e) {
+ expect(e.exitCode, 123);
+ expect(e.message, null);
+ }
+ verify(mockDevice.startApp(
+ null,
+ mainPath: anyNamed('mainPath'),
+ route: anyNamed('route'),
+ debuggingOptions: anyNamed('debuggingOptions'),
+ platformArgs: anyNamed('platformArgs'),
+ prebuiltApplication: false,
+ usesTerminalUi: false,
+ ));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ });
+
+ testUsingContext('does not use pre-built app if --build arg provided', () async {
+ await appStarterSetup();
+
+ final List<String> args = <String>[
+ 'drive',
+ '--build',
+ '--target=$testApp',
+ ];
+ try {
+ await createTestCommandRunner(command).run(args);
+ } on ToolExit catch (e) {
+ expect(e.exitCode, 123);
+ expect(e.message, null);
+ }
+ verify(mockDevice.startApp(
+ null,
+ mainPath: anyNamed('mainPath'),
+ route: anyNamed('route'),
+ debuggingOptions: anyNamed('debuggingOptions'),
+ platformArgs: anyNamed('platformArgs'),
+ prebuiltApplication: false,
+ usesTerminalUi: false,
+ ));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ });
+
+ testUsingContext('uses prebuilt app if --no-build arg provided', () async {
+ await appStarterSetup();
+
+ final List<String> args = <String>[
+ 'drive',
+ '--no-build',
+ '--target=$testApp',
+ ];
+ try {
+ await createTestCommandRunner(command).run(args);
+ } on ToolExit catch (e) {
+ expect(e.exitCode, 123);
+ expect(e.message, null);
+ }
+ verify(mockDevice.startApp(
+ null,
+ mainPath: anyNamed('mainPath'),
+ route: anyNamed('route'),
+ debuggingOptions: anyNamed('debuggingOptions'),
+ platformArgs: anyNamed('platformArgs'),
+ prebuiltApplication: true,
+ usesTerminalUi: false,
+ ));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ });
+ });
});
}
@@ -301,3 +425,5 @@
}
class MockAndroidDevice extends Mock implements AndroidDevice { }
+
+class MockLaunchResult extends Mock implements LaunchResult { }