@@ -11,86 +11,141 @@ import 'package:integration_test/integration_test.dart';
11
11
12
12
import 'package:pointer_interceptor_example/main.dart' as app;
13
13
14
+ final Finder nonClickableButtonFinder =
15
+ find.byKey (const Key ('transparent-button' ));
16
+ final Finder clickableWrappedButtonFinder =
17
+ find.byKey (const Key ('wrapped-transparent-button' ));
18
+ final Finder clickableButtonFinder = find.byKey (const Key ('clickable-button' ));
19
+ final Finder backgroundFinder =
20
+ find.byKey (const ValueKey <String >('background-widget' ));
21
+
14
22
void main () {
15
23
IntegrationTestWidgetsFlutterBinding .ensureInitialized ();
16
24
17
- group ('Widget' , () {
18
- final Finder nonClickableButtonFinder =
19
- find.byKey (const Key ('transparent-button' ));
20
- final Finder clickableWrappedButtonFinder =
21
- find.byKey (const Key ('wrapped-transparent-button' ));
22
- final Finder clickableButtonFinder =
23
- find.byKey (const Key ('clickable-button' ));
24
-
25
+ group ('Without semantics' , () {
25
26
testWidgets (
26
27
'on wrapped elements, the browser does not hit the background-html-view' ,
27
28
(WidgetTester tester) async {
28
29
app.main ();
29
30
await tester.pumpAndSettle ();
30
31
31
- final html.Element ? element =
32
- _getHtmlElementFromFinder (clickableButtonFinder, tester);
33
-
34
- if (html.document.querySelector ('flt-glass-pane' )? .shadowRoot != null ) {
35
- // In flutter master...
36
- expect (element? .id, isNot ('background-html-view' ));
37
- } else {
38
- // In previous versions (--web-renderer=html only)...
39
- expect (element? .tagName.toLowerCase (), 'flt-platform-view' );
40
- final html.Element ? platformViewRoot =
41
- element? .shadowRoot? .getElementById ('background-html-view' );
42
- expect (platformViewRoot, isNull);
43
- }
44
- });
32
+ final html.Element element =
33
+ _getHtmlElementAtCenter (clickableButtonFinder, tester);
34
+
35
+ expect (element.id, isNot ('background-html-view' ));
36
+ }, semanticsEnabled: false );
45
37
46
38
testWidgets (
47
39
'on wrapped elements with intercepting set to false, the browser hits the background-html-view' ,
48
40
(WidgetTester tester) async {
49
41
app.main ();
50
42
await tester.pumpAndSettle ();
51
43
52
- final html.Element ? element =
53
- _getHtmlElementFromFinder (clickableWrappedButtonFinder, tester);
54
-
55
- if (html.document.querySelector ('flt-glass-pane' )? .shadowRoot != null ) {
56
- // In flutter master...
57
- expect (element? .id, 'background-html-view' );
58
- } else {
59
- // In previous versions (--web-renderer=html only)...
60
- expect (element? .tagName.toLowerCase (), 'flt-platform-view' );
61
- final html.Element ? platformViewRoot =
62
- element? .shadowRoot? .getElementById ('background-html-view' );
63
- expect (platformViewRoot, isNotNull);
64
- }
65
- });
44
+ final html.Element element =
45
+ _getHtmlElementAtCenter (clickableWrappedButtonFinder, tester);
46
+
47
+ expect (element.id, 'background-html-view' );
48
+ }, semanticsEnabled: false );
66
49
67
50
testWidgets (
68
51
'on unwrapped elements, the browser hits the background-html-view' ,
69
52
(WidgetTester tester) async {
70
53
app.main ();
71
54
await tester.pumpAndSettle ();
72
55
73
- final html.Element ? element =
74
- _getHtmlElementFromFinder (nonClickableButtonFinder, tester);
75
-
76
- if (html.document.querySelector ('flt-glass-pane' )? .shadowRoot != null ) {
77
- // In flutter master...
78
- expect (element? .id, 'background-html-view' );
79
- } else {
80
- // In previous versions (--web-renderer=html only)...
81
- expect (element? .tagName.toLowerCase (), 'flt-platform-view' );
82
- final html.Element ? platformViewRoot =
83
- element? .shadowRoot? .getElementById ('background-html-view' );
84
- expect (platformViewRoot, isNotNull);
85
- }
56
+ final html.Element element =
57
+ _getHtmlElementAtCenter (nonClickableButtonFinder, tester);
58
+
59
+ expect (element.id, 'background-html-view' );
60
+ }, semanticsEnabled: false );
61
+
62
+ testWidgets ('on background directly' , (WidgetTester tester) async {
63
+ app.main ();
64
+ await tester.pumpAndSettle ();
65
+
66
+ final html.Element element =
67
+ _getHtmlElementAt (tester.getTopLeft (backgroundFinder));
68
+
69
+ expect (element.id, 'background-html-view' );
70
+ }, semanticsEnabled: false );
71
+ });
72
+
73
+ group ('With semantics' , () {
74
+ testWidgets ('finds semantics of wrapped widgets' ,
75
+ (WidgetTester tester) async {
76
+ app.main ();
77
+ await tester.pumpAndSettle ();
78
+
79
+ final html.Element element =
80
+ _getHtmlElementAtCenter (clickableButtonFinder, tester);
81
+
82
+ expect (element.tagName.toLowerCase (), 'flt-semantics' );
83
+ expect (element.getAttribute ('aria-label' ), 'Works As Expected' );
84
+ });
85
+
86
+ testWidgets (
87
+ 'finds semantics of wrapped widgets with intercepting set to false' ,
88
+ (WidgetTester tester) async {
89
+ app.main ();
90
+ await tester.pumpAndSettle ();
91
+
92
+ final html.Element element =
93
+ _getHtmlElementAtCenter (clickableWrappedButtonFinder, tester);
94
+
95
+ expect (element.tagName.toLowerCase (), 'flt-semantics' );
96
+ expect (element.getAttribute ('aria-label' ),
97
+ 'Never calls onPressed transparent' );
98
+ });
99
+
100
+ testWidgets ('finds semantics of unwrapped elements' ,
101
+ (WidgetTester tester) async {
102
+ app.main ();
103
+ await tester.pumpAndSettle ();
104
+
105
+ final html.Element element =
106
+ _getHtmlElementAtCenter (nonClickableButtonFinder, tester);
107
+
108
+ expect (element.tagName.toLowerCase (), 'flt-semantics' );
109
+ expect (element.getAttribute ('aria-label' ), 'Never calls onPressed' );
110
+ });
111
+
112
+ // Notice that, when hit-testing the background platform view, instead of
113
+ // finding a semantics node, the platform view itself is found. This is
114
+ // because the platform view does not add interactive semantics nodes into
115
+ // the framework's semantics tree. Instead, its semantics is determined by
116
+ // the HTML content of the platform view itself. Flutter's semantics tree
117
+ // simply allows the hit test to land on the platform view by making itself
118
+ // hit test transparent.
119
+ testWidgets ('on background directly' , (WidgetTester tester) async {
120
+ app.main ();
121
+ await tester.pumpAndSettle ();
122
+
123
+ final html.Element element =
124
+ _getHtmlElementAt (tester.getTopLeft (backgroundFinder));
125
+
126
+ expect (element.id, 'background-html-view' );
86
127
});
87
128
});
88
129
}
89
130
90
- // This functions locates a widget from a Finder, and asks the browser what's the
91
- // DOM element in the center of the coordinates of the widget. (Returns *which*
92
- // DOM element will handle Mouse interactions first at those coordinates.)
93
- html.Element ? _getHtmlElementFromFinder (Finder finder, WidgetTester tester) {
131
+ // Calls [_getHtmlElementAt] passing it the center of the widget identified by
132
+ // the `finder`.
133
+ html.Element _getHtmlElementAtCenter (Finder finder, WidgetTester tester) {
94
134
final Offset point = tester.getCenter (finder);
95
- return html.document.elementFromPoint (point.dx.toInt (), point.dy.toInt ());
135
+ return _getHtmlElementAt (point);
136
+ }
137
+
138
+ // Locates the DOM element at the given `point` using `elementFromPoint`.
139
+ //
140
+ // `elementFromPoint` is an approximate proxy for a hit test, although it's
141
+ // sensitive to the presence of shadow roots and browser quirks (not all
142
+ // browsers agree on what it should return in all situations). Since this test
143
+ // runs only in Chromium, it relies on Chromium's behavior.
144
+ html.Element _getHtmlElementAt (Offset point) {
145
+ // Probe at the shadow so the browser reports semantics nodes in addition to
146
+ // platform view elements. If probed from `html.document` the browser hides
147
+ // the contents of <flt-glass-name> as an implementation detail.
148
+ final html.ShadowRoot glassPaneShadow =
149
+ html.document.querySelector ('flt-glass-pane' )! .shadowRoot! ;
150
+ return glassPaneShadow.elementFromPoint (point.dx.toInt (), point.dy.toInt ())! ;
96
151
}
0 commit comments