test driver: fixed flaky descendant resolution
This commit is contained in:
parent
4ea1701462
commit
c0e11a68fa
16 changed files with 34 additions and 10 deletions
|
@ -133,6 +133,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
tooltip = MaterialLocalizations.of(context).openAppDrawerTooltip;
|
tooltip = MaterialLocalizations.of(context).openAppDrawerTooltip;
|
||||||
}
|
}
|
||||||
return IconButton(
|
return IconButton(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('appbar-leading-button'),
|
key: const Key('appbar-leading-button'),
|
||||||
icon: AnimatedIcon(
|
icon: AnimatedIcon(
|
||||||
icon: AnimatedIcons.menu_arrow,
|
icon: AnimatedIcons.menu_arrow,
|
||||||
|
@ -188,6 +189,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
final canAddShortcuts = snapshot.data ?? false;
|
final canAddShortcuts = snapshot.data ?? false;
|
||||||
return MenuIconTheme(
|
return MenuIconTheme(
|
||||||
child: PopupMenuButton<EntrySetAction>(
|
child: PopupMenuButton<EntrySetAction>(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('appbar-menu-button'),
|
key: const Key('appbar-menu-button'),
|
||||||
itemBuilder: (context) {
|
itemBuilder: (context) {
|
||||||
final groupable = collection.sortFactor == EntrySortFactor.date;
|
final groupable = collection.sortFactor == EntrySortFactor.date;
|
||||||
|
@ -201,11 +203,13 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
return [
|
return [
|
||||||
_toMenuItem(
|
_toMenuItem(
|
||||||
EntrySetAction.sort,
|
EntrySetAction.sort,
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('menu-sort'),
|
key: const Key('menu-sort'),
|
||||||
),
|
),
|
||||||
if (groupable)
|
if (groupable)
|
||||||
_toMenuItem(
|
_toMenuItem(
|
||||||
EntrySetAction.group,
|
EntrySetAction.group,
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('menu-group'),
|
key: const Key('menu-group'),
|
||||||
),
|
),
|
||||||
if (appMode == AppMode.main) ...[
|
if (appMode == AppMode.main) ...[
|
||||||
|
|
|
@ -56,6 +56,7 @@ class _CollectionPageState extends State<CollectionPage> {
|
||||||
child: ChangeNotifierProvider<CollectionLens>.value(
|
child: ChangeNotifierProvider<CollectionLens>.value(
|
||||||
value: collection,
|
value: collection,
|
||||||
child: const CollectionGrid(
|
child: const CollectionGrid(
|
||||||
|
// key is expected by test driver
|
||||||
key: Key('collection-grid'),
|
key: Key('collection-grid'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -48,6 +48,7 @@ class AvesExpansionTile extends StatelessWidget {
|
||||||
accentColor: Colors.white,
|
accentColor: Colors.white,
|
||||||
),
|
),
|
||||||
child: ExpansionTileCard(
|
child: ExpansionTileCard(
|
||||||
|
// key is expected by test driver
|
||||||
key: Key('tilecard-$value'),
|
key: Key('tilecard-$value'),
|
||||||
value: value,
|
value: value,
|
||||||
expandedNotifier: expandedNotifier,
|
expandedNotifier: expandedNotifier,
|
||||||
|
|
|
@ -51,6 +51,7 @@ class _AvesSelectionDialogState<T> extends State<AvesSelectionDialog<T>> {
|
||||||
Widget _buildRadioListTile(T value, String title) {
|
Widget _buildRadioListTile(T value, String title) {
|
||||||
final subtitle = widget.optionSubtitleBuilder?.call(value);
|
final subtitle = widget.optionSubtitleBuilder?.call(value);
|
||||||
return ReselectableRadioListTile<T>(
|
return ReselectableRadioListTile<T>(
|
||||||
|
// key is expected by test driver
|
||||||
key: Key(value.toString()),
|
key: Key(value.toString()),
|
||||||
value: value,
|
value: value,
|
||||||
groupValue: _selectedValue,
|
groupValue: _selectedValue,
|
||||||
|
|
|
@ -142,6 +142,7 @@ class _AppDrawerState extends State<AppDrawer> {
|
||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
children: [
|
children: [
|
||||||
OutlinedButton.icon(
|
OutlinedButton.icon(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('drawer-about-button'),
|
key: const Key('drawer-about-button'),
|
||||||
onPressed: () => goTo(AboutPage.routeName, (_) => const AboutPage()),
|
onPressed: () => goTo(AboutPage.routeName, (_) => const AboutPage()),
|
||||||
icon: const Icon(AIcons.info),
|
icon: const Icon(AIcons.info),
|
||||||
|
@ -178,6 +179,7 @@ class _AppDrawerState extends State<AppDrawer> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
OutlinedButton.icon(
|
OutlinedButton.icon(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('drawer-settings-button'),
|
key: const Key('drawer-settings-button'),
|
||||||
onPressed: () => goTo(SettingsPage.routeName, (_) => const SettingsPage()),
|
onPressed: () => goTo(SettingsPage.routeName, (_) => const SettingsPage()),
|
||||||
icon: const Icon(AIcons.settings),
|
icon: const Icon(AIcons.settings),
|
||||||
|
|
|
@ -24,6 +24,7 @@ class PageNavTile extends StatelessWidget {
|
||||||
top: false,
|
top: false,
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
// key is expected by test driver
|
||||||
key: Key('$routeName-tile'),
|
key: Key('$routeName-tile'),
|
||||||
leading: DrawerPageIcon(route: routeName),
|
leading: DrawerPageIcon(route: routeName),
|
||||||
title: DrawerPageTitle(route: routeName),
|
title: DrawerPageTitle(route: routeName),
|
||||||
|
|
|
@ -98,6 +98,7 @@ class _FilterGridAppBarState<T extends CollectionFilter> extends State<FilterGri
|
||||||
tooltip = MaterialLocalizations.of(context).openAppDrawerTooltip;
|
tooltip = MaterialLocalizations.of(context).openAppDrawerTooltip;
|
||||||
}
|
}
|
||||||
return IconButton(
|
return IconButton(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('appbar-leading-button'),
|
key: const Key('appbar-leading-button'),
|
||||||
icon: AnimatedIcon(
|
icon: AnimatedIcon(
|
||||||
icon: AnimatedIcons.menu_arrow,
|
icon: AnimatedIcons.menu_arrow,
|
||||||
|
@ -170,7 +171,6 @@ class _FilterGridAppBarState<T extends CollectionFilter> extends State<FilterGri
|
||||||
...buttonActions,
|
...buttonActions,
|
||||||
MenuIconTheme(
|
MenuIconTheme(
|
||||||
child: PopupMenuButton<ChipSetAction>(
|
child: PopupMenuButton<ChipSetAction>(
|
||||||
key: const Key('appbar-menu-button'),
|
|
||||||
itemBuilder: (context) {
|
itemBuilder: (context) {
|
||||||
final selectedItems = selection.selectedItems;
|
final selectedItems = selection.selectedItems;
|
||||||
final hasSelection = selectedItems.isNotEmpty;
|
final hasSelection = selectedItems.isNotEmpty;
|
||||||
|
|
|
@ -90,6 +90,8 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
|
||||||
child: AnimatedBuilder(
|
child: AnimatedBuilder(
|
||||||
animation: covers,
|
animation: covers,
|
||||||
builder: (context, child) => FilterGrid<T>(
|
builder: (context, child) => FilterGrid<T>(
|
||||||
|
// key is expected by test driver
|
||||||
|
key: const Key('filter-grid'),
|
||||||
settingsRouteKey: settingsRouteKey,
|
settingsRouteKey: settingsRouteKey,
|
||||||
appBar: appBar,
|
appBar: appBar,
|
||||||
appBarHeight: appBarHeight,
|
appBarHeight: appBarHeight,
|
||||||
|
|
|
@ -39,7 +39,6 @@ class FilterNavigationPage<T extends CollectionFilter> extends StatelessWidget {
|
||||||
return SelectionProvider<FilterGridItem<T>>(
|
return SelectionProvider<FilterGridItem<T>>(
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) => FilterGridPage<T>(
|
builder: (context) => FilterGridPage<T>(
|
||||||
key: const Key('filter-grid-page'),
|
|
||||||
appBar: FilterGridAppBar<T>(
|
appBar: FilterGridAppBar<T>(
|
||||||
source: source,
|
source: source,
|
||||||
title: title,
|
title: title,
|
||||||
|
|
|
@ -17,6 +17,7 @@ class CollectionSearchButton extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('search-button'),
|
key: const Key('search-button'),
|
||||||
icon: const Icon(AIcons.search),
|
icon: const Icon(AIcons.search),
|
||||||
onPressed: () => _goToSearch(context),
|
onPressed: () => _goToSearch(context),
|
||||||
|
|
|
@ -38,6 +38,7 @@ class _MultiEntryScrollerState extends State<MultiEntryScroller> with AutomaticK
|
||||||
return MagnifierGestureDetectorScope(
|
return MagnifierGestureDetectorScope(
|
||||||
axis: const [Axis.horizontal, Axis.vertical],
|
axis: const [Axis.horizontal, Axis.vertical],
|
||||||
child: PageView.builder(
|
child: PageView.builder(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('horizontal-pageview'),
|
key: const Key('horizontal-pageview'),
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
controller: pageController,
|
controller: pageController,
|
||||||
|
@ -81,6 +82,7 @@ class _MultiEntryScrollerState extends State<MultiEntryScroller> with AutomaticK
|
||||||
|
|
||||||
Widget _buildViewer(AvesEntry mainEntry, {AvesEntry? pageEntry}) {
|
Widget _buildViewer(AvesEntry mainEntry, {AvesEntry? pageEntry}) {
|
||||||
return EntryPageView(
|
return EntryPageView(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('imageview'),
|
key: const Key('imageview'),
|
||||||
mainEntry: mainEntry,
|
mainEntry: mainEntry,
|
||||||
pageEntry: pageEntry ?? mainEntry,
|
pageEntry: pageEntry ?? mainEntry,
|
||||||
|
|
|
@ -131,6 +131,7 @@ class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
child: PageView(
|
child: PageView(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('vertical-pageview'),
|
key: const Key('vertical-pageview'),
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
controller: widget.verticalPager,
|
controller: widget.verticalPager,
|
||||||
|
|
|
@ -22,6 +22,7 @@ class InfoAppBar extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SliverAppBar(
|
return SliverAppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('back-button'),
|
key: const Key('back-button'),
|
||||||
icon: const Icon(AIcons.goUp),
|
icon: const Icon(AIcons.goUp),
|
||||||
onPressed: onBackPressed,
|
onPressed: onBackPressed,
|
||||||
|
|
|
@ -109,6 +109,7 @@ class _WelcomePageState extends State<WelcomePage> {
|
||||||
text: context.l10n.welcomeCrashReportToggle,
|
text: context.l10n.welcomeCrashReportToggle,
|
||||||
),
|
),
|
||||||
LabeledCheckbox(
|
LabeledCheckbox(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('agree-checkbox'),
|
key: const Key('agree-checkbox'),
|
||||||
value: _hasAcceptedTerms,
|
value: _hasAcceptedTerms,
|
||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
|
@ -120,6 +121,7 @@ class _WelcomePageState extends State<WelcomePage> {
|
||||||
);
|
);
|
||||||
|
|
||||||
final button = ElevatedButton(
|
final button = ElevatedButton(
|
||||||
|
// key is expected by test driver
|
||||||
key: const Key('continue-button'),
|
key: const Key('continue-button'),
|
||||||
onPressed: _hasAcceptedTerms
|
onPressed: _hasAcceptedTerms
|
||||||
? () {
|
? () {
|
||||||
|
|
|
@ -129,10 +129,11 @@ void selectFirstAlbum() {
|
||||||
// wait for collection loading
|
// wait for collection loading
|
||||||
await driver.waitForCondition(const NoPendingPlatformMessages());
|
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(
|
await driver.tap(find.descendant(
|
||||||
of: find.byValueKey('filter-grid-page'),
|
of: find.byValueKey('filter-grid'),
|
||||||
matching: find.byType('CoveredFilterChip'),
|
matching: find.byType('MetaData'),
|
||||||
firstMatchOnly: true,
|
firstMatchOnly: true,
|
||||||
));
|
));
|
||||||
await driver.waitUntilNoTransientCallbacks();
|
await driver.waitUntilNoTransientCallbacks();
|
||||||
|
@ -158,9 +159,11 @@ void searchAlbum() {
|
||||||
|
|
||||||
void showViewer() {
|
void showViewer() {
|
||||||
test('[collection] show viewer', () async {
|
test('[collection] show viewer', () async {
|
||||||
|
// delay to avoid flaky descendant resolution
|
||||||
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
await driver.tap(find.descendant(
|
await driver.tap(find.descendant(
|
||||||
of: find.byValueKey('collection-grid'),
|
of: find.byValueKey('collection-grid'),
|
||||||
matching: find.byType('DecoratedThumbnail'),
|
matching: find.byType('MetaData'),
|
||||||
firstMatchOnly: true,
|
firstMatchOnly: true,
|
||||||
));
|
));
|
||||||
await driver.waitUntilNoTransientCallbacks();
|
await driver.waitUntilNoTransientCallbacks();
|
||||||
|
|
|
@ -3,10 +3,13 @@ import 'dart:io';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
String get adb {
|
String get adb {
|
||||||
final env = Platform.environment;
|
if (Platform.isWindows) {
|
||||||
// e.g. C:\Users\<username>\AppData\Local\Android\Sdk
|
final env = Platform.environment;
|
||||||
final sdkDir = env['ANDROID_SDK_ROOT'] ?? env['ANDROID_SDK']!;
|
// e.g. C:\Users\<username>\AppData\Local\Android\Sdk
|
||||||
return p.join(sdkDir, 'platform-tools', Platform.isWindows ? 'adb.exe' : 'adb');
|
final sdkDir = env['ANDROID_SDK_ROOT'] ?? env['ANDROID_SDK']!;
|
||||||
|
return p.join(sdkDir, 'platform-tools', 'adb.exe');
|
||||||
|
}
|
||||||
|
return 'adb';
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue