@@ -11,86 +11,141 @@ import 'package:integration_test/integration_test.dart';
1111
1212import 'package:pointer_interceptor_example/main.dart' as app;
1313
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+
1422void main () {
1523 IntegrationTestWidgetsFlutterBinding .ensureInitialized ();
1624
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' , () {
2526 testWidgets (
2627 'on wrapped elements, the browser does not hit the background-html-view' ,
2728 (WidgetTester tester) async {
2829 app.main ();
2930 await tester.pumpAndSettle ();
3031
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 );
4537
4638 testWidgets (
4739 'on wrapped elements with intercepting set to false, the browser hits the background-html-view' ,
4840 (WidgetTester tester) async {
4941 app.main ();
5042 await tester.pumpAndSettle ();
5143
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 );
6649
6750 testWidgets (
6851 'on unwrapped elements, the browser hits the background-html-view' ,
6952 (WidgetTester tester) async {
7053 app.main ();
7154 await tester.pumpAndSettle ();
7255
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' );
86127 });
87128 });
88129}
89130
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) {
94134 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 ())! ;
96151}
0 commit comments