feat(shorebird_cli): shorebird preview clears app data before installing app (#1364)

This commit is contained in:
Felix Angelov
2023-10-05 11:06:33 -05:00
committed by GitHub
parent 76e26819e4
commit 8f7af310f1
6 changed files with 116 additions and 0 deletions
@@ -247,6 +247,7 @@ class PreviewCommand extends ShorebirdCommand {
final startAppProgress = logger.progress('Starting app');
try {
await adb.clearAppData(package: package, deviceId: deviceId);
await adb.startApp(package: package, deviceId: deviceId);
startAppProgress.complete();
} catch (error) {
@@ -27,6 +27,21 @@ class Adb {
return process.start(adbPath, command.split(' '));
}
/// Clears the app data for the given [package] name.
Future<void> clearAppData({required String package, String? deviceId}) async {
final args = [
if (deviceId != null) ...['-s', deviceId],
'shell',
'pm',
'clear',
package,
];
final result = await _exec(args.join(' '));
if (result.exitCode != 0) {
throw Exception('Unable to clear app data: ${result.stderr}');
}
}
/// Starts the app with the given [package] name.
Future<void> startApp({
required String package,
@@ -160,6 +160,7 @@ Or run on an iOS simulator without code signing
[
'--debug',
if (deviceId != null) ...['--id', deviceId],
'-r', // uninstall the app before reinstalling and clear app data
'--bundle',
bundlePath,
],
@@ -247,6 +247,12 @@ void main() {
deviceId: any(named: 'deviceId'),
),
).thenAnswer((_) async {});
when(
() => adb.clearAppData(
package: any(named: 'package'),
deviceId: any(named: 'deviceId'),
),
).thenAnswer((_) async {});
when(
() => adb.startApp(
package: any(named: 'package'),
@@ -367,6 +373,23 @@ void main() {
verify(() => bundletool.installApks(apks: apksPath())).called(1);
});
test('exits with code 70 when clearing app data fails', () async {
when(
() => artifactManager.extractZip(
zipFile: any(named: 'zipFile'),
outputDirectory: any(named: 'outputDirectory'),
),
).thenAnswer(createShorebirdYaml);
final exception = Exception('oops');
when(
() => adb.clearAppData(package: any(named: 'package')),
).thenThrow(exception);
final result = await runWithOverrides(command.run);
expect(result, equals(ExitCode.software.code));
verify(() => adb.clearAppData(package: packageName)).called(1);
});
test('exits with code 70 when starting app fails', () async {
when(
() => artifactManager.extractZip(
@@ -48,6 +48,71 @@ void main() {
);
});
group('clearAppData', () {
const package = 'com.example.app';
test('throws when unable to locate adb', () async {
when(() => androidSdk.adbPath).thenReturn(null);
await expectLater(
() => runWithOverrides(() => adb.clearAppData(package: package)),
throwsA(
isA<Exception>().having(
(e) => e.toString(),
'exception()',
contains('Unable to locate adb'),
),
),
);
});
test('throws process exits with non-zero exit code', () async {
when(
() => process.run(any(), any()),
).thenAnswer(
(_) async => const ShorebirdProcessResult(
exitCode: 1,
stdout: '',
stderr: 'oops',
),
);
await expectLater(
() => runWithOverrides(() => adb.clearAppData(package: package)),
throwsA(
isA<Exception>().having(
(e) => e.toString(),
'exception()',
contains('Unable to clear app data: oops'),
),
),
);
});
test('completes when process exits with 0', () async {
await expectLater(
runWithOverrides(() => adb.clearAppData(package: package)),
completes,
);
verify(
() => process.run(adbPath, 'shell pm clear $package'.split(' ')),
).called(1);
});
test('forwards deviceId when provided', () async {
const deviceId = '1234';
await expectLater(
runWithOverrides(
() => adb.clearAppData(package: package, deviceId: deviceId),
),
completes,
);
verify(
() => process.run(
adbPath,
'-s $deviceId shell pm clear $package'.split(' '),
),
).called(1);
});
});
group('startApp', () {
const package = 'com.example.app';
test('throws when unable to locate adb', () async {
@@ -93,6 +93,7 @@ void main() {
'--debug',
'--id',
deviceId,
'-r',
'--bundle',
bundlePath,
]),
@@ -113,6 +114,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),
@@ -132,6 +134,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),
@@ -157,6 +160,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),
@@ -183,6 +187,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),
@@ -207,6 +212,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),
@@ -232,6 +238,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),
@@ -257,6 +264,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),
@@ -287,6 +295,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),
@@ -312,6 +321,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),
@@ -336,6 +346,7 @@ void main() {
verify(
() => shorebirdProcess.start(any(that: endsWith('ios-deploy')), [
'--debug',
'-r',
'--bundle',
bundlePath,
]),