Skip to content

Commit 951adfe

Browse files
authored
[pointer_interceptor] fix integration test (flutter#1675)
1 parent a539261 commit 951adfe

File tree

4 files changed

+117
-56
lines changed

4 files changed

+117
-56
lines changed

packages/pointer_interceptor/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.9.3+1
2+
3+
* Updates example code and integration tests to accomodate hit-testing changes in the Flutter web engine.
4+
15
## 0.9.3
26

37
* Require minimal version of flutter SDK to be `2.10`

packages/pointer_interceptor/example/integration_test/widget_test.dart

+109-54
Original file line numberDiff line numberDiff line change
@@ -11,86 +11,141 @@ import 'package:integration_test/integration_test.dart';
1111

1212
import '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+
1422
void 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
}

packages/pointer_interceptor/example/lib/main.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ class _MyHomePageState extends State<MyHomePage> {
116116
alignment: Alignment.center,
117117
children: <Widget>[
118118
HtmlElement(
119+
key: const ValueKey<String>('background-widget'),
119120
onClick: () {
120121
_clickedOn('html-element');
121122
},
@@ -134,7 +135,8 @@ class _MyHomePageState extends State<MyHomePage> {
134135
intercepting: false,
135136
child: ElevatedButton(
136137
key: const Key('wrapped-transparent-button'),
137-
child: const Text('Never calls onPressed'),
138+
child:
139+
const Text('Never calls onPressed transparent'),
138140
onPressed: () {
139141
_clickedOn('wrapped-transparent-button');
140142
},

packages/pointer_interceptor/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: pointer_interceptor
22
description: A widget to prevent clicks from being swallowed by underlying HtmlElementViews on the web.
33
repository: https://github.com/flutter/packages/tree/main/packages/pointer_interceptor
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pointer_interceptor%22
5-
version: 0.9.3
5+
version: 0.9.3+1
66

77
environment:
88
sdk: ">=2.12.0 <3.0.0"

0 commit comments

Comments
 (0)