diff --git a/lib/widgets/fullscreen/info/info_page.dart b/lib/widgets/fullscreen/info/info_page.dart index 9142f62ca..adf9b7abf 100644 --- a/lib/widgets/fullscreen/info/info_page.dart +++ b/lib/widgets/fullscreen/info/info_page.dart @@ -40,6 +40,7 @@ class InfoPageState extends State { final appBar = SliverAppBar( leading: IconButton( + key: Key('back-button'), icon: Icon(AIcons.goUp), onPressed: _goToImage, tooltip: 'Back to image', diff --git a/lib/widgets/fullscreen/info/metadata_section.dart b/lib/widgets/fullscreen/info/metadata_section.dart index f2544e1a4..fb3cf769e 100644 --- a/lib/widgets/fullscreen/info/metadata_section.dart +++ b/lib/widgets/fullscreen/info/metadata_section.dart @@ -87,6 +87,7 @@ class _MetadataSectionSliverState extends State with Auto accentColor: Colors.white, ), child: ExpansionTileCard( + key: Key('tilecard-${dir.name}'), value: dir.name, expandedNotifier: _expandedDirectoryNotifier, title: _DirectoryTitle(dir.name), diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 51474292d..9d9fd8052 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -5,14 +5,16 @@ import 'package:pedantic/pedantic.dart'; import 'package:test/test.dart'; import 'constants.dart'; +import 'driver_extension.dart'; import 'utils.dart'; +FlutterDriver driver; + void main() { group('Aves app', () { - FlutterDriver driver; + print('adb=${[adb, ...adbDeviceParam].join(' ')}'); setUpAll(() async { - print('adb=${[adb, ...adbDeviceParam].join(' ')}'); await copyContent(sourcePicturesDir, targetPicturesDir); await grantPermissions('deckers.thibault.aves.debug', [ 'android.permission.READ_EXTERNAL_STORAGE', @@ -24,89 +26,147 @@ void main() { tearDownAll(() async { await removeDirectory(targetPicturesDir); - if (driver != null) { - unawaited(driver.close()); - } + unawaited(driver?.close()); }); - test('agree to terms and reach home', () async { - await driver.scroll(find.text('Terms of Service'), 0, -300, Duration(milliseconds: 500)); + agreeToTerms(); + sortCollection(); + groupCollection(); + searchAlbum(); + showFullscreen(); + toggleOverlay(); + zoom(); + showInfoMetadata(); - 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.waitUntilNoTransientCallbacks(); - - expect(await driver.getText(find.byValueKey('appbar-title')), 'Aves'); - }); - - test('sort collection', () async { - await driver.tap(find.byValueKey('appbar-menu-button')); - await driver.waitUntilNoTransientCallbacks(); - - await driver.tap(find.byValueKey('menu-sort')); - await driver.waitUntilNoTransientCallbacks(); - - await driver.tap(find.byValueKey(SortFactor.date.toString())); - await driver.tap(find.byValueKey('apply-button')); - }); - - test('group collection', () async { - await driver.tap(find.byValueKey('appbar-menu-button')); - await driver.waitUntilNoTransientCallbacks(); - - await driver.tap(find.byValueKey('menu-group')); - await driver.waitUntilNoTransientCallbacks(); - - await driver.tap(find.byValueKey(GroupFactor.album.toString())); - await driver.tap(find.byValueKey('apply-button')); - }); - - test('search album', () async { - await driver.tap(find.byValueKey('search-button')); - await driver.waitUntilNoTransientCallbacks(); - - final album = path.split(targetPicturesDir).last; - await driver.tap(find.byType('TextField')); - await driver.enterText(album); - - final albumChipFinder = find.byValueKey('album-$album'); - await driver.waitFor(albumChipFinder); - await driver.tap(albumChipFinder); - }); - - test('show fullscreen', () async { - await driver.tap(find.byType('DecoratedThumbnail')); - await driver.waitUntilNoTransientCallbacks(); - await Future.delayed(Duration(seconds: 2)); - - final imageViewFinder = find.byValueKey('imageview'); - - print('* hide overlay'); - await driver.tap(imageViewFinder); - await Future.delayed(Duration(seconds: 1)); - - print('* show overlay'); - await driver.tap(imageViewFinder); - await Future.delayed(Duration(seconds: 1)); - }); - - test('show info', () async { - final verticalPageViewFinder = find.byValueKey('vertical-pageview'); - - print('* scroll to info'); - await driver.scroll(verticalPageViewFinder, 0, -600, Duration(milliseconds: 400)); - await Future.delayed(Duration(seconds: 1)); - - // TODO TLAD find.pageBack -// print('* back to image'); -// await driver.tap(find.pageBack()); -// await Future.delayed(Duration(seconds: 5)); + test('contemplation', () async { + await Future.delayed(Duration(seconds: 5)); }); }, timeout: Timeout(Duration(seconds: 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.waitUntilNoTransientCallbacks(); + + expect(await driver.getText(find.byValueKey('appbar-title')), 'Aves'); + }); +} + +void groupCollection() { + test('[collection] group', () async { + await driver.tap(find.byValueKey('appbar-menu-button')); + await driver.waitUntilNoTransientCallbacks(); + + await driver.tap(find.byValueKey('menu-group')); + await driver.waitUntilNoTransientCallbacks(); + + await driver.tap(find.byValueKey(GroupFactor.album.toString())); + await driver.tap(find.byValueKey('apply-button')); + }); +} + +void sortCollection() { + test('[collection] sort', () async { + await driver.tap(find.byValueKey('appbar-menu-button')); + await driver.waitUntilNoTransientCallbacks(); + + await driver.tap(find.byValueKey('menu-sort')); + await driver.waitUntilNoTransientCallbacks(); + + await driver.tap(find.byValueKey(SortFactor.date.toString())); + await driver.tap(find.byValueKey('apply-button')); + }); +} + +void searchAlbum() { + test('[collection] search album', () async { + await driver.tap(find.byValueKey('search-button')); + await driver.waitUntilNoTransientCallbacks(); + + final album = path.split(targetPicturesDir).last; + await driver.tap(find.byType('TextField')); + await driver.enterText(album); + + final albumChipFinder = find.byValueKey('album-$album'); + await driver.waitFor(albumChipFinder); + await driver.tap(albumChipFinder); + }); +} + +void showFullscreen() { + test('[collection] show fullscreen', () async { + await driver.tap(find.byType('DecoratedThumbnail')); + await driver.waitUntilNoTransientCallbacks(); + await Future.delayed(Duration(seconds: 2)); + }); +} + +void toggleOverlay() { + test('[fullscreen] toggle overlay', () async { + final imageViewFinder = find.byValueKey('imageview'); + + print('* hide overlay'); + await driver.tap(imageViewFinder); + await Future.delayed(Duration(seconds: 1)); + + print('* show overlay'); + await driver.tap(imageViewFinder); + await Future.delayed(Duration(seconds: 1)); + }); +} + +void zoom() { + test('[fullscreen] zoom cycle', () async { + final imageViewFinder = find.byValueKey('imageview'); + + await driver.doubleTap(imageViewFinder); + await Future.delayed(Duration(seconds: 1)); + + await driver.doubleTap(imageViewFinder); + await Future.delayed(Duration(seconds: 1)); + + await driver.doubleTap(imageViewFinder); + await Future.delayed(Duration(seconds: 1)); + }); +} + +void showInfoMetadata() { + test('[fullscreen] show info', () async { + final verticalPageViewFinder = find.byValueKey('vertical-pageview'); + + print('* scroll down to info'); + await driver.scroll(verticalPageViewFinder, 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 Future.delayed(Duration(seconds: 1)); + + print('* toggle GPS metadata'); + final gpsTileFinder = find.descendant( + of: find.byValueKey('tilecard-GPS'), + matching: find.byType('ListTile'), + ); + await driver.tap(gpsTileFinder); + await driver.waitUntilNoTransientCallbacks(); + await driver.tap(gpsTileFinder); + await driver.waitUntilNoTransientCallbacks(); + + print('* scroll up to show app bar'); + await driver.scroll(verticalPageViewFinder, 0, 100, Duration(milliseconds: 400)); + await Future.delayed(Duration(seconds: 1)); + + print('* back to image'); + await driver.tap(find.byValueKey('back-button')); + }); +} diff --git a/test_driver/driver_extension.dart b/test_driver/driver_extension.dart new file mode 100644 index 000000000..9e10657c9 --- /dev/null +++ b/test_driver/driver_extension.dart @@ -0,0 +1,11 @@ +import 'package:flutter_driver/flutter_driver.dart'; + +extension ExtraFlutterDriver on FlutterDriver { + static const doubleTapDelay = Duration(milliseconds: 100); // in [kDoubleTapMinTime = 40 ms, kDoubleTapTimeout = 300 ms] + + Future doubleTap(SerializableFinder finder, {Duration timeout}) async { + await tap(finder, timeout: timeout); + await Future.delayed(doubleTapDelay); + await tap(finder, timeout: timeout); + } +}