diff --git a/lib/model/image_metadata.dart b/lib/model/image_metadata.dart index 7c7e32490..a383d93df 100644 --- a/lib/model/image_metadata.dart +++ b/lib/model/image_metadata.dart @@ -44,7 +44,7 @@ class CatalogMetadata { this.xmpTitleDescription, double latitude, double longitude, - }) + }) // Geocoder throws an IllegalArgumentException when a coordinate has a funky values like 1.7056881853375E7 : latitude = latitude == null || latitude < -90.0 || latitude > 90.0 ? null : latitude, longitude = longitude == null || longitude < -180.0 || longitude > 180.0 ? null : longitude; diff --git a/lib/widgets/album/app_bar.dart b/lib/widgets/album/app_bar.dart index 0ad3967a1..bec58cb88 100644 --- a/lib/widgets/album/app_bar.dart +++ b/lib/widgets/album/app_bar.dart @@ -123,6 +123,7 @@ class _CollectionAppBarState extends State with SingleTickerPr tooltip = MaterialLocalizations.of(context).backButtonTooltip; } return IconButton( + key: Key('appbar-leading-button'), icon: AnimatedIcon( icon: AnimatedIcons.menu_arrow, progress: _browseToSelectAnimation, diff --git a/lib/widgets/app_drawer.dart b/lib/widgets/app_drawer.dart index 29bde3213..c24c77d01 100644 --- a/lib/widgets/app_drawer.dart +++ b/lib/widgets/app_drawer.dart @@ -200,6 +200,7 @@ class _AppDrawerState extends State { top: false, bottom: false, child: ListTile( + key: Key('albums-tile'), leading: Icon(AIcons.album), title: Text('Albums'), trailing: StreamBuilder( diff --git a/pubspec.yaml b/pubspec.yaml index cd7d16347..2b9345946 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -86,9 +86,14 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - # flutter drive --target=test_driver/app.dart + + # run on any device: + # % flutter drive -t test_driver/app.dart + # capture shaders in profile mode (real device only): + # % flutter drive -t test_driver/app.dart --profile --cache-sksl --write-sksl-on-exit shaders.sksl.json flutter_driver: sdk: flutter + test: any flutter: diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 9d9fd8052..cceb74971 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -5,8 +5,8 @@ import 'package:pedantic/pedantic.dart'; import 'package:test/test.dart'; import 'constants.dart'; -import 'driver_extension.dart'; -import 'utils.dart'; +import 'utils/adb_utils.dart'; +import 'utils/driver_extension.dart'; FlutterDriver driver; @@ -32,11 +32,13 @@ void main() { agreeToTerms(); sortCollection(); groupCollection(); + selectFirstAlbum(); searchAlbum(); showFullscreen(); toggleOverlay(); zoom(); showInfoMetadata(); + scrollOffImage(); test('contemplation', () async { await Future.delayed(Duration(seconds: 5)); @@ -48,14 +50,10 @@ void agreeToTerms() { test('[welcome] agree to terms', () async { await driver.scroll(find.text('Terms of Service'), 0, -300, Duration(milliseconds: 500)); - final buttonFinder = find.byValueKey('continue-button'); - expect(await isEnabled(driver, buttonFinder), equals(false)); - await driver.tap(find.byValueKey('agree-checkbox')); await Future.delayed(Duration(seconds: 1)); - expect(await isEnabled(driver, buttonFinder), equals(true)); - await driver.tap(buttonFinder); + await driver.tap(find.byValueKey('continue-button')); await driver.waitUntilNoTransientCallbacks(); expect(await driver.getText(find.byValueKey('appbar-title')), 'Aves'); @@ -88,6 +86,23 @@ void sortCollection() { }); } +void selectFirstAlbum() { + test('[collection] select first album', () async { + await driver.tap(find.byValueKey('appbar-leading-button')); + await driver.waitUntilNoTransientCallbacks(); + + await driver.tap(find.byValueKey('albums-tile')); + await driver.waitUntilNoTransientCallbacks(); + + await driver.tap(find.descendant( + of: find.byType('FilterGridPage'), + matching: find.byType('DecoratedFilterChip'), + firstMatchOnly: true, + )); + await driver.waitUntilNoTransientCallbacks(); + }); +} + void searchAlbum() { test('[collection] search album', () async { await driver.tap(find.byValueKey('search-button')); @@ -97,9 +112,9 @@ void searchAlbum() { await driver.tap(find.byType('TextField')); await driver.enterText(album); - final albumChipFinder = find.byValueKey('album-$album'); - await driver.waitFor(albumChipFinder); - await driver.tap(albumChipFinder); + final albumChip = find.byValueKey('album-$album'); + await driver.waitFor(albumChip); + await driver.tap(albumChip); }); } @@ -113,60 +128,67 @@ void showFullscreen() { void toggleOverlay() { test('[fullscreen] toggle overlay', () async { - final imageViewFinder = find.byValueKey('imageview'); + final imageView = find.byValueKey('imageview'); print('* hide overlay'); - await driver.tap(imageViewFinder); + await driver.tap(imageView); await Future.delayed(Duration(seconds: 1)); print('* show overlay'); - await driver.tap(imageViewFinder); + await driver.tap(imageView); await Future.delayed(Duration(seconds: 1)); }); } void zoom() { test('[fullscreen] zoom cycle', () async { - final imageViewFinder = find.byValueKey('imageview'); + final imageView = find.byValueKey('imageview'); - await driver.doubleTap(imageViewFinder); + await driver.doubleTap(imageView); await Future.delayed(Duration(seconds: 1)); - await driver.doubleTap(imageViewFinder); + await driver.doubleTap(imageView); await Future.delayed(Duration(seconds: 1)); - await driver.doubleTap(imageViewFinder); + await driver.doubleTap(imageView); await Future.delayed(Duration(seconds: 1)); }); } void showInfoMetadata() { test('[fullscreen] show info', () async { - final verticalPageViewFinder = find.byValueKey('vertical-pageview'); + final verticalPageView = find.byValueKey('vertical-pageview'); print('* scroll down to info'); - await driver.scroll(verticalPageViewFinder, 0, -600, Duration(milliseconds: 400)); + await driver.scroll(verticalPageView, 0, -600, Duration(milliseconds: 400)); await Future.delayed(Duration(seconds: 2)); print('* scroll down to metadata details'); - await driver.scroll(verticalPageViewFinder, 0, -800, Duration(milliseconds: 600)); + await driver.scroll(verticalPageView, 0, -800, Duration(milliseconds: 600)); await Future.delayed(Duration(seconds: 1)); print('* toggle GPS metadata'); - final gpsTileFinder = find.descendant( + final gpsTile = find.descendant( of: find.byValueKey('tilecard-GPS'), matching: find.byType('ListTile'), ); - await driver.tap(gpsTileFinder); + await driver.tap(gpsTile); await driver.waitUntilNoTransientCallbacks(); - await driver.tap(gpsTileFinder); + await driver.tap(gpsTile); await driver.waitUntilNoTransientCallbacks(); print('* scroll up to show app bar'); - await driver.scroll(verticalPageViewFinder, 0, 100, Duration(milliseconds: 400)); + await driver.scroll(verticalPageView, 0, 100, Duration(milliseconds: 400)); await Future.delayed(Duration(seconds: 1)); print('* back to image'); await driver.tap(find.byValueKey('back-button')); }); } + +void scrollOffImage() { + test('[fullscreen] scroll off', () async { + await driver.scroll(find.byValueKey('imageview'), 0, 800, Duration(milliseconds: 600)); + await Future.delayed(Duration(seconds: 1)); + }); +} diff --git a/test_driver/constants.dart b/test_driver/constants.dart index fb95e38fb..3e6962cf8 100644 --- a/test_driver/constants.dart +++ b/test_driver/constants.dart @@ -1,3 +1,2 @@ const sourcePicturesDir = 'test_driver/assets/'; const targetPicturesDir = '/sdcard/Pictures/Aves Test Driver/'; - diff --git a/test_driver/utils.dart b/test_driver/utils/adb_utils.dart similarity index 71% rename from test_driver/utils.dart rename to test_driver/utils/adb_utils.dart index 62d5b5d8d..ee2024efb 100644 --- a/test_driver/utils.dart +++ b/test_driver/utils/adb_utils.dart @@ -1,17 +1,7 @@ import 'dart:io'; -import 'package:flutter_driver/flutter_driver.dart'; import 'package:path/path.dart' as path; -// conditions - -Future isEnabled(FlutterDriver driver, SerializableFinder widgetFinder) async { - Map widgetDiagnostics = await driver.getWidgetDiagnostics(widgetFinder); - return widgetDiagnostics['properties'].firstWhere((property) => property['name'] == 'enabled')['value']; -} - -// ADB - String get adb { final env = Platform.environment; final sdkDir = env['ANDROID_SDK_ROOT'] ?? env['ANDROID_SDK']; @@ -25,18 +15,18 @@ String get adb { you need to use the -d, -e, or -s option to specify the target device to which the command should be directed. */ -const List adbDeviceParam = ['-e']; // '[-d]', '[-e]', or '[-s, ]' +const List adbDeviceParam = []; // '[]', '[-d]', '[-e]', or '[-s, ]' Future runAdb(List args) async { await Process.runSync(adb, [...adbDeviceParam, ...args]); } Future createDirectory(String dir) async { - await runAdb(['shell', 'mkdir -p', dir.replaceAll(' ', '\\ ')]); + await runAdb(['shell', 'mkdir', '-p', dir.replaceAll(' ', '\\ ')]); } Future removeDirectory(String dir) async { - await runAdb(['shell', 'rm -r', dir.replaceAll(' ', '\\ ')]); + await runAdb(['shell', 'rm', '-r', dir.replaceAll(' ', '\\ ')]); } Future copyContent(String sourceDir, String targetDir) async { diff --git a/test_driver/driver_extension.dart b/test_driver/utils/driver_extension.dart similarity index 100% rename from test_driver/driver_extension.dart rename to test_driver/utils/driver_extension.dart