Unverified Commit fc1b3043 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Add text field to semantics integration test (#21665)

parent fa0a857d
......@@ -6,12 +6,15 @@ import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'src/tests/controls_page.dart';
import 'src/tests/text_field_page.dart';
void main() {
timeDilation = 0.05; // remove animations.
enableFlutterDriverExtension(handler: dataHandler);
runApp(const TestApp());
}
......@@ -20,17 +23,26 @@ const MethodChannel kSemanticsChannel = MethodChannel('semantics');
Future<String> dataHandler(String message) async {
if (message.contains('getSemanticsNode')) {
final Completer<String> completer = new Completer<String>();
final int id = int.tryParse(message.split('#')[1]) ?? 0;
final dynamic result = await kSemanticsChannel.invokeMethod('getSemanticsNode', <String, dynamic>{
'id': id,
});
return json.encode(result);
Future<void> completeSemantics([Object _]) async {
final dynamic result = await kSemanticsChannel.invokeMethod('getSemanticsNode', <String, dynamic>{
'id': id,
});
completer.complete(json.encode(result));
}
if (SchedulerBinding.instance.hasScheduledFrame)
SchedulerBinding.instance.addPostFrameCallback(completeSemantics);
else
completeSemantics();
return completer.future;
}
throw new UnimplementedError();
}
const List<String> routes = <String>[
selectionControlsRoute,
textFieldRoute,
];
class TestApp extends StatelessWidget {
......@@ -41,11 +53,12 @@ class TestApp extends StatelessWidget {
return new MaterialApp(
routes: <String, WidgetBuilder>{
selectionControlsRoute: (BuildContext context) => new SelectionControlsPage(),
textFieldRoute: (BuildContext context) => new TextFieldPage(),
},
home: new Builder(
builder: (BuildContext context) {
return new Scaffold(
body: new Column(
body: new ListView(
children: routes.map((String value) {
return new MaterialButton(
child: new Text(value),
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// The name of the route containing the text field tests.
const String textFieldRoute = 'textField';
/// The string supplied to the [ValueKey] for the normal text field.
const String normalTextFieldKeyValue = 'textFieldNormal';
/// The string supplied to the [ValueKey] for the password text field.
const String passwordTextFieldKeyValue = 'passwordField';
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'text_field_constants.dart';
export 'text_field_constants.dart';
/// A page with a normal text field and a password field.
class TextFieldPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => new _TextFieldPageState();
}
class _TextFieldPageState extends State<TextFieldPage> {
final TextEditingController _normalController = new TextEditingController();
final TextEditingController _passwordController = new TextEditingController();
final Key normalTextFieldKey = const ValueKey<String>(normalTextFieldKeyValue);
final Key passwordTextFieldKey = const ValueKey<String>(passwordTextFieldKeyValue);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(leading: const BackButton(key: ValueKey<String>('back'))),
body: new Material(
child: new Column(children: <Widget>[
new TextField(
key: normalTextFieldKey,
controller: _normalController,
autofocus: false,
),
const Spacer(),
new TextField(
key: passwordTextFieldKey,
controller: _passwordController,
obscureText: true,
autofocus: false,
),
],
),
));
}
}
......@@ -3,3 +3,4 @@
// found in the LICENSE file.
export 'src/tests/controls_constants.dart';
export 'src/tests/text_field_constants.dart';
......@@ -47,6 +47,113 @@ void main() {
await run.exitCode;
driver?.close();
});
group('TextField', () {
setUpAll(() async {
await driver.tap(find.text(textFieldRoute));
});
test('TextField has correct Android semantics', () async {
final SerializableFinder normalTextField = find.byValueKey(normalTextFieldKeyValue);
expect(await getSemantics(normalTextField), hasAndroidSemantics(
className: AndroidClassName.editText,
isEditable: true,
isFocusable: true,
isFocused: false,
isPassword: false,
actions: <AndroidSemanticsAction>[
AndroidSemanticsAction.click,
AndroidSemanticsAction.accessibilityFocus,
],
));
await driver.tap(normalTextField);
expect(await getSemantics(normalTextField), hasAndroidSemantics(
className: AndroidClassName.editText,
isFocusable: true,
isFocused: true,
isEditable: true,
isPassword: false,
actions: <AndroidSemanticsAction>[
AndroidSemanticsAction.click,
AndroidSemanticsAction.accessibilityFocus,
AndroidSemanticsAction.setSelection,
AndroidSemanticsAction.copy,
],
));
await driver.enterText('hello world');
expect(await getSemantics(normalTextField), hasAndroidSemantics(
text: 'hello world',
className: AndroidClassName.editText,
isFocusable: true,
isFocused: true,
isEditable: true,
isPassword: false,
actions: <AndroidSemanticsAction>[
AndroidSemanticsAction.click,
AndroidSemanticsAction.accessibilityFocus,
AndroidSemanticsAction.setSelection,
AndroidSemanticsAction.copy,
],
));
});
test('password TextField has correct Android semantics', () async {
final SerializableFinder passwordTextField = find.byValueKey(passwordTextFieldKeyValue);
expect(await getSemantics(passwordTextField), hasAndroidSemantics(
className: AndroidClassName.editText,
isEditable: true,
isFocusable: true,
isFocused: false,
isPassword: true,
actions: <AndroidSemanticsAction>[
AndroidSemanticsAction.click,
AndroidSemanticsAction.accessibilityFocus,
],
));
await driver.tap(passwordTextField);
expect(await getSemantics(passwordTextField), hasAndroidSemantics(
className: AndroidClassName.editText,
isFocusable: true,
isFocused: true,
isEditable: true,
isPassword: true,
actions: <AndroidSemanticsAction>[
AndroidSemanticsAction.click,
AndroidSemanticsAction.accessibilityFocus,
AndroidSemanticsAction.setSelection,
AndroidSemanticsAction.copy,
],
));
await driver.enterText('hello world');
expect(await getSemantics(passwordTextField), hasAndroidSemantics(
text: '\u{2022}' * ('hello world'.length),
className: AndroidClassName.editText,
isFocusable: true,
isFocused: true,
isEditable: true,
isPassword: true,
actions: <AndroidSemanticsAction>[
AndroidSemanticsAction.click,
AndroidSemanticsAction.accessibilityFocus,
AndroidSemanticsAction.setSelection,
AndroidSemanticsAction.copy,
],
));
});
tearDownAll(() async {
await driver.tap(find.byValueKey('back'));
});
});
group('SelectionControls', () {
setUpAll(() async {
await driver.tap(find.text(selectionControlsRoute));
......
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