mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
184 lines
5.3 KiB
Dart
184 lines
5.3 KiB
Dart
// Copyright 2014 The Flutter 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/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'text_input_utils.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
group('AutofillClient', () {
|
|
late FakeTextChannel fakeTextChannel;
|
|
final FakeAutofillScope scope = FakeAutofillScope();
|
|
|
|
setUp(() {
|
|
fakeTextChannel = FakeTextChannel((MethodCall call) async {});
|
|
TextInput.setChannel(fakeTextChannel);
|
|
scope.clients.clear();
|
|
});
|
|
|
|
tearDown(() {
|
|
TextInputConnection.debugResetId();
|
|
TextInput.setChannel(SystemChannels.textInput);
|
|
});
|
|
|
|
test('Does not throw if the hint list is empty', () async {
|
|
Object? exception;
|
|
try {
|
|
const AutofillConfiguration(
|
|
uniqueIdentifier: 'id',
|
|
autofillHints: <String>[],
|
|
currentEditingValue: TextEditingValue.empty,
|
|
);
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
|
|
expect(exception, isNull);
|
|
});
|
|
|
|
test(
|
|
'AutofillClients send the correct configuration to the platform and responds to updateEditingStateWithTag method correctly',
|
|
() async {
|
|
final FakeAutofillClient client1 = FakeAutofillClient(const TextEditingValue(text: 'test1'));
|
|
final FakeAutofillClient client2 = FakeAutofillClient(const TextEditingValue(text: 'test2'));
|
|
|
|
client1.textInputConfiguration = TextInputConfiguration(
|
|
autofillConfiguration: AutofillConfiguration(
|
|
uniqueIdentifier: client1.autofillId,
|
|
autofillHints: const <String>['client1'],
|
|
currentEditingValue: client1.currentTextEditingValue,
|
|
),
|
|
);
|
|
|
|
client2.textInputConfiguration = TextInputConfiguration(
|
|
autofillConfiguration: AutofillConfiguration(
|
|
uniqueIdentifier: client2.autofillId,
|
|
autofillHints: const <String>['client2'],
|
|
currentEditingValue: client2.currentTextEditingValue,
|
|
),
|
|
);
|
|
|
|
scope.register(client1);
|
|
scope.register(client2);
|
|
client1.currentAutofillScope = scope;
|
|
client2.currentAutofillScope = scope;
|
|
|
|
scope.attach(client1, client1.textInputConfiguration);
|
|
|
|
final Map<String, dynamic> expectedConfiguration = client1.textInputConfiguration.toJson();
|
|
expectedConfiguration['fields'] = <Map<String, dynamic>>[
|
|
client1.textInputConfiguration.toJson(),
|
|
client2.textInputConfiguration.toJson(),
|
|
];
|
|
|
|
fakeTextChannel.validateOutgoingMethodCalls(<MethodCall>[
|
|
MethodCall('TextInput.setClient', <dynamic>[1, expectedConfiguration]),
|
|
]);
|
|
|
|
const TextEditingValue text2 = TextEditingValue(text: 'Text 2');
|
|
fakeTextChannel.incoming?.call(MethodCall(
|
|
'TextInputClient.updateEditingStateWithTag',
|
|
<dynamic>[0, <String, dynamic>{ client2.autofillId : text2.toJSON() }],
|
|
));
|
|
|
|
expect(client2.currentTextEditingValue, text2);
|
|
},
|
|
);
|
|
});
|
|
}
|
|
|
|
class FakeAutofillClient implements TextInputClient, AutofillClient {
|
|
FakeAutofillClient(this.currentTextEditingValue);
|
|
|
|
@override
|
|
String get autofillId => hashCode.toString();
|
|
|
|
@override
|
|
late TextInputConfiguration textInputConfiguration;
|
|
|
|
@override
|
|
void updateEditingValue(TextEditingValue newEditingValue) {
|
|
currentTextEditingValue = newEditingValue;
|
|
latestMethodCall = 'updateEditingValue';
|
|
}
|
|
|
|
@override
|
|
AutofillScope? currentAutofillScope;
|
|
|
|
String latestMethodCall = '';
|
|
|
|
@override
|
|
TextEditingValue currentTextEditingValue;
|
|
|
|
@override
|
|
void performAction(TextInputAction action) {
|
|
latestMethodCall = 'performAction';
|
|
}
|
|
|
|
@override
|
|
void performPrivateCommand(String action, Map<String, dynamic> data) {
|
|
latestMethodCall = 'performPrivateCommand';
|
|
}
|
|
|
|
@override
|
|
void updateFloatingCursor(RawFloatingCursorPoint point) {
|
|
latestMethodCall = 'updateFloatingCursor';
|
|
}
|
|
|
|
@override
|
|
void connectionClosed() {
|
|
latestMethodCall = 'connectionClosed';
|
|
}
|
|
|
|
@override
|
|
void showAutocorrectionPromptRect(int start, int end) {
|
|
latestMethodCall = 'showAutocorrectionPromptRect';
|
|
}
|
|
|
|
@override
|
|
void didChangeInputControl(TextInputControl? oldControl, TextInputControl? newControl) {
|
|
latestMethodCall = 'didChangeInputControl';
|
|
}
|
|
|
|
@override
|
|
void autofill(TextEditingValue newEditingValue) => updateEditingValue(newEditingValue);
|
|
|
|
@override
|
|
void showToolbar() {
|
|
latestMethodCall = 'showToolbar';
|
|
}
|
|
|
|
@override
|
|
void insertTextPlaceholder(Size size) {
|
|
latestMethodCall = 'insertTextPlaceholder';
|
|
}
|
|
|
|
@override
|
|
void removeTextPlaceholder() {
|
|
latestMethodCall = 'removeTextPlaceholder';
|
|
}
|
|
|
|
@override
|
|
void performSelector(String selectorName) {
|
|
latestMethodCall = 'performSelector';
|
|
}
|
|
}
|
|
|
|
class FakeAutofillScope with AutofillScopeMixin implements AutofillScope {
|
|
final Map<String, AutofillClient> clients = <String, AutofillClient>{};
|
|
|
|
@override
|
|
Iterable<AutofillClient> get autofillClients => clients.values;
|
|
|
|
@override
|
|
AutofillClient getAutofillClient(String autofillId) => clients[autofillId]!;
|
|
|
|
void register(AutofillClient client) {
|
|
clients.putIfAbsent(client.autofillId, () => client);
|
|
}
|
|
}
|