diff --git a/packages/neon/neon_dashboard/lib/l10n/en.arb b/packages/neon/neon_dashboard/lib/l10n/en.arb index d738d7d66c9..345f958f15d 100644 --- a/packages/neon/neon_dashboard/lib/l10n/en.arb +++ b/packages/neon/neon_dashboard/lib/l10n/en.arb @@ -9,5 +9,6 @@ } }, "locationSet": "Set location for weather", - "address": "Address" + "address": "Address", + "openWidget": "Open widget" } diff --git a/packages/neon/neon_dashboard/lib/l10n/localizations.dart b/packages/neon/neon_dashboard/lib/l10n/localizations.dart index 201ebe5b29d..deb5cdab3fa 100644 --- a/packages/neon/neon_dashboard/lib/l10n/localizations.dart +++ b/packages/neon/neon_dashboard/lib/l10n/localizations.dart @@ -118,6 +118,12 @@ abstract class DashboardLocalizations { /// In en, this message translates to: /// **'Address'** String get address; + + /// No description provided for @openWidget. + /// + /// In en, this message translates to: + /// **'Open widget'** + String get openWidget; } class _DashboardLocalizationsDelegate extends LocalizationsDelegate { diff --git a/packages/neon/neon_dashboard/lib/l10n/localizations_en.dart b/packages/neon/neon_dashboard/lib/l10n/localizations_en.dart index 1d29db41372..16bfcbf4f9a 100644 --- a/packages/neon/neon_dashboard/lib/l10n/localizations_en.dart +++ b/packages/neon/neon_dashboard/lib/l10n/localizations_en.dart @@ -39,4 +39,7 @@ class DashboardLocalizationsEn extends DashboardLocalizations { @override String get address => 'Address'; + + @override + String get openWidget => 'Open widget'; } diff --git a/packages/neon/neon_dashboard/lib/src/pages/main.dart b/packages/neon/neon_dashboard/lib/src/pages/main.dart index d0593ee3d2a..880ecafc7b3 100644 --- a/packages/neon/neon_dashboard/lib/src/pages/main.dart +++ b/packages/neon/neon_dashboard/lib/src/pages/main.dart @@ -327,7 +327,7 @@ class DashboardMainPage extends StatelessWidget { if (widget.buttons != null) { for (final button in widget.buttons!) { yield SizedBox( - height: 40, + height: 56, child: Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: DashboardWidgetButton( diff --git a/packages/neon/neon_dashboard/lib/src/widgets/widget.dart b/packages/neon/neon_dashboard/lib/src/widgets/widget.dart index 1760be0cf3f..1e1a79b1a8e 100644 --- a/packages/neon/neon_dashboard/lib/src/widgets/widget.dart +++ b/packages/neon/neon_dashboard/lib/src/widgets/widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:neon_dashboard/l10n/localizations.dart'; import 'package:nextcloud/dashboard.dart' as dashboard; /// Displays a single dashboard widget and its items. @@ -19,17 +20,26 @@ class DashboardWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Card( - child: InkWell( - onTap: widget.widgetUrl != null && widget.widgetUrl!.isNotEmpty ? () => context.go(widget.widgetUrl!) : null, - borderRadius: const BorderRadius.all(Radius.circular(12)), - child: Padding( - padding: const EdgeInsets.all(8), - child: Column( - children: children, - ), - ), + Widget child = Padding( + padding: const EdgeInsets.all(8), + child: Column( + children: children, ), ); + + if (widget.widgetUrl != null && widget.widgetUrl!.isNotEmpty) { + child = Tooltip( + message: DashboardLocalizations.of(context).openWidget, + child: InkWell( + onTap: () => context.go(widget.widgetUrl!), + borderRadius: const BorderRadius.all(Radius.circular(12)), + child: child, + ), + ); + } + + return Card( + child: child, + ); } } diff --git a/packages/neon/neon_dashboard/test/goldens/widget.png b/packages/neon/neon_dashboard/test/goldens/widget.png index 48af34e4068..73919801d70 100644 Binary files a/packages/neon/neon_dashboard/test/goldens/widget.png and b/packages/neon/neon_dashboard/test/goldens/widget.png differ diff --git a/packages/neon/neon_dashboard/test/goldens/widget_not_round.png b/packages/neon/neon_dashboard/test/goldens/widget_not_round.png index fa4304d3cbd..06bc6591aff 100644 Binary files a/packages/neon/neon_dashboard/test/goldens/widget_not_round.png and b/packages/neon/neon_dashboard/test/goldens/widget_not_round.png differ diff --git a/packages/neon/neon_dashboard/test/goldens/widget_with_empty.png b/packages/neon/neon_dashboard/test/goldens/widget_with_empty.png index 4054251bd84..3f269d1e860 100644 Binary files a/packages/neon/neon_dashboard/test/goldens/widget_with_empty.png and b/packages/neon/neon_dashboard/test/goldens/widget_with_empty.png differ diff --git a/packages/neon/neon_dashboard/test/goldens/widget_with_empty_and_half_empty.png b/packages/neon/neon_dashboard/test/goldens/widget_with_empty_and_half_empty.png index 4054251bd84..3f269d1e860 100644 Binary files a/packages/neon/neon_dashboard/test/goldens/widget_with_empty_and_half_empty.png and b/packages/neon/neon_dashboard/test/goldens/widget_with_empty_and_half_empty.png differ diff --git a/packages/neon/neon_dashboard/test/goldens/widget_with_half_empty.png b/packages/neon/neon_dashboard/test/goldens/widget_with_half_empty.png index b8977f92d2a..37a5ab0cda6 100644 Binary files a/packages/neon/neon_dashboard/test/goldens/widget_with_half_empty.png and b/packages/neon/neon_dashboard/test/goldens/widget_with_half_empty.png differ diff --git a/packages/neon/neon_dashboard/test/goldens/widget_with_multiple_buttons.png b/packages/neon/neon_dashboard/test/goldens/widget_with_multiple_buttons.png index 05efb3fe79d..6fd2c6da101 100644 Binary files a/packages/neon/neon_dashboard/test/goldens/widget_with_multiple_buttons.png and b/packages/neon/neon_dashboard/test/goldens/widget_with_multiple_buttons.png differ diff --git a/packages/neon/neon_dashboard/test/goldens/widget_without_items.png b/packages/neon/neon_dashboard/test/goldens/widget_without_items.png index 61e1a5481b0..14b24fc1200 100644 Binary files a/packages/neon/neon_dashboard/test/goldens/widget_without_items.png and b/packages/neon/neon_dashboard/test/goldens/widget_without_items.png differ diff --git a/packages/neon/neon_dashboard/test/set_weather_location_dialog_test.dart b/packages/neon/neon_dashboard/test/set_weather_location_dialog_test.dart index 20fc8b89029..7ae6ccbe13d 100644 --- a/packages/neon/neon_dashboard/test/set_weather_location_dialog_test.dart +++ b/packages/neon/neon_dashboard/test/set_weather_location_dialog_test.dart @@ -6,7 +6,7 @@ import 'package:neon_framework/testing.dart'; void main() { testWidgets('Set weather location dialog', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( const TestApp( localizationsDelegates: DashboardLocalizations.localizationsDelegates, supportedLocales: DashboardLocalizations.supportedLocales, diff --git a/packages/neon/neon_dashboard/test/widget_test.dart b/packages/neon/neon_dashboard/test/widget_test.dart index 565e69f13b6..3b2c78a671e 100644 --- a/packages/neon/neon_dashboard/test/widget_test.dart +++ b/packages/neon/neon_dashboard/test/widget_test.dart @@ -59,7 +59,7 @@ void main() { testWidgets('Everything filled', (tester) async { final router = MockGoRouter(); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetItem( @@ -99,7 +99,7 @@ void main() { }); testWidgets('Not round', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetItem( @@ -122,7 +122,7 @@ void main() { }); testWidgets('Without link', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetItem( @@ -143,7 +143,7 @@ void main() { }); testWidgets('Without overlayIconUrl', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetItem( @@ -157,7 +157,7 @@ void main() { }); testWidgets('Without iconUrl', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetItem( @@ -183,7 +183,7 @@ void main() { testWidgets('Opens link', (tester) async { final router = MockGoRouter(); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetButton( @@ -198,7 +198,7 @@ void main() { }); testWidgets('New', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetButton( @@ -214,7 +214,7 @@ void main() { }); testWidgets('More', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetButton( @@ -230,7 +230,7 @@ void main() { }); testWidgets('Setup', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetButton( @@ -246,7 +246,7 @@ void main() { }); testWidgets('Invalid', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, DashboardWidgetButton( @@ -299,7 +299,7 @@ void main() { ); testWidgets('Everything filled', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, Builder( @@ -345,7 +345,7 @@ void main() { testWidgets('Without widgetUrl', (tester) async { final widgetEmptyURL = widget.rebuild((b) => b.widgetUrl = ''); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, Builder( @@ -373,7 +373,7 @@ void main() { testWidgets('Not round', (tester) async { final widgetNotRound = widget.rebuild((b) => b.itemIconsRound = false); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, Builder( @@ -402,7 +402,7 @@ void main() { }); testWidgets('With halfEmptyContentMessage', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, Builder( @@ -425,7 +425,7 @@ void main() { }); testWidgets('With emptyContentMessage', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, Builder( @@ -448,7 +448,7 @@ void main() { }); testWidgets('With emptyContentMessage and halfEmptyContentMessage', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, Builder( @@ -479,7 +479,7 @@ void main() { }); testWidgets('Without items', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, Builder( @@ -503,7 +503,7 @@ void main() { testWidgets('Without buttons', (tester) async { final widgetWithoutButtons = widget.rebuild((b) => b.buttons.clear()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, Builder( @@ -528,7 +528,7 @@ void main() { final widgetWithMultipleButtons = widget.rebuild( (b) => b.buttons.replace([button, button]), ); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, Builder( diff --git a/packages/neon/neon_notifications/test/action_test.dart b/packages/neon/neon_notifications/test/action_test.dart index daefbe59390..7f33ec0e61f 100644 --- a/packages/neon/neon_notifications/test/action_test.dart +++ b/packages/neon/neon_notifications/test/action_test.dart @@ -11,7 +11,7 @@ void main() { when(() => action.label).thenReturn('label'); when(() => action.primary).thenReturn(true); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: NotificationsAction( action: action, @@ -27,7 +27,7 @@ void main() { when(() => action.label).thenReturn('label'); when(() => action.primary).thenReturn(false); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: NotificationsAction( action: action, @@ -46,7 +46,7 @@ void main() { when(() => action.primary).thenReturn(true); when(() => action.link).thenReturn('/link'); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( router: router, child: NotificationsAction( diff --git a/packages/neon/neon_notifications/test/main_page_test.dart b/packages/neon/neon_notifications/test/main_page_test.dart index 71151ffc169..5d3275b7ca8 100644 --- a/packages/neon/neon_notifications/test/main_page_test.dart +++ b/packages/neon/neon_notifications/test/main_page_test.dart @@ -46,7 +46,7 @@ void main() { final controller = StreamController(); when(() => bloc.errors).thenAnswer((_) => controller.stream); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: NotificationsLocalizations.localizationsDelegates, supportedLocales: NotificationsLocalizations.supportedLocales, @@ -69,7 +69,7 @@ void main() { }); testWidgets('Without notifications', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: NotificationsLocalizations.localizationsDelegates, supportedLocales: NotificationsLocalizations.supportedLocales, @@ -113,7 +113,7 @@ void main() { ), ); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: NotificationsLocalizations.localizationsDelegates, supportedLocales: NotificationsLocalizations.supportedLocales, diff --git a/packages/neon/neon_notifications/test/notification_test.dart b/packages/neon/neon_notifications/test/notification_test.dart index a1fac5023c5..29982e4088e 100644 --- a/packages/neon/neon_notifications/test/notification_test.dart +++ b/packages/neon/neon_notifications/test/notification_test.dart @@ -57,7 +57,7 @@ void main() { }); testWidgets('Without matching app', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: NotificationsLocalizations.localizationsDelegates, supportedLocales: NotificationsLocalizations.supportedLocales, @@ -100,7 +100,7 @@ void main() { when(() => app.id).thenReturn('app'); when(() => app.buildIcon(size: any(named: 'size'))).thenReturn(const SizedBox()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: NotificationsLocalizations.localizationsDelegates, supportedLocales: NotificationsLocalizations.supportedLocales, diff --git a/packages/neon/neon_talk/lib/l10n/en.arb b/packages/neon/neon_talk/lib/l10n/en.arb index 36a866b7256..b4d9b1d04d1 100644 --- a/packages/neon/neon_talk/lib/l10n/en.arb +++ b/packages/neon/neon_talk/lib/l10n/en.arb @@ -12,5 +12,10 @@ "type": {} } }, - "roomSendMessage": "Send a message..." + "roomSendMessage": "Send a message...", + "roomMessageAddEmoji": "Add emoji to message", + "roomMessageSend": "Send message", + "reactionsAddNew": "Add a new reaction", + "reactionsLoading": "Loading reactions", + "roomsCreateNew": "Create new room" } diff --git a/packages/neon/neon_talk/lib/l10n/localizations.dart b/packages/neon/neon_talk/lib/l10n/localizations.dart index 99c00f4b642..ec3bb545eb6 100644 --- a/packages/neon/neon_talk/lib/l10n/localizations.dart +++ b/packages/neon/neon_talk/lib/l10n/localizations.dart @@ -136,6 +136,36 @@ abstract class TalkLocalizations { /// In en, this message translates to: /// **'Send a message...'** String get roomSendMessage; + + /// No description provided for @roomMessageAddEmoji. + /// + /// In en, this message translates to: + /// **'Add emoji to message'** + String get roomMessageAddEmoji; + + /// No description provided for @roomMessageSend. + /// + /// In en, this message translates to: + /// **'Send message'** + String get roomMessageSend; + + /// No description provided for @reactionsAddNew. + /// + /// In en, this message translates to: + /// **'Add a new reaction'** + String get reactionsAddNew; + + /// No description provided for @reactionsLoading. + /// + /// In en, this message translates to: + /// **'Loading reactions'** + String get reactionsLoading; + + /// No description provided for @roomsCreateNew. + /// + /// In en, this message translates to: + /// **'Create new room'** + String get roomsCreateNew; } class _TalkLocalizationsDelegate extends LocalizationsDelegate { diff --git a/packages/neon/neon_talk/lib/l10n/localizations_en.dart b/packages/neon/neon_talk/lib/l10n/localizations_en.dart index 7e6f167d7e2..59df8ff4039 100644 --- a/packages/neon/neon_talk/lib/l10n/localizations_en.dart +++ b/packages/neon/neon_talk/lib/l10n/localizations_en.dart @@ -40,4 +40,19 @@ class TalkLocalizationsEn extends TalkLocalizations { @override String get roomSendMessage => 'Send a message...'; + + @override + String get roomMessageAddEmoji => 'Add emoji to message'; + + @override + String get roomMessageSend => 'Send message'; + + @override + String get reactionsAddNew => 'Add a new reaction'; + + @override + String get reactionsLoading => 'Loading reactions'; + + @override + String get roomsCreateNew => 'Create new room'; } diff --git a/packages/neon/neon_talk/lib/src/pages/main.dart b/packages/neon/neon_talk/lib/src/pages/main.dart index a5af68c1520..788e99eb7fd 100644 --- a/packages/neon/neon_talk/lib/src/pages/main.dart +++ b/packages/neon/neon_talk/lib/src/pages/main.dart @@ -5,6 +5,7 @@ import 'package:neon_framework/blocs.dart'; import 'package:neon_framework/models.dart'; import 'package:neon_framework/utils.dart'; import 'package:neon_framework/widgets.dart'; +import 'package:neon_talk/l10n/localizations.dart'; import 'package:neon_talk/src/blocs/room.dart'; import 'package:neon_talk/src/blocs/talk.dart'; import 'package:neon_talk/src/dialogs/create_room.dart'; @@ -63,7 +64,7 @@ class _TalkMainPageState extends State { ), ), floatingActionButton: FloatingActionButton( - child: const Icon(Icons.add), + tooltip: TalkLocalizations.of(context).roomsCreateNew, onPressed: () async { final result = await showDialog( context: context, @@ -79,6 +80,7 @@ class _TalkMainPageState extends State { result.invite, ); }, + child: const Icon(Icons.add), ), ); } diff --git a/packages/neon/neon_talk/lib/src/pages/room.dart b/packages/neon/neon_talk/lib/src/pages/room.dart index 737f55eb499..06c72f528d1 100644 --- a/packages/neon/neon_talk/lib/src/pages/room.dart +++ b/packages/neon/neon_talk/lib/src/pages/room.dart @@ -160,6 +160,7 @@ class _TalkRoomPageState extends State { // On cupertino the keyboard always has an option to insert emojis, so we don't need to add it if (!isCupertino(context)) { emojiButton = IconButton( + tooltip: TalkLocalizations.of(context).roomMessageAddEmoji, onPressed: () async { final emoji = await showDialog( context: context, @@ -202,6 +203,7 @@ class _TalkRoomPageState extends State { decoration: InputDecoration( prefixIcon: emojiButton, suffixIcon: IconButton( + tooltip: TalkLocalizations.of(context).roomMessageSend, icon: Icon(AdaptiveIcons.send), onPressed: sendMessage, ), diff --git a/packages/neon/neon_talk/lib/src/widgets/reactions.dart b/packages/neon/neon_talk/lib/src/widgets/reactions.dart index 87d1939f989..79a7035b688 100644 --- a/packages/neon/neon_talk/lib/src/widgets/reactions.dart +++ b/packages/neon/neon_talk/lib/src/widgets/reactions.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:intersperse/intersperse.dart'; import 'package:neon_framework/utils.dart'; import 'package:neon_framework/widgets.dart'; +import 'package:neon_talk/l10n/localizations.dart'; import 'package:neon_talk/src/blocs/room.dart'; import 'package:nextcloud/spreed.dart' as spreed; @@ -49,7 +50,8 @@ class TalkReactions extends StatelessWidget { fontFamily: 'monospace', ), ), - tooltip: reactions?[reaction.key]?.map((r) => r.actorDisplayName).join(', '), + tooltip: reactions?[reaction.key]?.map((r) => r.actorDisplayName).join(', ') ?? + TalkLocalizations.of(context).reactionsLoading, padding: EdgeInsets.zero, labelPadding: const EdgeInsets.only( top: -2.5, @@ -78,6 +80,7 @@ class TalkReactions extends StatelessWidget { label: const SizedBox(), padding: EdgeInsets.zero, labelPadding: const EdgeInsets.symmetric(vertical: -2.5), + tooltip: TalkLocalizations.of(context).reactionsAddNew, onPressed: () async { final reaction = await showDialog( context: context, diff --git a/packages/neon/neon_talk/test/actor_avatar_test.dart b/packages/neon/neon_talk/test/actor_avatar_test.dart index b24499dfd51..ff7d7e1f7b2 100644 --- a/packages/neon/neon_talk/test/actor_avatar_test.dart +++ b/packages/neon/neon_talk/test/actor_avatar_test.dart @@ -27,7 +27,7 @@ void main() { final accountsBloc = MockAccountsBloc(); when(() => accountsBloc.activeAccount).thenAnswer((_) => BehaviorSubject.seeded(account)); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), diff --git a/packages/neon/neon_talk/test/create_room_dialog_test.dart b/packages/neon/neon_talk/test/create_room_dialog_test.dart index 1c573c2b8f9..7cb7521cdb8 100644 --- a/packages/neon/neon_talk/test/create_room_dialog_test.dart +++ b/packages/neon/neon_talk/test/create_room_dialog_test.dart @@ -105,7 +105,7 @@ void main() { when(() => accountsBloc.activeAccount).thenAnswer((_) => BehaviorSubject.seeded(account)); when(() => accountsBloc.getUserStatusBlocFor(account)).thenReturn(userStatusBloc); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( NeonProvider.value( value: accountsBloc, child: const TestApp( @@ -160,7 +160,7 @@ void main() { final accountsBloc = MockAccountsBloc(); when(() => accountsBloc.activeAccount).thenAnswer((_) => BehaviorSubject.seeded(account)); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( NeonProvider.value( value: accountsBloc, child: const TestApp( diff --git a/packages/neon/neon_talk/test/goldens/rich_object_mention_user_other.png b/packages/neon/neon_talk/test/goldens/rich_object_mention_user_other.png index 6536199e445..06a5973c91e 100644 Binary files a/packages/neon/neon_talk/test/goldens/rich_object_mention_user_other.png and b/packages/neon/neon_talk/test/goldens/rich_object_mention_user_other.png differ diff --git a/packages/neon/neon_talk/test/main_page_test.dart b/packages/neon/neon_talk/test/main_page_test.dart index c9e6193f315..aec58246d89 100644 --- a/packages/neon/neon_talk/test/main_page_test.dart +++ b/packages/neon/neon_talk/test/main_page_test.dart @@ -60,7 +60,7 @@ void main() { final controller = StreamController(); when(() => bloc.errors).thenAnswer((_) => controller.stream); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -84,8 +84,10 @@ void main() { when(() => room.lastMessage).thenReturn((baseMessage: null, builtListNever: null, chatMessage: null)); when(() => room.unreadMessages).thenReturn(0); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( + localizationsDelegates: TalkLocalizations.localizationsDelegates, + supportedLocales: TalkLocalizations.supportedLocales, providers: [ NeonProvider.value(value: accountsBloc), NeonProvider.value(value: bloc), @@ -109,7 +111,7 @@ void main() { when(() => room.lastMessage).thenReturn((baseMessage: null, builtListNever: null, chatMessage: chatMessage)); when(() => room.unreadMessages).thenReturn(1); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -143,7 +145,7 @@ void main() { when(() => room.unreadMessages).thenReturn(0); when(() => room.lastCommonReadMessage).thenReturn(0); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -176,7 +178,7 @@ void main() { when(() => room.unreadMessages).thenReturn(0); when(() => room.lastCommonReadMessage).thenReturn(0); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -203,7 +205,7 @@ void main() { when(() => room.lastMessage).thenReturn((baseMessage: null, builtListNever: null, chatMessage: null)); when(() => room.unreadMessages).thenReturn(0); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, diff --git a/packages/neon/neon_talk/test/message_test.dart b/packages/neon/neon_talk/test/message_test.dart index 6d907b341bb..c6ec840f2c6 100644 --- a/packages/neon/neon_talk/test/message_test.dart +++ b/packages/neon/neon_talk/test/message_test.dart @@ -57,7 +57,7 @@ void main() { when(() => chatMessage.messageType).thenReturn(spreed.MessageType.comment); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -79,7 +79,7 @@ void main() { when(() => chatMessage.messageType).thenReturn(spreed.MessageType.comment); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -100,7 +100,7 @@ void main() { when(() => chatMessage.messageType).thenReturn(spreed.MessageType.comment); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -121,7 +121,7 @@ void main() { when(() => chatMessage.messageType).thenReturn(spreed.MessageType.comment); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -142,7 +142,7 @@ void main() { when(() => chatMessage.messageType).thenReturn(spreed.MessageType.system); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -163,7 +163,7 @@ void main() { when(() => chatMessage.messageType).thenReturn(spreed.MessageType.comment); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -186,7 +186,7 @@ void main() { when(() => chatMessage.message).thenReturn(''); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -220,7 +220,7 @@ void main() { final roomBloc = MockRoomBloc(); when(() => roomBloc.reactions).thenAnswer((_) => BehaviorSubject.seeded(BuiltMap())); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -243,7 +243,7 @@ void main() { final chatMessage = MockChatMessage(); when(() => chatMessage.systemMessage).thenReturn('reaction'); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -264,7 +264,7 @@ void main() { when(() => chatMessage.message).thenReturn('test'); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -288,7 +288,7 @@ void main() { when(() => chatMessage.message).thenReturn('test'); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -325,7 +325,7 @@ void main() { when(() => chatMessage.reactions).thenReturn(BuiltMap()); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -343,7 +343,7 @@ void main() { }); group('TalkCommentMessage', () { - testWidgets('Default', (tester) async { + testWidgets('Self', (tester) async { final account = MockAccount(); when(() => account.id).thenReturn(''); when(() => account.username).thenReturn('test'); @@ -371,7 +371,7 @@ void main() { final roomBloc = MockRoomBloc(); when(() => roomBloc.reactions).thenAnswer((_) => BehaviorSubject.seeded(BuiltMap())); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -398,7 +398,7 @@ void main() { ); }); - testWidgets('Default', (tester) async { + testWidgets('Other', (tester) async { final account = MockAccount(); when(() => account.id).thenReturn(''); when(() => account.username).thenReturn('other'); @@ -426,7 +426,7 @@ void main() { final roomBloc = MockRoomBloc(); when(() => roomBloc.reactions).thenAnswer((_) => BehaviorSubject.seeded(BuiltMap())); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -476,7 +476,7 @@ void main() { when(() => chatMessage.reactions).thenReturn(BuiltMap()); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -515,7 +515,7 @@ void main() { when(() => chatMessage.message).thenReturn('abc'); when(() => chatMessage.messageParameters).thenReturn(BuiltMap()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -575,7 +575,7 @@ void main() { final roomBloc = MockRoomBloc(); when(() => roomBloc.reactions).thenAnswer((_) => BehaviorSubject.seeded(BuiltMap())); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -625,7 +625,7 @@ void main() { final roomBloc = MockRoomBloc(); when(() => roomBloc.reactions).thenAnswer((_) => BehaviorSubject.seeded(BuiltMap())); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -677,7 +677,7 @@ void main() { final roomBloc = MockRoomBloc(); when(() => roomBloc.reactions).thenAnswer((_) => BehaviorSubject.seeded(BuiltMap())); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -729,7 +729,7 @@ void main() { final roomBloc = MockRoomBloc(); when(() => roomBloc.reactions).thenAnswer((_) => BehaviorSubject.seeded(BuiltMap())); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -778,7 +778,7 @@ void main() { when(() => accountsBloc.activeAccount).thenAnswer((_) => BehaviorSubject.seeded(account)); when(() => accountsBloc.activeUserDetailsBloc).thenReturn(userDetailsBloc); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), @@ -806,7 +806,7 @@ void main() { }); testWidgets('File', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: RichText( text: buildRichObjectParameter( @@ -828,7 +828,7 @@ void main() { }); testWidgets('Deck card', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: RichText( text: buildRichObjectParameter( @@ -852,7 +852,7 @@ void main() { }); testWidgets('Fallback', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: RichText( text: buildRichObjectParameter( diff --git a/packages/neon/neon_talk/test/reactions_test.dart b/packages/neon/neon_talk/test/reactions_test.dart index 697c22f9394..231eb515a34 100644 --- a/packages/neon/neon_talk/test/reactions_test.dart +++ b/packages/neon/neon_talk/test/reactions_test.dart @@ -5,6 +5,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:neon_framework/testing.dart'; import 'package:neon_framework/utils.dart'; +import 'package:neon_talk/l10n/localizations.dart'; import 'package:neon_talk/src/blocs/room.dart'; import 'package:neon_talk/src/widgets/reactions.dart'; import 'package:nextcloud/spreed.dart' as spreed; @@ -44,8 +45,10 @@ void main() { }); testWidgets('Reactions', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( + localizationsDelegates: TalkLocalizations.localizationsDelegates, + supportedLocales: TalkLocalizations.supportedLocales, providers: [ NeonProvider.value(value: bloc), ], @@ -62,8 +65,10 @@ void main() { }); testWidgets('Add reaction', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( + localizationsDelegates: TalkLocalizations.localizationsDelegates, + supportedLocales: TalkLocalizations.supportedLocales, providers: [ NeonProvider.value(value: bloc), ], @@ -79,8 +84,10 @@ void main() { }); testWidgets('Remove reaction', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( + localizationsDelegates: TalkLocalizations.localizationsDelegates, + supportedLocales: TalkLocalizations.supportedLocales, providers: [ NeonProvider.value(value: bloc), ], @@ -98,8 +105,10 @@ void main() { testWidgets('Add new reaction', (tester) async { SharedPreferences.setMockInitialValues({}); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( + localizationsDelegates: TalkLocalizations.localizationsDelegates, + supportedLocales: TalkLocalizations.supportedLocales, providers: [ NeonProvider.value(value: bloc), ], @@ -122,8 +131,10 @@ void main() { }); testWidgets('Load reactions on hover', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( + localizationsDelegates: TalkLocalizations.localizationsDelegates, + supportedLocales: TalkLocalizations.supportedLocales, providers: [ NeonProvider.value(value: bloc), ], diff --git a/packages/neon/neon_talk/test/read_indicator_test.dart b/packages/neon/neon_talk/test/read_indicator_test.dart index fa27e6ed9c9..2354cd22979 100644 --- a/packages/neon/neon_talk/test/read_indicator_test.dart +++ b/packages/neon/neon_talk/test/read_indicator_test.dart @@ -11,7 +11,7 @@ void main() { final chatMessage = MockChatMessage(); when(() => chatMessage.id).thenReturn(1); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: TalkReadIndicator( chatMessage: chatMessage, @@ -26,7 +26,7 @@ void main() { final chatMessage = MockChatMessage(); when(() => chatMessage.id).thenReturn(1); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: TalkReadIndicator( chatMessage: chatMessage, diff --git a/packages/neon/neon_talk/test/rich_object_test.dart b/packages/neon/neon_talk/test/rich_object_test.dart index 03954187aaa..8a3fe903cba 100644 --- a/packages/neon/neon_talk/test/rich_object_test.dart +++ b/packages/neon/neon_talk/test/rich_object_test.dart @@ -46,7 +46,7 @@ void main() { testWidgets('Deck card', (tester) async { final router = MockGoRouter(); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( router: router, child: TalkRichObjectDeckCard( @@ -74,56 +74,60 @@ void main() { }); group('Mention', () { - testWidgets('user', (tester) async { - await tester.pumpWidget( - TestApp( - providers: [ - NeonProvider.value(value: accountsBloc), - ], - child: TalkRichObjectMention( - parameter: spreed.RichObjectParameter( - (b) => b - ..type = 'user' - ..id = 'username' - ..name = 'name', + group('user', () { + testWidgets('Self', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + NeonProvider.value(value: accountsBloc), + ], + child: TalkRichObjectMention( + parameter: spreed.RichObjectParameter( + (b) => b + ..type = 'user' + ..id = 'username' + ..name = 'name', + ), + textStyle: null, ), - textStyle: null, ), - ), - ); - expect(find.byType(NeonUserAvatar), findsOne); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(TalkRichObjectMention), - matchesGoldenFile('goldens/rich_object_mention_user_highlight.png'), - ); + ); + expect(find.byType(NeonUserAvatar), findsOne); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(TalkRichObjectMention), + matchesGoldenFile('goldens/rich_object_mention_user_highlight.png'), + ); + }); - await tester.pumpWidget( - TestApp( - providers: [ - NeonProvider.value(value: accountsBloc), - ], - child: TalkRichObjectMention( - parameter: spreed.RichObjectParameter( - (b) => b - ..type = 'user' - ..id = 'other' - ..name = 'name', + testWidgets('Other', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + NeonProvider.value(value: accountsBloc), + ], + child: TalkRichObjectMention( + parameter: spreed.RichObjectParameter( + (b) => b + ..type = 'user' + ..id = 'other' + ..name = 'name', + ), + textStyle: null, ), - textStyle: null, ), - ), - ); - expect(find.byType(NeonUserAvatar), findsOne); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(TalkRichObjectMention), - matchesGoldenFile('goldens/rich_object_mention_user_other.png'), - ); + ); + expect(find.byType(NeonUserAvatar), findsOne); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(TalkRichObjectMention), + matchesGoldenFile('goldens/rich_object_mention_user_other.png'), + ); + }); }); testWidgets('call', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), @@ -149,7 +153,7 @@ void main() { }); testWidgets('guest', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: TalkRichObjectMention( parameter: spreed.RichObjectParameter( @@ -180,7 +184,7 @@ void main() { when(() => accountsBloc.activeUserDetailsBloc).thenReturn(userDetailsBloc); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), @@ -203,7 +207,7 @@ void main() { matchesGoldenFile('goldens/rich_object_mention_${type}_highlight.png'), ); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), @@ -233,7 +237,7 @@ void main() { testWidgets('Opens link', (tester) async { final router = MockGoRouter(); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( router: router, child: TalkRichObjectFile( @@ -256,7 +260,7 @@ void main() { }); testWidgets('With preview', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), @@ -278,7 +282,7 @@ void main() { }); testWidgets('Without preview', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: TalkRichObjectFile( parameter: spreed.RichObjectParameter( @@ -304,7 +308,7 @@ void main() { group('File preview', () { testWidgets('Without dimensions', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), @@ -339,7 +343,7 @@ void main() { testWidgets('With dimensions', (tester) async { // Default device pixel ratio for tests is 3, so we don't need to set it manually to ensure the calculations are right. - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), @@ -376,7 +380,7 @@ void main() { testWidgets('With dimensions too big', (tester) async { // Default device pixel ratio for tests is 3, so we don't need to set it manually to ensure the calculations are right. - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), @@ -415,7 +419,7 @@ void main() { testWidgets('Opens link', (tester) async { final router = MockGoRouter(); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( router: router, child: TalkRichObjectFallback( @@ -436,7 +440,7 @@ void main() { }); testWidgets('Without icon', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: TalkRichObjectFallback( parameter: spreed.RichObjectParameter( @@ -458,7 +462,7 @@ void main() { }); testWidgets('With icon', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), diff --git a/packages/neon/neon_talk/test/room_avatar_test.dart b/packages/neon/neon_talk/test/room_avatar_test.dart index 81349512a32..ebac4296130 100644 --- a/packages/neon/neon_talk/test/room_avatar_test.dart +++ b/packages/neon/neon_talk/test/room_avatar_test.dart @@ -39,7 +39,7 @@ void main() { when(() => room.token).thenReturn('abc123'); when(() => room.avatarVersion).thenReturn(''); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, TalkRoomAvatar( @@ -67,7 +67,7 @@ void main() { when(() => room.type).thenReturn(spreed.RoomType.oneToOne.value); when(() => room.name).thenReturn(''); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, TalkRoomAvatar( @@ -88,7 +88,7 @@ void main() { when(() => room.isCustomAvatar).thenReturn(false); when(() => room.type).thenReturn(spreed.RoomType.group.value); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( wrapWidget( accountsBloc, TalkRoomAvatar( diff --git a/packages/neon/neon_talk/test/room_page_test.dart b/packages/neon/neon_talk/test/room_page_test.dart index 3a95c123205..70f45844ac3 100644 --- a/packages/neon/neon_talk/test/room_page_test.dart +++ b/packages/neon/neon_talk/test/room_page_test.dart @@ -47,7 +47,7 @@ void main() { testWidgets('Status message', (tester) async { when(() => room.statusMessage).thenReturn('status'); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -68,7 +68,7 @@ void main() { final controller = StreamController(); when(() => bloc.errors).thenAnswer((_) => controller.stream); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -146,7 +146,7 @@ void main() { final accountsBloc = MockAccountsBloc(); when(() => accountsBloc.activeAccount).thenAnswer((_) => BehaviorSubject.seeded(account)); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -169,7 +169,7 @@ void main() { testWidgets('Read-only', (tester) async { when(() => room.readOnly).thenReturn(1); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -186,7 +186,7 @@ void main() { }); testWidgets('Cupertino no emoji button', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, @@ -209,7 +209,7 @@ void main() { testWidgets('Emoji button', (tester) async { SharedPreferences.setMockInitialValues({}); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( localizationsDelegates: TalkLocalizations.localizationsDelegates, supportedLocales: TalkLocalizations.supportedLocales, diff --git a/packages/neon/neon_talk/test/unread_indicator_test.dart b/packages/neon/neon_talk/test/unread_indicator_test.dart index 3429d9f7f43..37d97eb2397 100644 --- a/packages/neon/neon_talk/test/unread_indicator_test.dart +++ b/packages/neon/neon_talk/test/unread_indicator_test.dart @@ -14,7 +14,7 @@ void main() { when(() => room.unreadMentionDirect).thenReturn(false); when(() => room.type).thenReturn(spreed.RoomType.group.value); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: TalkUnreadIndicator( room: room, @@ -34,7 +34,7 @@ void main() { when(() => room.unreadMentionDirect).thenReturn(false); when(() => room.type).thenReturn(spreed.RoomType.oneToOne.value); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: TalkUnreadIndicator( room: room, @@ -54,7 +54,7 @@ void main() { when(() => room.unreadMentionDirect).thenReturn(false); when(() => room.type).thenReturn(spreed.RoomType.group.value); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: TalkUnreadIndicator( room: room, @@ -73,7 +73,7 @@ void main() { when(() => room.unreadMention).thenReturn(true); when(() => room.unreadMentionDirect).thenReturn(true); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: TalkUnreadIndicator( room: room, diff --git a/packages/neon_framework/lib/src/testing/utils.dart b/packages/neon_framework/lib/src/testing/utils.dart index 1b6ab6e88be..2237139b6ab 100644 --- a/packages/neon_framework/lib/src/testing/utils.dart +++ b/packages/neon_framework/lib/src/testing/utils.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +// ignore: depend_on_referenced_packages +import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:neon_framework/src/theme/theme.dart'; import 'package:neon_framework/testing.dart'; @@ -106,3 +108,21 @@ class TestApp extends StatelessWidget { return app; } } + +/// Extension for pumping widgets with automatic accessibility guideline checks. +extension TesterPumpWidgetWithAccessibility on WidgetTester { + /// Pumps the [widget] like [pumpWidget], but performs automatic accessibility guideline checks. + Future pumpWidgetWithAccessibility(Widget widget) async { + final handle = ensureSemantics(); + + // ignore: prefer_pump_widget_with_accessibility + await pumpWidget(widget); + + await expectLater(this, meetsGuideline(androidTapTargetGuideline)); + await expectLater(this, meetsGuideline(iOSTapTargetGuideline)); + await expectLater(this, meetsGuideline(labeledTapTargetGuideline)); + await expectLater(this, meetsGuideline(textContrastGuideline)); + + handle.dispose(); + } +} diff --git a/packages/neon_framework/lib/src/widgets/dialog.dart b/packages/neon_framework/lib/src/widgets/dialog.dart index c097070de18..ac8d10f15af 100644 --- a/packages/neon_framework/lib/src/widgets/dialog.dart +++ b/packages/neon_framework/lib/src/widgets/dialog.dart @@ -202,6 +202,9 @@ class NeonDialog extends StatelessWidget { child: Text( NeonLocalizations.of(context).actionCancel, textAlign: TextAlign.end, + style: TextStyle( + color: Theme.of(context).colorScheme.onSurface, + ), ), ), ...?actions, diff --git a/packages/neon_framework/lib/src/widgets/validation_tile.dart b/packages/neon_framework/lib/src/widgets/validation_tile.dart index 0696b374d01..6a6c97aabfa 100644 --- a/packages/neon_framework/lib/src/widgets/validation_tile.dart +++ b/packages/neon_framework/lib/src/widgets/validation_tile.dart @@ -41,7 +41,7 @@ class NeonValidationTile extends StatelessWidget { ), ValidationState.canceled => Icon( AdaptiveIcons.cancel_outlined, - color: Theme.of(context).disabledColor, + color: Theme.of(context).colorScheme.primary, size: size, ), ValidationState.success => Icon( @@ -52,10 +52,7 @@ class NeonValidationTile extends StatelessWidget { }; return AdaptiveListTile( leading: leading, - title: Text( - title, - style: state == ValidationState.canceled ? TextStyle(color: Theme.of(context).disabledColor) : null, - ), + title: Text(title), ); } } diff --git a/packages/neon_framework/test/autocomplete_test.dart b/packages/neon_framework/test/autocomplete_test.dart index 7b1c1583799..d99a3d91ebc 100644 --- a/packages/neon_framework/test/autocomplete_test.dart +++ b/packages/neon_framework/test/autocomplete_test.dart @@ -69,7 +69,7 @@ void main() { testWidgets('Autocomplete', (tester) async { final callback = MockOnSelectedCallbackFunction(); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: Builder( builder: (context) => NeonAutocomplete.withAccount( diff --git a/packages/neon_framework/test/dialog_test.dart b/packages/neon_framework/test/dialog_test.dart index 032515c5677..44cda272a00 100644 --- a/packages/neon_framework/test/dialog_test.dart +++ b/packages/neon_framework/test/dialog_test.dart @@ -17,10 +17,10 @@ import 'package:timezone/timezone.dart' as tz; void main() { group('dialog', () { group('NeonConfirmationDialog', () { - testWidgets('NeonConfirmationDialog widget', (widgetTester) async { + testWidgets('NeonConfirmationDialog widget', (tester) async { const title = 'My Title'; var dialog = const NeonConfirmationDialog(title: title); - await widgetTester.pumpWidget(TestApp(child: dialog)); + await tester.pumpWidgetWithAccessibility(TestApp(child: dialog)); expect(find.text(title), findsOneWidget); expect(find.byType(NeonDialogAction), findsExactly(2)); @@ -34,7 +34,7 @@ void main() { isDestructive: false, ); - await widgetTester.pumpWidget(TestApp(child: dialog)); + await tester.pumpWidgetWithAccessibility(TestApp(child: dialog)); expect(find.byType(NeonDialogAction), findsExactly(2)); expect(find.byType(OutlinedButton), findsExactly(2)); @@ -50,7 +50,7 @@ void main() { confirmAction: confirmAction, declineAction: declineAction, ); - await widgetTester.pumpWidget(TestApp(child: dialog)); + await tester.pumpWidgetWithAccessibility(TestApp(child: dialog)); expect(find.byIcon(Icons.error), findsOneWidget); expect(find.byKey(const Key('content')), findsOneWidget); @@ -58,82 +58,82 @@ void main() { expect(find.byKey(const Key('declineAction')), findsOneWidget); }); - testWidgets('NeonConfirmationDialog actions', (widgetTester) async { + testWidgets('NeonConfirmationDialog actions', (tester) async { const title = 'My Title'; - await widgetTester.pumpWidget(const TestApp(child: Placeholder())); - final context = widgetTester.element(find.byType(Placeholder)); + await tester.pumpWidgetWithAccessibility(const TestApp(child: Placeholder())); + final context = tester.element(find.byType(Placeholder)); // confirm var result = showConfirmationDialog(context: context, title: title); - await widgetTester.pumpAndSettle(); - await widgetTester.tap(find.text(NeonLocalizationsEn().actionContinue)); + await tester.pumpAndSettle(); + await tester.tap(find.text(NeonLocalizationsEn().actionContinue)); expect(await result, isTrue); // decline result = showConfirmationDialog(context: context, title: title); - await widgetTester.pumpAndSettle(); - await widgetTester.tap(find.text(NeonLocalizationsEn().actionCancel)); + await tester.pumpAndSettle(); + await tester.tap(find.text(NeonLocalizationsEn().actionCancel)); expect(await result, isFalse); // cancel by tapping outside result = showConfirmationDialog(context: context, title: title); - await widgetTester.pumpAndSettle(); - await widgetTester.tapAt(Offset.zero); + await tester.pumpAndSettle(); + await tester.tapAt(Offset.zero); expect(await result, isFalse); }); }); group('NeonRenameDialog', () { - testWidgets('NeonRenameDialog widget', (widgetTester) async { + testWidgets('NeonRenameDialog widget', (tester) async { const title = 'My Title'; const value = 'My value'; const dialog = NeonRenameDialog(title: title, value: value); - await widgetTester.pumpWidget(const TestApp(child: dialog)); + await tester.pumpWidgetWithAccessibility(const TestApp(child: dialog)); expect(find.text(title), findsExactly(2), reason: 'The title is also used for the confirmation button'); expect(find.text(value), findsOneWidget); expect(find.byType(TextFormField), findsOneWidget); }); - testWidgets('NeonRenameDialog actions', (widgetTester) async { + testWidgets('NeonRenameDialog actions', (tester) async { const title = 'My Title'; const value = 'My value'; - await widgetTester.pumpWidget(const TestApp(child: Placeholder())); - final context = widgetTester.element(find.byType(Placeholder)); + await tester.pumpWidgetWithAccessibility(const TestApp(child: Placeholder())); + final context = tester.element(find.byType(Placeholder)); // Equal value should not submit var result = showRenameDialog(context: context, title: title, initialValue: value); - await widgetTester.pumpAndSettle(); - await widgetTester.enterText(find.byType(TextFormField), value); - await widgetTester.tap(find.byType(NeonDialogAction)); + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextFormField), value); + await tester.tap(find.byType(NeonDialogAction)); expect(await result, isNull); // Empty value should not submit result = showRenameDialog(context: context, title: title, initialValue: value); - await widgetTester.pumpAndSettle(); - await widgetTester.enterText(find.byType(TextFormField), ''); - await widgetTester.tap(find.byType(NeonDialogAction)); + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextFormField), ''); + await tester.tap(find.byType(NeonDialogAction)); // Different value should submit - await widgetTester.enterText(find.byType(TextFormField), 'My new value'); - await widgetTester.tap(find.byType(NeonDialogAction)); + await tester.enterText(find.byType(TextFormField), 'My new value'); + await tester.tap(find.byType(NeonDialogAction)); expect(await result, equals('My new value')); // Submit via keyboard result = showRenameDialog(context: context, title: title, initialValue: value); - await widgetTester.pumpAndSettle(); - await widgetTester.enterText(find.byType(TextFormField), 'My new value'); - await widgetTester.testTextInput.receiveAction(TextInputAction.done); + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextFormField), 'My new value'); + await tester.testTextInput.receiveAction(TextInputAction.done); expect(await result, equals('My new value')); }); }); group('NeonErrorDialog', () { - testWidgets('NeonErrorDialog widget', (widgetTester) async { + testWidgets('NeonErrorDialog widget', (tester) async { const title = 'My Title'; const content = 'My content'; var dialog = const NeonErrorDialog(content: content, title: title); - await widgetTester.pumpWidget(TestApp(child: dialog)); + await tester.pumpWidgetWithAccessibility(TestApp(child: dialog)); expect(find.byIcon(Icons.error), findsOneWidget); expect(find.text(title), findsOneWidget); @@ -141,39 +141,39 @@ void main() { expect(find.byType(NeonDialogAction), findsOneWidget); dialog = const NeonErrorDialog(content: content); - await widgetTester.pumpWidget(TestApp(child: dialog)); + await tester.pumpWidgetWithAccessibility(TestApp(child: dialog)); expect(find.text(NeonLocalizationsEn().errorDialog), findsOneWidget); }); - testWidgets('NeonErrorDialog actions', (widgetTester) async { + testWidgets('NeonErrorDialog actions', (tester) async { const content = 'My content'; - await widgetTester.pumpWidget(const TestApp(child: Placeholder())); - final context = widgetTester.element(find.byType(Placeholder)); + await tester.pumpWidgetWithAccessibility(const TestApp(child: Placeholder())); + final context = tester.element(find.byType(Placeholder)); final result = showErrorDialog(context: context, message: content); - await widgetTester.pumpAndSettle(); - await widgetTester.tap(find.text(NeonLocalizationsEn().actionClose)); + await tester.pumpAndSettle(); + await tester.tap(find.text(NeonLocalizationsEn().actionClose)); await result; }); }); - testWidgets('UnimplementedDialog', (widgetTester) async { + testWidgets('UnimplementedDialog', (tester) async { const title = 'My Title'; - await widgetTester.pumpWidget(const TestApp(child: Placeholder())); - final context = widgetTester.element(find.byType(Placeholder)); + await tester.pumpWidgetWithAccessibility(const TestApp(child: Placeholder())); + final context = tester.element(find.byType(Placeholder)); final result = showUnimplementedDialog(context: context, title: title); - await widgetTester.pumpAndSettle(); - await widgetTester.tap(find.text(NeonLocalizationsEn().actionClose)); + await tester.pumpAndSettle(); + await tester.tap(find.text(NeonLocalizationsEn().actionClose)); await result; }); - testWidgets('NeonDialog', (widgetTester) async { + testWidgets('NeonDialog', (tester) async { var dialog = const NeonDialog( actions: [], ); - await widgetTester.pumpWidget(TestApp(platform: TargetPlatform.macOS, child: dialog)); + await tester.pumpWidgetWithAccessibility(TestApp(platform: TargetPlatform.macOS, child: dialog)); expect( find.byType(NeonDialogAction), findsOneWidget, @@ -184,14 +184,14 @@ void main() { automaticallyShowCancel: false, actions: [], ); - await widgetTester.pumpWidget(TestApp(platform: TargetPlatform.macOS, child: dialog)); + await tester.pumpWidgetWithAccessibility(TestApp(platform: TargetPlatform.macOS, child: dialog)); expect(find.byType(NeonDialogAction), findsNothing); }); testWidgets('NeonEmojiPickerDialog', (tester) async { SharedPreferences.setMockInitialValues({}); - await tester.pumpWidget(const TestApp(child: Placeholder())); + await tester.pumpWidgetWithAccessibility(const TestApp(child: Placeholder())); final BuildContext context = tester.element(find.byType(Placeholder)); final future = showDialog( @@ -270,7 +270,7 @@ void main() { final accountsBloc = MockAccountsBloc(); when(() => accountsBloc.getUserStatusBlocFor(account)).thenReturn(userStatusBloc); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( wrapMaterial: false, providers: [ @@ -420,7 +420,7 @@ void main() { final accountsBloc = MockAccountsBloc(); when(() => accountsBloc.getCapabilitiesBlocFor(account)).thenReturn(capabilitiesBloc); - await tester.pumpWidget(const TestApp(child: Placeholder())); + await tester.pumpWidgetWithAccessibility(const TestApp(child: Placeholder())); final BuildContext context = tester.element(find.byType(Placeholder)); final future = showDialog( @@ -471,7 +471,7 @@ void main() { final accountsBloc = MockAccountsBloc(); when(() => accountsBloc.getCapabilitiesBlocFor(account)).thenReturn(capabilitiesBloc); - await tester.pumpWidget(const TestApp(child: Placeholder())); + await tester.pumpWidgetWithAccessibility(const TestApp(child: Placeholder())); final BuildContext context = tester.element(find.byType(Placeholder)); final future = showDialog( @@ -524,7 +524,7 @@ void main() { final accountsBloc = MockAccountsBloc(); when(() => accountsBloc.getCapabilitiesBlocFor(account)).thenReturn(capabilitiesBloc); - await tester.pumpWidget(const TestApp(child: Placeholder())); + await tester.pumpWidgetWithAccessibility(const TestApp(child: Placeholder())); final BuildContext context = tester.element(find.byType(Placeholder)); final future = showDialog( diff --git a/packages/neon_framework/test/drawer_test.dart b/packages/neon_framework/test/drawer_test.dart index 1159489107b..9089d71200d 100644 --- a/packages/neon_framework/test/drawer_test.dart +++ b/packages/neon_framework/test/drawer_test.dart @@ -52,7 +52,7 @@ void main() { when(() => accountsBloc.activeAppsBloc).thenReturn(appsBloc); when(() => accountsBloc.activeCapabilitiesBloc).thenReturn(capabilitiesBloc); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), diff --git a/packages/neon_framework/test/image_test.dart b/packages/neon_framework/test/image_test.dart index 03b42ec1035..23c3d0572fc 100644 --- a/packages/neon_framework/test/image_test.dart +++ b/packages/neon_framework/test/image_test.dart @@ -32,7 +32,7 @@ void main() { final image = BehaviorSubject>(); final callback = MockCallbackFunction(); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: NeonImage( image: image, @@ -94,7 +94,7 @@ void main() { final mockRequest = http.Request('GET', Uri()); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: NeonApiImage.withAccount( getRequest: (_) => mockRequest, @@ -136,7 +136,7 @@ void main() { when(() => mockAccount.client).thenReturn(mockNextcloudClient); final uri = Uri.parse('https://example.com'); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: NeonUriImage.withAccount( uri: uri, diff --git a/packages/neon_framework/test/nextcloud_logo_test.dart b/packages/neon_framework/test/nextcloud_logo_test.dart index 0ff15ff92f4..49d459ecefc 100644 --- a/packages/neon_framework/test/nextcloud_logo_test.dart +++ b/packages/neon_framework/test/nextcloud_logo_test.dart @@ -5,10 +5,10 @@ import 'package:neon_framework/testing.dart'; import 'package:vector_graphics/vector_graphics.dart'; void main() { - testWidgets('NextcloudLogo', (widgetTester) async { + testWidgets('NextcloudLogo', (tester) async { const widget = NextcloudLogo(); - await widgetTester.pumpWidget(const TestApp(wrapMaterial: false, child: widget)); + await tester.pumpWidgetWithAccessibility(const TestApp(wrapMaterial: false, child: widget)); expect(find.byType(VectorGraphic), findsOneWidget); expect(find.bySemanticsLabel(NeonLocalizationsEn().nextcloudLogo), findsOneWidget); diff --git a/packages/neon_framework/test/server_icon_test.dart b/packages/neon_framework/test/server_icon_test.dart index bb3859dbc66..1e6d60a879c 100644 --- a/packages/neon_framework/test/server_icon_test.dart +++ b/packages/neon_framework/test/server_icon_test.dart @@ -5,17 +5,17 @@ import 'package:neon_framework/testing.dart'; import 'package:vector_graphics/vector_graphics.dart'; void main() { - testWidgets('NeonServerIcon', (widgetTester) async { + testWidgets('NeonServerIcon', (tester) async { var widget = const NeonServerIcon(icon: 'icon-logo-dark'); - await widgetTester.pumpWidget(TestApp(wrapMaterial: false, child: widget)); + await tester.pumpWidgetWithAccessibility(TestApp(wrapMaterial: false, child: widget)); expect(find.byType(VectorGraphic), findsOneWidget); widget = const NeonServerIcon( icon: 'icon-logo-dark', colorFilter: ColorFilter.mode(Colors.orange, BlendMode.srcIn), ); - await widgetTester.pumpWidget(TestApp(wrapMaterial: false, child: widget)); + await tester.pumpWidgetWithAccessibility(TestApp(wrapMaterial: false, child: widget)); await expectLater(find.byType(VectorGraphic), matchesGoldenFile('goldens/neon_server_icon_nextcloud_logo.png')); }); diff --git a/packages/neon_framework/test/settings_test.dart b/packages/neon_framework/test/settings_test.dart index 83c34dfb99a..cb0bf2f0178 100644 --- a/packages/neon_framework/test/settings_test.dart +++ b/packages/neon_framework/test/settings_test.dart @@ -35,7 +35,7 @@ void main() { }); group('OptionSettingsTile', () { - testWidgets('ToggleOption', (widgetTester) async { + testWidgets('ToggleOption', (tester) async { final option = ToggleOption( storage: storage, key: key, @@ -44,12 +44,12 @@ void main() { ); final widget = TestApp(child: OptionSettingsTile(option: option)); - await widgetTester.pumpWidget(widget); + await tester.pumpWidgetWithAccessibility(widget); expect(find.text('label'), findsOneWidget); - await widgetTester.tap(find.byType(SwitchListTile)); - await widgetTester.pumpAndSettle(); + await tester.tap(find.byType(SwitchListTile)); + await tester.pumpAndSettle(); expect(option.value, isFalse); }); @@ -74,50 +74,50 @@ void main() { ); }); - testWidgets('ToggleOption material', (widgetTester) async { + testWidgets('ToggleOption material', (tester) async { final widget = TestApp(child: OptionSettingsTile(option: option)); - await widgetTester.pumpWidget(widget); + await tester.pumpWidgetWithAccessibility(widget); expect(find.text('label'), findsOneWidget); expect(find.text('first'), findsOneWidget); - await widgetTester.tap(find.byType(SelectSettingsTile)); - await widgetTester.pumpAndSettle(); + await tester.tap(find.byType(SelectSettingsTile)); + await tester.pumpAndSettle(); expect(find.byType(SelectSettingsTileDialog), findsOneWidget); // cancel selection - await widgetTester.tapAt(Offset.zero); - await widgetTester.pumpAndSettle(); + await tester.tapAt(Offset.zero); + await tester.pumpAndSettle(); expect(option.value, SelectValues.first); - await widgetTester.tap(find.byType(SelectSettingsTile)); - await widgetTester.pumpAndSettle(); + await tester.tap(find.byType(SelectSettingsTile)); + await tester.pumpAndSettle(); // Select null value - await widgetTester.tap(find.text('null')); - await widgetTester.pumpAndSettle(); + await tester.tap(find.text('null')); + await tester.pumpAndSettle(); expect(option.value, isNull); }); - testWidgets('ToggleOption cupertino', (widgetTester) async { + testWidgets('ToggleOption cupertino', (tester) async { final widget = TestApp(platform: TargetPlatform.macOS, child: OptionSettingsTile(option: option)); - await widgetTester.pumpWidget(widget); + await tester.pumpWidgetWithAccessibility(widget); expect(find.text('label'), findsOneWidget); expect(find.text('first'), findsOneWidget); - await widgetTester.tap(find.byType(SelectSettingsTile)); - await widgetTester.pumpAndSettle(); + await tester.tap(find.byType(SelectSettingsTile)); + await tester.pumpAndSettle(); expect(find.byType(SelectSettingsTileScreen), findsOneWidget); // Select null value - await widgetTester.tap(find.text('null')); - await widgetTester.pumpAndSettle(); + await tester.tap(find.text('null')); + await tester.pumpAndSettle(); expect(option.value, isNull); // Select second value - await widgetTester.tap(find.text('second')); - await widgetTester.pumpAndSettle(); + await tester.tap(find.text('second')); + await tester.pumpAndSettle(); expect(option.value, SelectValues.second); }); }); diff --git a/packages/neon_framework/test/user_avatar_test.dart b/packages/neon_framework/test/user_avatar_test.dart index 937e0b20d75..3306602c5d7 100644 --- a/packages/neon_framework/test/user_avatar_test.dart +++ b/packages/neon_framework/test/user_avatar_test.dart @@ -45,7 +45,7 @@ void main() { when(() => accountsBloc.activeAccount).thenAnswer((_) => BehaviorSubject.seeded(account)); when(() => accountsBloc.getUserStatusBlocFor(account)).thenReturn(userStatusBloc); - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( providers: [ NeonProvider.value(value: accountsBloc), @@ -71,7 +71,7 @@ void main() { (user_status.$Type.dnd, null, findsNothing, findsOne), ]) { testWidgets('${status.value} ${icon != null ? 'with' : 'without'} emoji', (tester) async { - await tester.pumpWidget( + await tester.pumpWidgetWithAccessibility( TestApp( child: NeonUserStatusIndicator( result: Result( diff --git a/packages/neon_framework/test/validation_tile_test.dart b/packages/neon_framework/test/validation_tile_test.dart index aba888b877f..3946d266bb9 100644 --- a/packages/neon_framework/test/validation_tile_test.dart +++ b/packages/neon_framework/test/validation_tile_test.dart @@ -7,42 +7,48 @@ import 'package:neon_framework/testing.dart'; void main() { group('NeonValidationTile', () { - testWidgets('NeonValidationTile material', (widgetTester) async { + testWidgets('NeonValidationTile material', (tester) async { var widget = const NeonValidationTile(title: 'title', state: ValidationState.loading); - await widgetTester.pumpWidget(TestApp(child: widget)); + await tester.pumpWidgetWithAccessibility(TestApp(child: widget)); expect(find.byType(CircularProgressIndicator), findsOneWidget); // We do not change the theme throughout the test so getting once is enough. - final theme = (widgetTester.firstWidget(find.byType(Theme)) as Theme).data; + final theme = (tester.firstWidget(find.byType(Theme)) as Theme).data; widget = const NeonValidationTile(title: 'title', state: ValidationState.failure); - await widgetTester.pumpWidget(TestApp(child: widget)); + await tester.pumpWidgetWithAccessibility(TestApp(child: widget)); var iconFinder = find.byIcon(AdaptiveIcons.error_outline); expect(iconFinder, findsOneWidget); - var icon = widgetTester.firstWidget(iconFinder) as Icon; + var icon = tester.firstWidget(iconFinder) as Icon; expect(icon.color, theme.colorScheme.error); widget = const NeonValidationTile(title: 'title', state: ValidationState.canceled); - await widgetTester.pumpWidget(TestApp(child: widget)); + await tester.pumpWidgetWithAccessibility(TestApp(child: widget)); iconFinder = find.byIcon(AdaptiveIcons.cancel_outlined); expect(iconFinder, findsOneWidget); - icon = widgetTester.firstWidget(iconFinder) as Icon; - expect(icon.color, theme.disabledColor); - final text = widgetTester.firstWidget(find.text('title')) as Text; - expect(text.style?.color, theme.disabledColor); + icon = tester.firstWidget(iconFinder) as Icon; + expect(icon.color, theme.colorScheme.primary); widget = const NeonValidationTile(title: 'title', state: ValidationState.success); - await widgetTester.pumpWidget(TestApp(child: widget)); + await tester.pumpWidgetWithAccessibility(TestApp(child: widget)); iconFinder = find.byIcon(AdaptiveIcons.check_circle); expect(iconFinder, findsOneWidget); - icon = widgetTester.firstWidget(iconFinder) as Icon; + icon = tester.firstWidget(iconFinder) as Icon; expect(icon.color, theme.colorScheme.primary); }); - testWidgets('NeonValidationTile cupertino', (widgetTester) async { + testWidgets('NeonValidationTile cupertino', (tester) async { const widget = NeonValidationTile(title: 'title', state: ValidationState.canceled); - await widgetTester.pumpWidget(const TestApp(platform: TargetPlatform.macOS, child: widget)); + await tester.pumpWidgetWithAccessibility( + const TestApp( + platform: TargetPlatform.macOS, + child: ColoredBox( + color: Colors.white, + child: widget, + ), + ), + ); expect(find.byType(CupertinoListTile), findsOneWidget); }); }); diff --git a/packages/neon_lints/example/pubspec.yaml b/packages/neon_lints/example/pubspec.yaml index adfea8fb4f0..0036a5e10c4 100644 --- a/packages/neon_lints/example/pubspec.yaml +++ b/packages/neon_lints/example/pubspec.yaml @@ -11,6 +11,8 @@ dependencies: dev_dependencies: custom_lint: ^0.6.4 + flutter_test: + sdk: flutter meta: ^1.11.0 neon_lints: git: diff --git a/packages/neon_lints/example/test/widget_test.dart b/packages/neon_lints/example/test/widget_test.dart new file mode 100644 index 00000000000..dea4086869e --- /dev/null +++ b/packages/neon_lints/example/test/widget_test.dart @@ -0,0 +1,9 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('test', (tester) async { + // expect_lint: prefer_pump_widget_with_accessibility + await tester.pumpWidget(Container()); + }); +} diff --git a/packages/neon_lints/lib/neon_lints.dart b/packages/neon_lints/lib/neon_lints.dart index c10a98aebe1..372ea450556 100644 --- a/packages/neon_lints/lib/neon_lints.dart +++ b/packages/neon_lints/lib/neon_lints.dart @@ -3,6 +3,7 @@ import 'package:neon_lints/src/avoid_dart_html.dart'; import 'package:neon_lints/src/avoid_dart_io.dart'; import 'package:neon_lints/src/avoid_debug_print.dart'; import 'package:neon_lints/src/avoid_exports.dart'; +import 'package:neon_lints/src/prefer_pump_widget_with_accessibility.dart'; /// Registers the neon lints plugin. /// @@ -18,5 +19,6 @@ class _NeonLintsPlugin extends PluginBase { AvoidDartHTML(), AvoidDartIO(), AvoidExports(), + PreferPumpWidgetWithAccessibility(), ]; } diff --git a/packages/neon_lints/lib/src/prefer_pump_widget_with_accessibility.dart b/packages/neon_lints/lib/src/prefer_pump_widget_with_accessibility.dart new file mode 100644 index 00000000000..f8510d5441e --- /dev/null +++ b/packages/neon_lints/lib/src/prefer_pump_widget_with_accessibility.dart @@ -0,0 +1,32 @@ +import 'package:analyzer/error/listener.dart'; +import 'package:custom_lint_builder/custom_lint_builder.dart'; + +/// Lint rule checking that `pumpWidgetWithAccessibility` is used instead of `pumpWidget`. +final class PreferPumpWidgetWithAccessibility extends DartLintRule { + /// @nodoc + const PreferPumpWidgetWithAccessibility() : super(code: _code); + + static const _code = LintCode( + name: 'prefer_pump_widget_with_accessibility', + problemMessage: 'Do not use pumpWidget.', + correctionMessage: ''' +Use 'pumpWidgetWithAccessibility' instead to perform automatic accessibility guideline checks. +''', + ); + + static const String _pumpWidget = 'pumpWidget'; + + @override + void run( + CustomLintResolver resolver, + ErrorReporter reporter, + CustomLintContext context, + ) { + context.registry.addInvocationExpression((node) { + if (node.function.toSource() == _pumpWidget) { + // ignore: deprecated_member_use + reporter.reportErrorForToken(code, node.beginToken); + } + }); + } +}