@@ -428,7 +428,7 @@ void _testEngineSemanticsOwner() {
428
428
expectSemanticsTree ('''
429
429
<sem style="$rootSemanticStyle ">
430
430
<sem-c>
431
- <sem aria-label="Hello"></sem>
431
+ <sem aria-label="Hello" role="text" ></sem>
432
432
</sem-c>
433
433
</sem>''' );
434
434
@@ -443,7 +443,7 @@ void _testEngineSemanticsOwner() {
443
443
expectSemanticsTree ('''
444
444
<sem style="$rootSemanticStyle ">
445
445
<sem-c>
446
- <a aria-label="Hello" role="button" style="display: block;"></a>
446
+ <a aria-label="Hello" style="display: block;"></a>
447
447
</sem-c>
448
448
</sem>''' );
449
449
expect (existingParent, tree[1 ]! .element.parent);
@@ -2106,6 +2106,89 @@ void _testTappable() {
2106
2106
2107
2107
semantics ().semanticsEnabled = false ;
2108
2108
});
2109
+
2110
+ // Regression test for: https://github.com/flutter/flutter/issues/134842
2111
+ //
2112
+ // If the click event is allowed to propagate through the hierarchy, then both
2113
+ // the descendant and the parent will generate a SemanticsAction.tap, causing
2114
+ // a double-tap to happen on the framework side.
2115
+ test ('inner tappable overrides ancestor tappable' , () async {
2116
+ semantics ()
2117
+ ..debugOverrideTimestampFunction (() => _testTime)
2118
+ ..semanticsEnabled = true ;
2119
+
2120
+ final List <CapturedAction > capturedActions = < CapturedAction > [];
2121
+ EnginePlatformDispatcher .instance.onSemanticsActionEvent = (ui.SemanticsActionEvent event) {
2122
+ capturedActions.add ((event.nodeId, event.type, event.arguments));
2123
+ };
2124
+
2125
+ final SemanticsTester tester = SemanticsTester (semantics ());
2126
+ tester.updateNode (
2127
+ id: 0 ,
2128
+ isFocusable: true ,
2129
+ hasTap: true ,
2130
+ hasEnabledState: true ,
2131
+ isEnabled: true ,
2132
+ isButton: true ,
2133
+ rect: const ui.Rect .fromLTRB (0 , 0 , 100 , 50 ),
2134
+ children: < SemanticsNodeUpdate > [
2135
+ tester.updateNode (
2136
+ id: 1 ,
2137
+ isFocusable: true ,
2138
+ hasTap: true ,
2139
+ hasEnabledState: true ,
2140
+ isEnabled: true ,
2141
+ isButton: true ,
2142
+ rect: const ui.Rect .fromLTRB (0 , 0 , 100 , 50 ),
2143
+ ),
2144
+ ],
2145
+ );
2146
+ tester.apply ();
2147
+
2148
+ expectSemanticsTree ('''
2149
+ <sem flt-tappable role="button" style="$rootSemanticStyle ">
2150
+ <sem-c>
2151
+ <sem flt-tappable role="button"></sem>
2152
+ </sem-c>
2153
+ </sem>
2154
+ ''' );
2155
+
2156
+ // Tap on the outer element
2157
+ {
2158
+ final DomElement element = tester.getSemanticsObject (0 ).element;
2159
+ final DomRect rect = element.getBoundingClientRect ();
2160
+
2161
+ element.dispatchEvent (createDomMouseEvent ('click' , < Object ? , Object ? > {
2162
+ 'clientX' : (rect.left + (rect.right - rect.left) / 2 ).floor (),
2163
+ 'clientY' : (rect.top + (rect.bottom - rect.top) / 2 ).floor (),
2164
+ }));
2165
+
2166
+ expect (capturedActions, < CapturedAction > [
2167
+ (0 , ui.SemanticsAction .tap, null ),
2168
+ ]);
2169
+ }
2170
+
2171
+ // Tap on the inner element
2172
+ {
2173
+ capturedActions.clear ();
2174
+ final DomElement element = tester.getSemanticsObject (1 ).element;
2175
+ final DomRect rect = element.getBoundingClientRect ();
2176
+
2177
+ element.dispatchEvent (createDomMouseEvent ('click' , < Object ? , Object ? > {
2178
+ 'bubbles' : true ,
2179
+ 'clientX' : (rect.left + (rect.right - rect.left) / 2 ).floor (),
2180
+ 'clientY' : (rect.top + (rect.bottom - rect.top) / 2 ).floor (),
2181
+ }));
2182
+
2183
+ // The click on the inner element should not propagate to the parent to
2184
+ // avoid sending a second SemanticsAction.tap action to the framework.
2185
+ expect (capturedActions, < CapturedAction > [
2186
+ (1 , ui.SemanticsAction .tap, null ),
2187
+ ]);
2188
+ }
2189
+
2190
+ semantics ().semanticsEnabled = false ;
2191
+ });
2109
2192
}
2110
2193
2111
2194
void _testImage () {
0 commit comments