diff --git a/lib/widgets/collection/app_bar.dart b/lib/widgets/collection/app_bar.dart index 0f364a23c..7fcb9a5eb 100644 --- a/lib/widgets/collection/app_bar.dart +++ b/lib/widgets/collection/app_bar.dart @@ -133,6 +133,7 @@ class _CollectionAppBarState extends State with SingleTickerPr tooltip = MaterialLocalizations.of(context).openAppDrawerTooltip; } return IconButton( + // key is expected by test driver key: const Key('appbar-leading-button'), icon: AnimatedIcon( icon: AnimatedIcons.menu_arrow, @@ -188,6 +189,7 @@ class _CollectionAppBarState extends State with SingleTickerPr final canAddShortcuts = snapshot.data ?? false; return MenuIconTheme( child: PopupMenuButton( + // key is expected by test driver key: const Key('appbar-menu-button'), itemBuilder: (context) { final groupable = collection.sortFactor == EntrySortFactor.date; @@ -201,11 +203,13 @@ class _CollectionAppBarState extends State with SingleTickerPr return [ _toMenuItem( EntrySetAction.sort, + // key is expected by test driver key: const Key('menu-sort'), ), if (groupable) _toMenuItem( EntrySetAction.group, + // key is expected by test driver key: const Key('menu-group'), ), if (appMode == AppMode.main) ...[ diff --git a/lib/widgets/collection/collection_page.dart b/lib/widgets/collection/collection_page.dart index f4ad0c5cc..9cd50c7f6 100644 --- a/lib/widgets/collection/collection_page.dart +++ b/lib/widgets/collection/collection_page.dart @@ -56,6 +56,7 @@ class _CollectionPageState extends State { child: ChangeNotifierProvider.value( value: collection, child: const CollectionGrid( + // key is expected by test driver key: Key('collection-grid'), ), ), diff --git a/lib/widgets/common/identity/aves_expansion_tile.dart b/lib/widgets/common/identity/aves_expansion_tile.dart index f745c79a4..a2cfca454 100644 --- a/lib/widgets/common/identity/aves_expansion_tile.dart +++ b/lib/widgets/common/identity/aves_expansion_tile.dart @@ -48,6 +48,7 @@ class AvesExpansionTile extends StatelessWidget { accentColor: Colors.white, ), child: ExpansionTileCard( + // key is expected by test driver key: Key('tilecard-$value'), value: value, expandedNotifier: expandedNotifier, diff --git a/lib/widgets/dialogs/aves_selection_dialog.dart b/lib/widgets/dialogs/aves_selection_dialog.dart index 9db644f29..d339470a4 100644 --- a/lib/widgets/dialogs/aves_selection_dialog.dart +++ b/lib/widgets/dialogs/aves_selection_dialog.dart @@ -51,6 +51,7 @@ class _AvesSelectionDialogState extends State> { Widget _buildRadioListTile(T value, String title) { final subtitle = widget.optionSubtitleBuilder?.call(value); return ReselectableRadioListTile( + // key is expected by test driver key: Key(value.toString()), value: value, groupValue: _selectedValue, diff --git a/lib/widgets/drawer/app_drawer.dart b/lib/widgets/drawer/app_drawer.dart index bdee8ebfc..28765222b 100644 --- a/lib/widgets/drawer/app_drawer.dart +++ b/lib/widgets/drawer/app_drawer.dart @@ -142,6 +142,7 @@ class _AppDrawerState extends State { runSpacing: 8, children: [ OutlinedButton.icon( + // key is expected by test driver key: const Key('drawer-about-button'), onPressed: () => goTo(AboutPage.routeName, (_) => const AboutPage()), icon: const Icon(AIcons.info), @@ -178,6 +179,7 @@ class _AppDrawerState extends State { ), ), OutlinedButton.icon( + // key is expected by test driver key: const Key('drawer-settings-button'), onPressed: () => goTo(SettingsPage.routeName, (_) => const SettingsPage()), icon: const Icon(AIcons.settings), diff --git a/lib/widgets/drawer/page_nav_tile.dart b/lib/widgets/drawer/page_nav_tile.dart index fdf462655..e442c5074 100644 --- a/lib/widgets/drawer/page_nav_tile.dart +++ b/lib/widgets/drawer/page_nav_tile.dart @@ -24,6 +24,7 @@ class PageNavTile extends StatelessWidget { top: false, bottom: false, child: ListTile( + // key is expected by test driver key: Key('$routeName-tile'), leading: DrawerPageIcon(route: routeName), title: DrawerPageTitle(route: routeName), diff --git a/lib/widgets/filter_grids/common/app_bar.dart b/lib/widgets/filter_grids/common/app_bar.dart index 8c48c9433..c60169bb7 100644 --- a/lib/widgets/filter_grids/common/app_bar.dart +++ b/lib/widgets/filter_grids/common/app_bar.dart @@ -98,6 +98,7 @@ class _FilterGridAppBarState extends State extends State( - key: const Key('appbar-menu-button'), itemBuilder: (context) { final selectedItems = selection.selectedItems; final hasSelection = selectedItems.isNotEmpty; diff --git a/lib/widgets/filter_grids/common/filter_grid_page.dart b/lib/widgets/filter_grids/common/filter_grid_page.dart index 9e6c746ed..d7d483b2d 100644 --- a/lib/widgets/filter_grids/common/filter_grid_page.dart +++ b/lib/widgets/filter_grids/common/filter_grid_page.dart @@ -90,6 +90,8 @@ class FilterGridPage extends StatelessWidget { child: AnimatedBuilder( animation: covers, builder: (context, child) => FilterGrid( + // key is expected by test driver + key: const Key('filter-grid'), settingsRouteKey: settingsRouteKey, appBar: appBar, appBarHeight: appBarHeight, diff --git a/lib/widgets/filter_grids/common/filter_nav_page.dart b/lib/widgets/filter_grids/common/filter_nav_page.dart index e073e4f5d..65b2d36df 100644 --- a/lib/widgets/filter_grids/common/filter_nav_page.dart +++ b/lib/widgets/filter_grids/common/filter_nav_page.dart @@ -39,7 +39,6 @@ class FilterNavigationPage extends StatelessWidget { return SelectionProvider>( child: Builder( builder: (context) => FilterGridPage( - key: const Key('filter-grid-page'), appBar: FilterGridAppBar( source: source, title: title, diff --git a/lib/widgets/search/search_button.dart b/lib/widgets/search/search_button.dart index 9b4fa9701..dbda912df 100644 --- a/lib/widgets/search/search_button.dart +++ b/lib/widgets/search/search_button.dart @@ -17,6 +17,7 @@ class CollectionSearchButton extends StatelessWidget { @override Widget build(BuildContext context) { return IconButton( + // key is expected by test driver key: const Key('search-button'), icon: const Icon(AIcons.search), onPressed: () => _goToSearch(context), diff --git a/lib/widgets/viewer/entry_horizontal_pager.dart b/lib/widgets/viewer/entry_horizontal_pager.dart index 9bb81bd86..4670105e4 100644 --- a/lib/widgets/viewer/entry_horizontal_pager.dart +++ b/lib/widgets/viewer/entry_horizontal_pager.dart @@ -38,6 +38,7 @@ class _MultiEntryScrollerState extends State with AutomaticK return MagnifierGestureDetectorScope( axis: const [Axis.horizontal, Axis.vertical], child: PageView.builder( + // key is expected by test driver key: const Key('horizontal-pageview'), scrollDirection: Axis.horizontal, controller: pageController, @@ -81,6 +82,7 @@ class _MultiEntryScrollerState extends State with AutomaticK Widget _buildViewer(AvesEntry mainEntry, {AvesEntry? pageEntry}) { return EntryPageView( + // key is expected by test driver key: const Key('imageview'), mainEntry: mainEntry, pageEntry: pageEntry ?? mainEntry, diff --git a/lib/widgets/viewer/entry_vertical_pager.dart b/lib/widgets/viewer/entry_vertical_pager.dart index 438e503de..ff1b785d2 100644 --- a/lib/widgets/viewer/entry_vertical_pager.dart +++ b/lib/widgets/viewer/entry_vertical_pager.dart @@ -131,6 +131,7 @@ class _ViewerVerticalPageViewState extends State { child: child, ), child: PageView( + // key is expected by test driver key: const Key('vertical-pageview'), scrollDirection: Axis.vertical, controller: widget.verticalPager, diff --git a/lib/widgets/viewer/info/info_app_bar.dart b/lib/widgets/viewer/info/info_app_bar.dart index 5bc3d7559..4860026f7 100644 --- a/lib/widgets/viewer/info/info_app_bar.dart +++ b/lib/widgets/viewer/info/info_app_bar.dart @@ -22,6 +22,7 @@ class InfoAppBar extends StatelessWidget { Widget build(BuildContext context) { return SliverAppBar( leading: IconButton( + // key is expected by test driver key: const Key('back-button'), icon: const Icon(AIcons.goUp), onPressed: onBackPressed, diff --git a/lib/widgets/welcome_page.dart b/lib/widgets/welcome_page.dart index c88705076..fb71abbcd 100644 --- a/lib/widgets/welcome_page.dart +++ b/lib/widgets/welcome_page.dart @@ -109,6 +109,7 @@ class _WelcomePageState extends State { text: context.l10n.welcomeCrashReportToggle, ), LabeledCheckbox( + // key is expected by test driver key: const Key('agree-checkbox'), value: _hasAcceptedTerms, onChanged: (v) { @@ -120,6 +121,7 @@ class _WelcomePageState extends State { ); final button = ElevatedButton( + // key is expected by test driver key: const Key('continue-button'), onPressed: _hasAcceptedTerms ? () { diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 91709081e..52da9a1d6 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -129,10 +129,11 @@ void selectFirstAlbum() { // wait for collection loading await driver.waitForCondition(const NoPendingPlatformMessages()); - // TODO TLAD fix finder + // delay to avoid flaky descendant resolution + await Future.delayed(const Duration(seconds: 2)); await driver.tap(find.descendant( - of: find.byValueKey('filter-grid-page'), - matching: find.byType('CoveredFilterChip'), + of: find.byValueKey('filter-grid'), + matching: find.byType('MetaData'), firstMatchOnly: true, )); await driver.waitUntilNoTransientCallbacks(); @@ -158,9 +159,11 @@ void searchAlbum() { void showViewer() { test('[collection] show viewer', () async { + // delay to avoid flaky descendant resolution + await Future.delayed(const Duration(seconds: 2)); await driver.tap(find.descendant( of: find.byValueKey('collection-grid'), - matching: find.byType('DecoratedThumbnail'), + matching: find.byType('MetaData'), firstMatchOnly: true, )); await driver.waitUntilNoTransientCallbacks(); diff --git a/test_driver/utils/adb_utils.dart b/test_driver/utils/adb_utils.dart index a663f6ea9..c56f43758 100644 --- a/test_driver/utils/adb_utils.dart +++ b/test_driver/utils/adb_utils.dart @@ -3,10 +3,13 @@ import 'dart:io'; import 'package:path/path.dart' as p; String get adb { - final env = Platform.environment; - // e.g. C:\Users\\AppData\Local\Android\Sdk - final sdkDir = env['ANDROID_SDK_ROOT'] ?? env['ANDROID_SDK']!; - return p.join(sdkDir, 'platform-tools', Platform.isWindows ? 'adb.exe' : 'adb'); + if (Platform.isWindows) { + final env = Platform.environment; + // e.g. C:\Users\\AppData\Local\Android\Sdk + final sdkDir = env['ANDROID_SDK_ROOT'] ?? env['ANDROID_SDK']!; + return p.join(sdkDir, 'platform-tools', 'adb.exe'); + } + return 'adb'; } /*