diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bca3cf824..763129d137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ - Tag all spans with thread info on non-web platforms ([#3101](https://github.com/getsentry/sentry-dart/pull/3101), [#3144](https://github.com/getsentry/sentry-dart/pull/3144)) - feat(feedback): Add option to disable keyboard resize ([#3154](https://github.com/getsentry/sentry-dart/pull/3154)) +### Fixes + +- Implement prefill logic in `SentryFeedbackWidget` for `useSentryUser` parameter to populate fields with current user data ([#3180](https://github.com/getsentry/sentry-dart/pull/3180)) + ### Enhancements - Add `DioException` response data to error breadcrumb ([#3164](https://github.com/getsentry/sentry-dart/pull/3164)) diff --git a/packages/flutter/lib/src/feedback/sentry_feedback_widget.dart b/packages/flutter/lib/src/feedback/sentry_feedback_widget.dart index ea017d0c65..0488e7ebb5 100644 --- a/packages/flutter/lib/src/feedback/sentry_feedback_widget.dart +++ b/packages/flutter/lib/src/feedback/sentry_feedback_widget.dart @@ -94,6 +94,9 @@ class _SentryFeedbackWidgetState extends State { void initState() { super.initState(); + if(widget.options.useSentryUser) { + _setSentryUserData(); + } _restorePreservedData(); _captureReplay(); @@ -407,6 +410,28 @@ class _SentryFeedbackWidgetState extends State { } } + SentryUser? _getUser() { + SentryUser? user; + widget._hub.configureScope((scope) { + user = scope.user; + }); + return user; + } + + void _setSentryUserData() { + final user = _getUser(); + if(user == null) return; + + final userName = user.name; + if(userName != null) { + _nameController.text = userName; + } + final userEmail = user.email; + if(userEmail != null) { + _emailController.text = userEmail; + } + } + void _restorePreservedData() { final preservedName = SentryFeedbackWidget.preservedName; if (preservedName != null) { diff --git a/packages/flutter/test/feedback/sentry_feedback_widget_test.dart b/packages/flutter/test/feedback/sentry_feedback_widget_test.dart index 9551fa7dc9..9187e21eae 100644 --- a/packages/flutter/test/feedback/sentry_feedback_widget_test.dart +++ b/packages/flutter/test/feedback/sentry_feedback_widget_test.dart @@ -20,11 +20,7 @@ void main() { final mockBinding = MockSentryNativeBinding(); when(mockBinding.supportsReplay).thenReturn(true); when(fixture.hub.scope).thenReturn(fixture.scope); - when(fixture.hub.configureScope(any)).thenAnswer((invocation) { - final callback = invocation.positionalArguments.first; - callback(fixture.scope); - return null; - }); + final replayId = SentryId.fromId('1988bb1b6f0d4c509e232f0cb9aaeaea'); when(mockBinding.captureReplay()).thenAnswer((_) async => replayId); @@ -228,6 +224,59 @@ void main() { }); }); + group('$SentryFeedbackWidget prefills fields from sentryUser', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + testWidgets('prefills form data if useSentryUser is true', (tester) async { + fixture.options.feedback.useSentryUser = true; + fixture.hub.configureScope((scope) { + scope.setUser(fixture.sentryUser); + }); + + await fixture.pumpFeedbackWidget( + tester, + (hub) => SentryFeedbackWidget(hub: hub), + ); + + final nameField = tester.widget( + find.byKey(ValueKey('sentry_feedback_name_textfield')), + ); + final emailField = tester.widget( + find.byKey(ValueKey('sentry_feedback_email_textfield')), + ); + + expect(nameField.controller?.text, "fixture-name"); + expect(emailField.controller?.text, "fixture@example.com"); + }); + + testWidgets('does not prefill form data if useSentryUser is false', (tester) async { + fixture.options.feedback.useSentryUser = false; + fixture.hub.configureScope((scope) { + scope.setUser(fixture.sentryUser); + }); + + await fixture.pumpFeedbackWidget( + tester, + (hub) => SentryFeedbackWidget(hub: hub), + ); + + final nameField = tester.widget( + find.byKey(ValueKey('sentry_feedback_name_textfield')), + ); + final emailField = tester.widget( + find.byKey(ValueKey('sentry_feedback_email_textfield')), + ); + + expect(nameField.controller?.text, isEmpty); + expect(emailField.controller?.text, isEmpty); + }); + + }); + group('$SentryFeedbackWidget uses naming from options', () { late Fixture fixture; @@ -759,6 +808,7 @@ class Fixture { var options = SentryFlutterOptions(); var hub = MockHub(); late var scope = Scope(options); + late SentryUser sentryUser; Fixture() { when(hub.options).thenReturn(options); @@ -768,9 +818,20 @@ class Fixture { hint: anyNamed('hint'), withScope: anyNamed('withScope'), )).thenAnswer((_) async => SentryId.empty()); - + when(hub.configureScope(any)).thenAnswer((invocation) { + final callback = invocation.positionalArguments.first; + callback(scope); + return null; + }); SentryFeedbackWidget.pendingAssociatedEventId = null; SentryFeedbackWidget.clearPreservedData(); + + sentryUser = SentryUser( + id: 'fixture-id', + username: 'fixture-username', + name: 'fixture-name', + email: 'fixture@example.com', + ); } Future pumpFeedbackWidget( diff --git a/packages/flutter/test/screenshot/sentry_screenshot_widget_test.dart b/packages/flutter/test/screenshot/sentry_screenshot_widget_test.dart index 59d782c637..928b1fd148 100644 --- a/packages/flutter/test/screenshot/sentry_screenshot_widget_test.dart +++ b/packages/flutter/test/screenshot/sentry_screenshot_widget_test.dart @@ -102,7 +102,14 @@ void main() { options.navigatorKey = navigatorKey; var hub = mocks.MockHub(); + late var scope = Scope(options); + when(hub.options).thenReturn(options); + when(hub.configureScope(any)).thenAnswer((invocation) { + final callback = invocation.positionalArguments.first; + callback(scope); + return null; + }); await tester.pumpWidget( MaterialApp(