diff --git a/CHANGELOG.md b/CHANGELOG.md index f2a92e3990..1b284e336c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ ### Fixes -- Fix: Only call method channels on native platforms ([#1196](https://github.com/getsentry/sentry-dart/pull/1196)) +- enableUserInteractionTracing sometimes finds the wrong widget ([#1212](https://github.com/getsentry/sentry-dart/pull/1212)) +- Only call method channels on native platforms ([#1196](https://github.com/getsentry/sentry-dart/pull/1196)) ### Dependencies 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 86240954c4..405d5b42f5 100644 --- a/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart +++ b/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:meta/meta.dart'; import '../../sentry_flutter.dart'; @@ -257,6 +258,13 @@ class _SentryUserInteractionWidgetState if (renderObject == null) { return; } + var hitFound = true; + if (renderObject is RenderPointerListener) { + final hitResult = BoxHitTestResult(); + + // Returns false if the hit can continue to other objects below this one. + hitFound = renderObject.hitTest(hitResult, position: position); + } final transform = renderObject.getTransformTo(rootElement.renderObject); final paintBounds = @@ -268,7 +276,7 @@ class _SentryUserInteractionWidgetState tappedWidget = _getDescriptionFrom(element); - if (tappedWidget == null) { + if (tappedWidget == null || !hitFound) { element.visitChildElements(elementFinder); } } 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 e7ce8bf60b..5c6733bb47 100644 --- a/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart +++ b/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart @@ -201,7 +201,7 @@ void main() { currentTimer = tracer.autoFinishAfterTimer; }); - await tapMe(tester, sut, 'btn_1'); + await tapMe(tester, sut, 'btn_1', pumpWidget: false); Timer? autoFinishAfterTimer; fixture.hub.configureScope((scope) { @@ -226,7 +226,7 @@ void main() { currentTracer = (scope.span as SentryTracer); }); - await tapMe(tester, sut, 'btn_2'); + await tapMe(tester, sut, 'btn_2', pumpWidget: false); SentryTracer? tracer; fixture.hub.configureScope((scope) { @@ -238,8 +238,15 @@ void main() { }); } -Future tapMe(WidgetTester tester, Widget widget, String key) async { - await tester.pumpWidget(widget); +Future tapMe( + WidgetTester tester, + Widget widget, + String key, { + bool pumpWidget = true, +}) async { + if (pumpWidget) { + await tester.pumpWidget(widget); + } await tester.tap(find.byKey(Key(key))); } @@ -278,59 +285,96 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: 'Welcome to Flutter', - home: Scaffold( - appBar: AppBar( - title: const Text('Welcome to Flutter'), - ), - body: Center( - child: Column( - children: [ - MaterialButton( - key: Key('btn_1'), - onPressed: () { - // print('button pressed'); - }, - child: const Text('Button 1'), - ), - CupertinoButton( - key: Key('btn_2'), - onPressed: () { - // print('button pressed 2'); - }, - child: const Text('Button 2'), + home: Page1(), + routes: {'page2': (context) => const Page2()}, + ); + } +} + +class Page1 extends StatelessWidget { + const Page1({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + children: [ + MaterialButton( + key: Key('btn_1'), + onPressed: () { + // print('button pressed'); + }, + child: const Text('Button 1'), + ), + CupertinoButton( + key: Key('btn_2'), + onPressed: () { + // print('button pressed 2'); + }, + child: const Text('Button 2'), + ), + IconButton( + key: Key('btn_3'), + onPressed: () { + // print('button pressed 3'); + }, + icon: Icon( + Icons.dark_mode, + semanticLabel: 'My Icon', ), - IconButton( - key: Key('btn_3'), - onPressed: () { - // print('button pressed 3'); + ), + Card( + child: GestureDetector( + key: Key('btn_4'), + onTap: () => { + // print('button pressed 4'), }, - icon: Icon( - Icons.dark_mode, - semanticLabel: 'My Icon', + child: Stack( + children: [ + //fancy card layout + ElevatedButton( + key: Key('btn_5'), + onPressed: () => { + // print('button pressed 5'), + }, + child: const Text('Button 5'), + ), + ], ), ), - Card( - child: GestureDetector( - key: Key('btn_4'), - onTap: () => { - // print('button pressed 4'), - }, - child: Stack( - children: [ - //fancy card layout - ElevatedButton( - key: Key('btn_5'), - onPressed: () => { - // print('button pressed 5'), - }, - child: const Text('Button 5'), - ), - ], - ), - ), - ) - ], - ), + ), + MaterialButton( + key: Key('btn_go_to_page2'), + onPressed: () { + Navigator.of(context).pushNamed('page2'); + }, + child: const Text('Go to page 2'), + ), + ], + ), + ), + ); + } +} + +class Page2 extends StatelessWidget { + const Page2({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + children: [ + MaterialButton( + key: Key('btn_page_2'), + onPressed: () { + // print('button page 2 pressed'); + }, + child: const Text('Button Page 2'), + ), + ], ), ), );