Skip to content

Commit

Permalink
Allow for specifying a particular device to use (#53)
Browse files Browse the repository at this point in the history
* implement "--device" option for command "maestro drive"

* set version to 0.0.9

* improve READMEs
  • Loading branch information
bartekpacia authored Jun 7, 2022
1 parent c3fd3ad commit e010962
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 44 deletions.
2 changes: 1 addition & 1 deletion AutomatorServer/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ android {
minSdkVersion 26
targetSdkVersion 32
versionCode 1
versionName "0.0.8"
versionName "0.0.9"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Simple, easy-to-learn, Flutter-native UI testing framework eliminating
limitations of `flutter_driver`.

[![maestro_test on pub.dev][pub_badge_test]][pub_link_test]

[![maestro_cli on pub.dev][pub_badge_cli]][pub_link_cli]
[![code style][pub_badge_style]][pub_badge_link]

## CLI

Expand Down Expand Up @@ -34,7 +34,7 @@ $ maestro drive

## Package

The `maestro_test` package builds on top of `flutter_driver` to make it easy to
`maestro_test` package builds on top of `flutter_driver` to make it easy to
control the native device. It does this by using Android's
[UIAutomator][ui_automator] library.

Expand Down Expand Up @@ -103,9 +103,11 @@ git tag -a "maestro_cli-v0.0.4" -m "Release notes go here"

2. Push it! GitHub Actions will take care of the rest.

[pub_badge_test]: https://img.shields.io/pub/v/maestro_test.svg
[pub_badge_test]: https://img.shields.io/pub/v/maestro_test?label=maestro_test
[pub_link_test]: https://pub.dartlang.org/packages/maestro_test
[pub_badge_cli]: https://img.shields.io/pub/v/maestro_cli.svg
[pub_badge_cli]: https://img.shields.io/pub/v/maestro_cli?label=maestro_cli
[pub_badge_style]: https://img.shields.io/badge/style-leancode__lint-black
[pub_badge_link]: https://pub.dartlang.org/packages/lean_code_lint
[pub_link_cli]: https://pub.dartlang.org/packages/maestro_cli
[ui_automator]: https://developer.android.com/training/testing/other-components/ui-automator
[annotated_tag]: https://git-scm.com/book/en/v2/Git-Basics-Tagging#_annotated_tags
5 changes: 5 additions & 0 deletions packages/maestro_cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.0.9

- Add `--device` option for `maestro drive`, which allows you to specify the
device to use. Devices can be obtained using `adb devices`.

## 0.0.8

- Fix `maestro drive` on Windows crashing with ProcessException.
Expand Down
17 changes: 12 additions & 5 deletions packages/maestro_cli/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# maestro_cli

Command-line tool for [maestro_test][pub_link_test].

[![maestro_cli on pub.dev][pub_badge]][pub_link]
[![code style][pub_badge_style]][pub_badge_link]

Command-line tool to make working with [maestro_test][pub_link_test] easier.

## Installation

Expand All @@ -19,9 +20,11 @@ $ dart pub global activate maestro_cli
3. Go to `packages/maestro_cli`.
4. Run `dart pub global activate --source path .`

Now you can should be able to run `maestro` in your terminal. If you can't and
the error is something along the lines of "command not found", make sure that
you've added appropriate directories to PATH:
### Troubleshooting

If you can't run `maestro` from the terminal and the error is something along
the lines of "command not found", make sure that you've added appropriate
directories to PATH:

- on Unix-like systems, add `$HOME/.pub-cache/bin`
- on Windows, add `%USERPROFILE%\AppData\Local\Pub\Cache\bin`
Expand Down Expand Up @@ -57,3 +60,7 @@ Run `maestro bootstrap` to automatically do 1, 2, 3, 4, and most of 5.
[pub_badge]: https://img.shields.io/pub/v/maestro_cli.svg
[pub_link]: https://pub.dartlang.org/packages/maestro_cli
[pub_link_test]: https://pub.dartlang.org/packages/maestro_test
[pub_badge]: https://img.shields.io/pub/v/maestro_cli.svg
[pub_link]: https://pub.dartlang.org/packages/maestro_cli
[pub_badge_style]: https://img.shields.io/badge/style-leancode__lint-black
[pub_badge_link]: https://pub.dartlang.org/packages/lean_code_lint
18 changes: 14 additions & 4 deletions packages/maestro_cli/lib/src/commands/drive_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class DriveCommand extends Command<int> {
'driver',
abbr: 'd',
help: 'Dart file which starts flutter_driver.',
)
..addOption(
'device',
help: 'Serial number of ADB device to use.',
);
}

Expand Down Expand Up @@ -65,17 +69,23 @@ class DriveCommand extends Command<int> {
throw const FormatException('`driver` argument is not a string');
}

final device = argResults?['device'] as String?;

final options = MaestroDriveOptions(
host: host,
port: int.parse(portStr),
target: target,
driver: driver,
);

await adb.installApps();
await adb.forwardPorts(options.port);
await adb.runServer();
await flutter_driver.runTestsWithOutput(options.driver, options.target);
await adb.installApps(device: device);
await adb.forwardPorts(options.port, device: device);
await adb.runServer(device: device);
await flutter_driver.runTestsWithOutput(
options.driver,
options.target,
device: device,
);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/maestro_cli/lib/src/common/constants.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// Version of Maestro CLI. Must be kept in sync with pubspec.yaml.
const version = '0.0.8';
const version = '0.0.9';

const maestroPackage = 'maestro_test';
const maestroCliPackage = 'maestro_cli';
Expand Down
24 changes: 18 additions & 6 deletions packages/maestro_cli/lib/src/external/adb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import 'dart:io';
import 'package:maestro_cli/src/common/common.dart';
import 'package:path/path.dart' as path;

Future<void> installApps() async {
Future<void> installApps({String? device}) async {
final progress1 = log.progress('Installing server');
try {
await _installApk(serverArtifactFile);
await _installApk(serverArtifactFile, device: device);
} catch (err) {
progress1.fail('Failed to install server');
rethrow;
Expand All @@ -16,7 +16,7 @@ Future<void> installApps() async {

final progress2 = log.progress('Installing instrumentation');
try {
await _installApk(instrumentationArtifactFile);
await _installApk(instrumentationArtifactFile, device: device);
} catch (err) {
progress2.fail('Failed to install instrumentation');
rethrow;
Expand All @@ -25,12 +25,16 @@ Future<void> installApps() async {
progress2.complete('Installed instrumentation');
}

Future<void> forwardPorts(int port) async {
Future<void> forwardPorts(int port, {String? device}) async {
final progress = log.progress('Forwarding ports');

final result = await Process.run(
'adb',
[
if (device != null) ...[
'-s',
device,
],
'forward',
'tcp:$port',
'tcp:$port',
Expand All @@ -46,14 +50,18 @@ Future<void> forwardPorts(int port) async {
progress.complete('Forwarded ports');
}

Future<void> runServer() async {
Future<void> runServer({String? device}) async {
final progress = log.progress('Starting instrumentation server');

Process process;
try {
process = await Process.start(
'adb',
[
if (device != null) ...[
'-s',
device,
],
'shell',
'am',
'instrument',
Expand Down Expand Up @@ -82,10 +90,14 @@ Future<void> runServer() async {
progress.complete('Started instrumentation server');
}

Future<void> _installApk(String name) async {
Future<void> _installApk(String name, {String? device}) async {
final result = await Process.run(
'adb',
[
if (device != null) ...[
'-s',
device,
],
'install',
path.join(artifactPath, name),
],
Expand Down
35 changes: 30 additions & 5 deletions packages/maestro_cli/lib/src/external/flutter_driver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:maestro_cli/src/common/common.dart';

/// Runs flutter driver with the given [driver] and [target] and waits until the
/// drive is done.
Future<void> runTests(String driver, String target) async {
Future<void> runTests(String driver, String target, {String? device}) async {
log.info('Running tests...');

final res = await Process.run(
Expand All @@ -15,6 +15,10 @@ Future<void> runTests(String driver, String target) async {
driver,
'--target',
target,
if (device != null) ...[
'--device-id',
device,
],
],
runInShell: true,
);
Expand All @@ -28,7 +32,11 @@ Future<void> runTests(String driver, String target) async {
/// drive is done.
///
/// Prints standard output of "flutter drive".
Future<void> runTestsWithOutput(String driver, String target) async {
Future<void> runTestsWithOutput(
String driver,
String target, {
String? device,
}) async {
log.info('Running tests with output...');

final res = await Process.start(
Expand All @@ -39,11 +47,15 @@ Future<void> runTestsWithOutput(String driver, String target) async {
driver,
'--target',
target,
if (device != null) ...[
'--device-id',
device,
],
],
runInShell: true,
);

final sub = res.stdout.listen((msg) {
final stdOutSub = res.stdout.listen((msg) {
final text = 'driver: ${systemEncoding.decode(msg)}';
if (text.contains('I/flutter')) {
log.info(text);
Expand All @@ -52,6 +64,19 @@ Future<void> runTestsWithOutput(String driver, String target) async {
}
});

await res.exitCode;
await sub.cancel();
final stdErrSub = res.stderr.listen((msg) {
final text = 'driver: ${systemEncoding.decode(msg)}';
log.severe(text);
});

final exitCode = await res.exitCode;
await stdOutSub.cancel();
await stdErrSub.cancel();

final msg = 'flutter_driver exited with code $exitCode';
if (exitCode == 0) {
log.info(msg);
} else {
log.severe(msg);
}
}
2 changes: 1 addition & 1 deletion packages/maestro_cli/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: maestro_cli
description: CLI for Maestro.
version: 0.0.8
version: 0.0.9
homepage: https://github.com/leancodepl/maestro

environment:
Expand Down
74 changes: 57 additions & 17 deletions packages/maestro_test/README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,68 @@
# maestro_test

TODO: Put a short description of the package here that helps potential users
know whether this package might be useful for them.
[![maestro_test on pub.dev][pub_badge]][pub_link]
[![code style][pub_badge_style]][pub_badge_link]

## Features
`maestro_test` package builds on top of `flutter_driver` to make it easy to
control the native device from Dart. It does this by using Android's
[UIAutomator][ui_automator] library.

TODO: List what your package can do. Maybe include images, gifs, or videos.
### Installation

## Getting started
Add `maestro_test` as a dev dependency in `pubspec.yaml`:

TODO: List prerequisites and provide or point to information on how to
start using the package.

## Usage
```
dev_dependencies:
maestro_test: ^0.0.3
```

TODO: Include short and useful examples for package users. Add longer examples
to `/example` folder.
### Usage

```dart
const like = 'sample';
```
// integration_test/app_test.dart
import 'package:example/app.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:maestro_test/maestro_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
Automator.init(verbose: true);
final automator = Automator.instance;
testWidgets(
"counter state is the same after going to Home and switching apps",
(WidgetTester tester) async {
Text findCounterText() {
return tester
.firstElement(find.byKey(const ValueKey('counterText')))
.widget as Text;
}
await tester.pumpWidget(const MyApp());
await tester.pumpAndSettle();
## Additional information
await tester.tap(find.byType(FloatingActionButton));
await tester.pumpAndSettle();
expect(findCounterText().data, '1');
await automator.pressHome();
await automator.pressDoubleRecentApps();
expect(findCounterText().data, '1');
await tester.tap(find.byType(FloatingActionButton));
await tester.pumpAndSettle();
expect(findCounterText().data, '2');
await automator.openNotifications();
},
);
}
```

TODO: Tell users more about the package: where to find more information, how to
contribute to the package, how to file issues, what response they can expect
from the package authors, and more.
[pub_badge]: https://img.shields.io/pub/v/maestro_test.svg
[pub_link]: https://pub.dartlang.org/packages/maestro_test
[pub_badge_style]: https://img.shields.io/badge/style-leancode__lint-black
[pub_badge_link]: https://pub.dartlang.org/packages/lean_code_lint

0 comments on commit e010962

Please sign in to comment.