Unverified Commit c94f0bea authored by David Iglesias's avatar David Iglesias Committed by GitHub

[web] Make web integration tests shadow DOM aware. (#82926)

parent fa1c6a28
...@@ -904,6 +904,7 @@ Future<void> _runFlutterDriverWebTest({ ...@@ -904,6 +904,7 @@ Future<void> _runFlutterDriverWebTest({
await runCommand( await runCommand(
flutter, flutter,
<String>[ <String>[
...?flutterTestArgs,
'drive', 'drive',
'--target=$target', '--target=$target',
'--browser-name=chrome', '--browser-name=chrome',
...@@ -1080,6 +1081,7 @@ Future<void> _runGalleryE2eWebTest(String buildMode, { bool canvasKit = false }) ...@@ -1080,6 +1081,7 @@ Future<void> _runGalleryE2eWebTest(String buildMode, { bool canvasKit = false })
await runCommand( await runCommand(
flutter, flutter,
<String>[ <String>[
...?flutterTestArgs,
'drive', 'drive',
if (canvasKit) if (canvasKit)
'--dart-define=FLUTTER_WEB_USE_SKIA=true', '--dart-define=FLUTTER_WEB_USE_SKIA=true',
...@@ -1163,6 +1165,7 @@ Future<void> _runWebReleaseTest(String target, { ...@@ -1163,6 +1165,7 @@ Future<void> _runWebReleaseTest(String target, {
await runCommand( await runCommand(
flutter, flutter,
<String>[ <String>[
...?flutterTestArgs,
'build', 'build',
'web', 'web',
'--release', '--release',
......
...@@ -15,6 +15,15 @@ import 'package:web_e2e_tests/text_editing_main.dart' as app; ...@@ -15,6 +15,15 @@ import 'package:web_e2e_tests/text_editing_main.dart' as app;
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
/// Locate elements in the correct root of the application, whether it is
/// `document` or the new `shadowRoot` of `flt-class-pane`.
List<Node> findElements(String selector) {
final ShadowRoot? shadowRoot = document.querySelector('flt-glass-pane')?.shadowRoot;
return (shadowRoot != null) ?
shadowRoot.querySelectorAll(selector):
document.querySelectorAll(selector);
}
testWidgets('Focused text field creates a native input element', testWidgets('Focused text field creates a native input element',
(WidgetTester tester) async { (WidgetTester tester) async {
app.main(); app.main();
...@@ -29,10 +38,9 @@ void main() { ...@@ -29,10 +38,9 @@ void main() {
await tester.tap(find.byKey(const Key('input'))); await tester.tap(find.byKey(const Key('input')));
// A native input element will be appended to the DOM. // A native input element will be appended to the DOM.
final List<Node> nodeList = document.getElementsByTagName('input'); final List<Node> nodeList = findElements('input');
expect(nodeList.length, equals(1)); expect(nodeList.length, equals(1));
final InputElement input = final InputElement input = nodeList[0] as InputElement;
document.getElementsByTagName('input')[0] as InputElement;
// The element's value will be the same as the textFormField's value. // The element's value will be the same as the textFormField's value.
expect(input.value, 'Text1'); expect(input.value, 'Text1');
...@@ -57,10 +65,9 @@ void main() { ...@@ -57,10 +65,9 @@ void main() {
await tester.tap(find.byKey(const Key('empty-input'))); await tester.tap(find.byKey(const Key('empty-input')));
// A native input element will be appended to the DOM. // A native input element will be appended to the DOM.
final List<Node> nodeList = document.getElementsByTagName('input'); final List<Node> nodeList = findElements('input');
expect(nodeList.length, equals(1)); expect(nodeList.length, equals(1));
final InputElement input = final InputElement input = nodeList[0] as InputElement;
document.getElementsByTagName('input')[0] as InputElement;
// The element's value will be empty. // The element's value will be empty.
expect(input.value, ''); expect(input.value, '');
...@@ -92,8 +99,7 @@ void main() { ...@@ -92,8 +99,7 @@ void main() {
await tester.tap(find.byKey(const Key('input2'))); await tester.tap(find.byKey(const Key('input2')));
// // Press Tab. This should trigger `onFieldSubmitted` of TextField. // // Press Tab. This should trigger `onFieldSubmitted` of TextField.
final InputElement input = final InputElement input = findElements('input')[0] as InputElement;
document.getElementsByTagName('input')[0] as InputElement;
dispatchKeyboardEvent(input, 'keydown', <String, dynamic>{ dispatchKeyboardEvent(input, 'keydown', <String, dynamic>{
'keyCode': 13, // Enter. 'keyCode': 13, // Enter.
'cancelable': true, 'cancelable': true,
...@@ -121,10 +127,9 @@ void main() { ...@@ -121,10 +127,9 @@ void main() {
await tester.tap(find.byKey(const Key('input'))); await tester.tap(find.byKey(const Key('input')));
// A native input element will be appended to the DOM. // A native input element will be appended to the DOM.
final List<Node> nodeList = document.getElementsByTagName('input'); final List<Node> nodeList = findElements('input');
expect(nodeList.length, equals(1)); expect(nodeList.length, equals(1));
final InputElement input = final InputElement input = nodeList[0] as InputElement;
document.getElementsByTagName('input')[0] as InputElement;
// Press Tab. The focus should move to the next TextFormField. // Press Tab. The focus should move to the next TextFormField.
dispatchKeyboardEvent(input, 'keydown', <String, dynamic>{ dispatchKeyboardEvent(input, 'keydown', <String, dynamic>{
...@@ -132,14 +137,14 @@ void main() { ...@@ -132,14 +137,14 @@ void main() {
'code': 'Tab', 'code': 'Tab',
'bubbles': true, 'bubbles': true,
'cancelable': true, 'cancelable': true,
'composed': true,
}); });
await tester.pumpAndSettle(); await tester.pumpAndSettle();
// A native input element for the next TextField should be attached to the // A native input element for the next TextField should be attached to the
// DOM. // DOM.
final InputElement input2 = final InputElement input2 = findElements('input')[0] as InputElement;
document.getElementsByTagName('input')[0] as InputElement;
expect(input2.value, 'Text2'); expect(input2.value, 'Text2');
}, semanticsEnabled: false); }, semanticsEnabled: false);
...@@ -156,10 +161,9 @@ void main() { ...@@ -156,10 +161,9 @@ void main() {
await tester.tap(find.byKey(const Key('input'))); await tester.tap(find.byKey(const Key('input')));
// A native input element will be appended to the DOM. // A native input element will be appended to the DOM.
final List<Node> nodeList = document.getElementsByTagName('input'); final List<Node> nodeList = findElements('input');
expect(nodeList.length, equals(1)); expect(nodeList.length, equals(1));
final InputElement input = final InputElement input = nodeList[0] as InputElement;
document.getElementsByTagName('input')[0] as InputElement;
// Press and release CapsLock. // Press and release CapsLock.
dispatchKeyboardEvent(input, 'keydown', <String, dynamic>{ dispatchKeyboardEvent(input, 'keydown', <String, dynamic>{
...@@ -167,12 +171,14 @@ void main() { ...@@ -167,12 +171,14 @@ void main() {
'code': 'CapsLock', 'code': 'CapsLock',
'bubbles': true, 'bubbles': true,
'cancelable': true, 'cancelable': true,
'composed': true,
}); });
dispatchKeyboardEvent(input, 'keyup', <String, dynamic>{ dispatchKeyboardEvent(input, 'keyup', <String, dynamic>{
'key': 'CapsLock', 'key': 'CapsLock',
'code': 'CapsLock', 'code': 'CapsLock',
'bubbles': true, 'bubbles': true,
'cancelable': true, 'cancelable': true,
'composed': true,
}); });
// Press Tab. The focus should move to the next TextFormField. // Press Tab. The focus should move to the next TextFormField.
...@@ -181,14 +187,14 @@ void main() { ...@@ -181,14 +187,14 @@ void main() {
'code': 'Tab', 'code': 'Tab',
'bubbles': true, 'bubbles': true,
'cancelable': true, 'cancelable': true,
'composed': true,
}); });
await tester.pumpAndSettle(); await tester.pumpAndSettle();
// A native input element for the next TextField should be attached to the // A native input element for the next TextField should be attached to the
// DOM. // DOM.
final InputElement input2 = final InputElement input2 = findElements('input')[0] as InputElement;
document.getElementsByTagName('input')[0] as InputElement;
expect(input2.value, 'Text2'); expect(input2.value, 'Text2');
}, semanticsEnabled: false); }, semanticsEnabled: false);
...@@ -216,7 +222,7 @@ void main() { ...@@ -216,7 +222,7 @@ void main() {
await gesture.up(); await gesture.up();
// A native input element will be appended to the DOM. // A native input element will be appended to the DOM.
final List<Node> nodeList = document.getElementsByTagName('textarea'); final List<Node> nodeList = findElements('textarea');
expect(nodeList.length, equals(1)); expect(nodeList.length, equals(1));
final TextAreaElement input = nodeList[0] as TextAreaElement; final TextAreaElement input = nodeList[0] as TextAreaElement;
// The element's value should contain the selectable text. // The element's value should contain the selectable text.
......
...@@ -8,6 +8,8 @@ import 'package:flutter_driver/flutter_driver.dart'; ...@@ -8,6 +8,8 @@ import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
import 'package:webdriver/async_io.dart'; import 'package:webdriver/async_io.dart';
// TODO(web): Migrate this test to a normal integration_test with a WidgetTester.
/// The following test is used as a simple smoke test for verifying Flutter /// The following test is used as a simple smoke test for verifying Flutter
/// Framework and Flutter Web Engine integration. /// Framework and Flutter Web Engine integration.
void main() { void main() {
...@@ -35,12 +37,23 @@ void main() { ...@@ -35,12 +37,23 @@ void main() {
await Future<void>.delayed(const Duration(seconds: 2)); await Future<void>.delayed(const Duration(seconds: 2));
// A flutter web app may be rendered directly on the body of the page, or
// inside the shadow root of the flt-glass-pane (after Flutter 2.4). To
// make this test backwards compatible, we first need to locate the correct
// root for the app.
//
// It's either the shadowRoot within flt-glass-pane, or [driver.webDriver].
final SearchContext appRoot = await driver.webDriver.execute(
'return document.querySelector("flt-glass-pane")?.shadowRoot;',
<dynamic>[],
) as SearchContext? ?? driver.webDriver;
// Elements with tag "flt-semantics" would show up after enabling // Elements with tag "flt-semantics" would show up after enabling
// accessibility. // accessibility.
// //
// The tag used here is based on // The tag used here is based on
// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/semantics/semantics.dart#L534 // https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/semantics/semantics.dart#L534
final WebElement element = await driver.webDriver.findElement(const By.tagName('flt-semantics')); final WebElement element = await appRoot.findElement(const By.cssSelector('flt-semantics'));
expect(element, isNotNull); expect(element, isNotNull);
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment