diff --git a/packages/url_launcher/url_launcher_web/CHANGELOG.md b/packages/url_launcher/url_launcher_web/CHANGELOG.md index 6c3c1b01071..010a4bfd95a 100644 --- a/packages/url_launcher/url_launcher_web/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_web/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.4.2 +* Fixed an issue that caused duplicate semantic nodes for `Link` widgets. * Updates minimum supported SDK version to Flutter 3.29/Dart 3.7. ## 2.4.1 diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart index 4f74f4ff1aa..2c9b2c81c36 100644 --- a/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart @@ -208,6 +208,43 @@ void main() { maxScrolls: 1000, ); }); + + testWidgets('MergeSemantics is always present to avoid duplicate nodes', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Column( + children: [ + WebLinkDelegate( + TestLinkInfo( + uri: Uri.parse('https://dart.dev/xyz'), + target: LinkTarget.blank, + builder: (BuildContext context, FollowLink? followLink) { + return ElevatedButton( + onPressed: followLink, + child: const Text('First Button'), + ); + }, + ), + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + final Finder buttonFinder = find.byType(ElevatedButton); + expect(buttonFinder, findsOneWidget); + + final Element buttonElement = tester.element(buttonFinder); + final MergeSemantics? parentWidget = + buttonElement.findAncestorWidgetOfExactType(); + expect(parentWidget, isNotNull); + }); }); group('Follows links', () { @@ -897,17 +934,13 @@ void main() { isLink: true, identifier: 'test-link-12', // linkUrl: 'https://foobar/example?q=1', - children: [ - matchesSemantics( - hasTapAction: true, - hasEnabledState: true, - hasFocusAction: true, - isEnabled: true, - isButton: true, - isFocusable: true, - label: 'Button Link Text', - ), - ], + hasTapAction: true, + hasEnabledState: true, + hasFocusAction: true, + isEnabled: true, + isButton: true, + isFocusable: true, + label: 'Button Link Text', ), ); @@ -943,7 +976,9 @@ void main() { final Finder linkFinder = find.byKey(linkKey); expect( tester.getSemantics( - find.descendant(of: linkFinder, matching: find.byType(Semantics)), + find + .descendant(of: linkFinder, matching: find.byType(Semantics)) + .first, ), matchesSemantics( isLink: true, diff --git a/packages/url_launcher/url_launcher_web/lib/src/link.dart b/packages/url_launcher/url_launcher_web/lib/src/link.dart index f28ca254f29..8a633f44295 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/link.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/link.dart @@ -117,13 +117,15 @@ class WebLinkDelegateState extends State { } Widget _buildChild(BuildContext context) { - return Semantics( - link: true, - identifier: _semanticsIdentifier, - linkUrl: widget.link.uri, - child: widget.link.builder( - context, - widget.link.isDisabled ? null : _followLink, + return MergeSemantics( + child: Semantics( + link: true, + identifier: _semanticsIdentifier, + linkUrl: widget.link.uri, + child: widget.link.builder( + context, + widget.link.isDisabled ? null : _followLink, + ), ), ); } diff --git a/packages/url_launcher/url_launcher_web/pubspec.yaml b/packages/url_launcher/url_launcher_web/pubspec.yaml index 820e20f349d..7e0f0e6f9ff 100644 --- a/packages/url_launcher/url_launcher_web/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher_web description: Web platform implementation of url_launcher repository: https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22 -version: 2.4.1 +version: 2.4.2 environment: sdk: ^3.7.0