diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e9d0b26e3..c6d149849d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- SentryUserInteractionWidget: add support for PopupMenuButton and PopupMenuItem ([#1361](https://github.com/getsentry/sentry-dart/pull/1361)) + ### Fixes - Fix `SentryUserInteractionWidget` throwing when Sentry is not enabled ([#1363](https://github.com/getsentry/sentry-dart/pull/1363)) diff --git a/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart b/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart index a33d96435d..f98a919065 100644 --- a/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart +++ b/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart @@ -219,7 +219,7 @@ Element? _clickTrackerElement; /// /// It's supported by the most common [Widget], for example: /// [ButtonStyleButton], [MaterialButton], [CupertinoButton], [InkWell], -/// and [IconButton]. +/// [IconButton], [PopupMenuButton] and [PopupMenuItem]. /// Mostly for onPressed, onTap, and onLongPress events /// /// Example on how to set up: @@ -542,6 +542,24 @@ class _SentryUserInteractionWidgetState eventType: 'onPressed', ); } + } else if (widget is PopupMenuButton) { + if (widget.enabled) { + return UserInteractionWidget( + element: element, + description: _findDescriptionOf(element, false), + type: 'PopupMenuButton', + eventType: 'onTap', + ); + } + } else if (widget is PopupMenuItem) { + if (widget.enabled) { + return UserInteractionWidget( + element: element, + description: _findDescriptionOf(element, false), + type: 'PopupMenuItem', + eventType: 'onTap', + ); + } } return null; diff --git a/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart b/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart index d62a54ad2e..02d1022157 100644 --- a/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart +++ b/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart @@ -120,6 +120,42 @@ void main() { expect(crumb?.data?['label'], 'Button 5'); }); }); + + testWidgets('Add crumb for PopupMenuButton', (tester) async { + await tester.runAsync(() async { + final sut = fixture.getSut(); + + await tapMe(tester, sut, 'popup_menu_button'); + + Breadcrumb? crumb; + fixture.hub.configureScope((scope) { + crumb = scope.breadcrumbs.last; + }); + expect(crumb?.category, 'ui.click'); + expect(crumb?.data?['view.id'], 'popup_menu_button'); + expect(crumb?.data?['view.class'], 'PopupMenuButton'); + }); + }); + + testWidgets('Add crumb for PopupMenuItem', (tester) async { + await tester.runAsync(() async { + final sut = fixture.getSut(); + + // open the popup menu and wait for the animation to complete + await tapMe(tester, sut, 'popup_menu_button'); + await tester.pumpAndSettle(); + + await tapMe(tester, sut, 'popup_menu_item_1'); + + Breadcrumb? crumb; + fixture.hub.configureScope((scope) { + crumb = scope.breadcrumbs.last; + }); + expect(crumb?.category, 'ui.click'); + expect(crumb?.data?['view.id'], 'popup_menu_item_1'); + expect(crumb?.data?['view.class'], 'PopupMenuItem'); + }); + }); }); group('$SentryUserInteractionWidget performance', () { @@ -363,6 +399,15 @@ class Page1 extends StatelessWidget { }, child: const Text('Go to page 2'), ), + PopupMenuButton( + key: ValueKey('popup_menu_button'), + itemBuilder: (_) => [ + PopupMenuItem( + key: ValueKey('popup_menu_item_1'), + child: Text('first item'), + ), + ], + ), ], ), ),