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