Migrate to ChannelBuffers.push (#81235)
This commit is contained in:
parent
cb0bda39c0
commit
35ad43f20c
@ -11,6 +11,6 @@ void main() {
|
||||
Ticker((Duration duration) { }).start();
|
||||
|
||||
final ByteData? message = const StringCodec().encodeMessage('AppLifecycleState.paused');
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
|
||||
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
|
||||
});
|
||||
}
|
||||
|
@ -20,9 +20,6 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Focus on a TextFormField.
|
||||
final Finder finder = find.byKey(const Key('input'));
|
||||
expect(finder, findsOneWidget);
|
||||
@ -48,9 +45,6 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Focus on a TextFormField.
|
||||
final Finder finder = find.byKey(const Key('empty-input'));
|
||||
expect(finder, findsOneWidget);
|
||||
@ -76,9 +70,6 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// This text will show no-enter initially. It will have 'enter-pressed'
|
||||
// after `onFieldSubmitted` of TextField is triggered.
|
||||
final Finder textFinder = find.byKey(const Key('text'));
|
||||
@ -112,9 +103,6 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Focus on a TextFormField.
|
||||
final Finder finder = find.byKey(const Key('input'));
|
||||
expect(finder, findsOneWidget);
|
||||
@ -147,9 +135,6 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Focus on a TextFormField.
|
||||
final Finder finder = find.byKey(const Key('input'));
|
||||
expect(finder, findsOneWidget);
|
||||
@ -197,9 +182,6 @@ void main() {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
|
||||
SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
// Select something from the selectable text.
|
||||
final Finder finder = find.byKey(const Key('selectable'));
|
||||
expect(finder, findsOneWidget);
|
||||
|
@ -5,7 +5,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_driver/flutter_driver.dart';
|
||||
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
|
||||
import 'package:test/test.dart';
|
||||
import 'package:webdriver/async_io.dart';
|
||||
|
||||
/// The following test is used as a simple smoke test for verifying Flutter
|
||||
@ -33,6 +33,7 @@ void main() {
|
||||
test('enable accessibility', () async {
|
||||
await driver.enableAccessibility();
|
||||
|
||||
// TODO(ianh): this delay violates our style guide. We should instead wait for a triggering event.
|
||||
await Future<void>.delayed(const Duration(seconds: 2));
|
||||
|
||||
// Elements with tag "flt-semantics" would show up after enabling
|
||||
|
@ -104,8 +104,8 @@ abstract class BindingBase {
|
||||
/// A number of additional bindings are defined as extensions of
|
||||
/// [BindingBase], e.g., [ServicesBinding], [RendererBinding], and
|
||||
/// [WidgetsBinding]. Each of these bindings define behaviors that interact
|
||||
/// with a [ui.PlatformDispatcher], e.g., [ServicesBinding] registers a
|
||||
/// [ui.PlatformDispatcher.onPlatformMessage] handler, and [RendererBinding]
|
||||
/// with a [ui.PlatformDispatcher], e.g., [ServicesBinding] registers
|
||||
/// listeners with the [ChannelBuffers], and [RendererBinding]
|
||||
/// registers [ui.PlatformDispatcher.onMetricsChanged],
|
||||
/// [ui.PlatformDispatcher.onTextScaleFactorChanged],
|
||||
/// [ui.PlatformDispatcher.onSemanticsEnabledChanged], and
|
||||
|
@ -2,12 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'binding.dart';
|
||||
|
||||
/// A function which takes a platform message and asynchronously returns an encoded response.
|
||||
typedef MessageHandler = Future<ByteData?>? Function(ByteData? message);
|
||||
|
||||
@ -19,12 +16,39 @@ abstract class BinaryMessenger {
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const BinaryMessenger();
|
||||
|
||||
/// Calls the handler registered for the given channel.
|
||||
/// Queues a message.
|
||||
///
|
||||
/// Typically called by [ServicesBinding] to handle platform messages received
|
||||
/// from [dart:ui.PlatformDispatcher.onPlatformMessage].
|
||||
/// The returned future completes immediately.
|
||||
///
|
||||
/// This method adds the provided message to the given channel (named by the
|
||||
/// `channel` argument) of the [ChannelBuffers] object. This simulates what
|
||||
/// happens when a plugin on the platform thread (e.g. Kotlin or Swift code)
|
||||
/// sends a message to the plugin package on the Dart thread.
|
||||
///
|
||||
/// The `data` argument contains the message as encoded bytes. (The format
|
||||
/// used for the message depends on the channel.)
|
||||
///
|
||||
/// The `callback` argument, if non-null, is eventually invoked with the
|
||||
/// response that would have been sent to the platform thread.
|
||||
///
|
||||
/// In production code, it is more efficient to call
|
||||
/// `ServicesBinding.instance.channelBuffers.push` directly.
|
||||
///
|
||||
/// In tests, consider using
|
||||
/// `tester.binding.defaultBinaryMessenger.handlePlatformMessage` (see
|
||||
/// [WidgetTester], [TestWidgetsFlutterBinding], [TestDefaultBinaryMessenger],
|
||||
/// and [TestDefaultBinaryMessenger.handlePlatformMessage] respectively).
|
||||
///
|
||||
/// To register a handler for a given message channel, see [setMessageHandler].
|
||||
///
|
||||
/// To send a message _to_ a plugin on the platform thread, see [send].
|
||||
// TODO(ianh): deprecate this method once cocoon and other customer_tests are migrated:
|
||||
// @NotYetDeprecated(
|
||||
// 'Instead of calling this method, use ServicesBinding.instance.channelBuffers.push. '
|
||||
// 'In tests, consider using tester.binding.defaultBinaryMessenger.handlePlatformMessage '
|
||||
// 'or TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.handlePlatformMessage. '
|
||||
// 'This feature was deprecated after v2.1.0-10.0.pre.'
|
||||
// )
|
||||
Future<void> handlePlatformMessage(String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback);
|
||||
|
||||
/// Send a binary message to the platform plugins on the given channel.
|
||||
@ -43,37 +67,6 @@ abstract class BinaryMessenger {
|
||||
/// The handler's return value, if non-null, is sent as a response, unencoded.
|
||||
void setMessageHandler(String channel, MessageHandler? handler);
|
||||
|
||||
/// Returns true if the `handler` argument matches the `handler` previously
|
||||
/// passed to [setMessageHandler].
|
||||
///
|
||||
/// This method is useful for tests or test harnesses that want to assert the
|
||||
/// handler for the specified channel has not been altered by a previous test.
|
||||
///
|
||||
/// Passing null for the `handler` returns true if the handler for the
|
||||
/// `channel` is not set.
|
||||
bool checkMessageHandler(String channel, MessageHandler? handler);
|
||||
|
||||
/// Set a mock callback for intercepting messages from the [send] method on
|
||||
/// this class, on the given channel, without decoding them.
|
||||
///
|
||||
/// The given callback will replace the currently registered mock callback for
|
||||
/// that channel, if any. To remove the mock handler, pass null as the
|
||||
/// `handler` argument.
|
||||
///
|
||||
/// The handler's return value, if non-null, is used as a response, unencoded.
|
||||
///
|
||||
/// This is intended for testing. Messages intercepted in this manner are not
|
||||
/// sent to platform plugins.
|
||||
void setMockMessageHandler(String channel, MessageHandler? handler);
|
||||
|
||||
/// Returns true if the `handler` argument matches the `handler` previously
|
||||
/// passed to [setMockMessageHandler].
|
||||
///
|
||||
/// This method is useful for tests or test harnesses that want to assert the
|
||||
/// mock handler for the specified channel has not been altered by a previous
|
||||
/// test.
|
||||
///
|
||||
/// Passing null for the `handler` returns true if the handler for the
|
||||
/// `channel` is not set.
|
||||
bool checkMockMessageHandler(String channel, MessageHandler? handler);
|
||||
// Looking for setMockMessageHandler or checkMockMessageHandler?
|
||||
// See this shim package: packages/flutter_test/lib/src/deprecated.dart
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
|
||||
_instance = this;
|
||||
_defaultBinaryMessenger = createBinaryMessenger();
|
||||
_restorationManager = createRestorationManager();
|
||||
window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
|
||||
initLicenses();
|
||||
SystemChannels.system.setMessageHandler((dynamic message) => handleSystemMessage(message as Object));
|
||||
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
|
||||
@ -49,6 +48,28 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
|
||||
BinaryMessenger get defaultBinaryMessenger => _defaultBinaryMessenger;
|
||||
late BinaryMessenger _defaultBinaryMessenger;
|
||||
|
||||
/// The low level buffering and dispatch mechanism for messages sent by
|
||||
/// plugins on the engine side to their corresponding plugin code on
|
||||
/// the framework side.
|
||||
///
|
||||
/// This exposes the [dart:ui.channelBuffers] object. Bindings can override
|
||||
/// this getter to intercept calls to the [ChannelBuffers] mechanism (for
|
||||
/// example, for tests).
|
||||
///
|
||||
/// In production, direct access to this object should not be necessary.
|
||||
/// Messages are received and dispatched by the [defaultBinaryMessenger]. This
|
||||
/// object is primarily used to send mock messages in tests, via the
|
||||
/// [ChannelBuffers.push] method (simulating a plugin sending a message to the
|
||||
/// framework).
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [PlatformDispatcher.sendPlatformMessage], which is used for sending
|
||||
/// messages to plugins from the framework (the opposite of
|
||||
/// [channelBuffers]).
|
||||
/// * [platformDispatcher], the [PlatformDispatcher] singleton.
|
||||
ui.ChannelBuffers get channelBuffers => ui.channelBuffers;
|
||||
|
||||
/// Creates a default [BinaryMessenger] instance that can be used for sending
|
||||
/// platform messages.
|
||||
@protected
|
||||
@ -56,7 +77,6 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
|
||||
return const _DefaultBinaryMessenger._();
|
||||
}
|
||||
|
||||
|
||||
/// Called when the operating system notifies the application of a memory
|
||||
/// pressure situation.
|
||||
///
|
||||
@ -253,17 +273,20 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
|
||||
class _DefaultBinaryMessenger extends BinaryMessenger {
|
||||
const _DefaultBinaryMessenger._();
|
||||
|
||||
// Handlers for incoming messages from platform plugins.
|
||||
// This is static so that this class can have a const constructor.
|
||||
static final Map<String, MessageHandler> _handlers =
|
||||
<String, MessageHandler>{};
|
||||
@override
|
||||
Future<void> handlePlatformMessage(
|
||||
String channel,
|
||||
ByteData? message,
|
||||
ui.PlatformMessageResponseCallback? callback,
|
||||
) async {
|
||||
ui.channelBuffers.push(channel, message, (ByteData? data) {
|
||||
if (callback != null)
|
||||
callback(data);
|
||||
});
|
||||
}
|
||||
|
||||
// Mock handlers that intercept and respond to outgoing messages.
|
||||
// This is static so that this class can have a const constructor.
|
||||
static final Map<String, MessageHandler> _mockHandlers =
|
||||
<String, MessageHandler>{};
|
||||
|
||||
Future<ByteData?> _sendPlatformMessage(String channel, ByteData? message) {
|
||||
@override
|
||||
Future<ByteData?> send(String channel, ByteData? message) {
|
||||
final Completer<ByteData?> completer = Completer<ByteData?>();
|
||||
// ui.PlatformDispatcher.instance is accessed directly instead of using
|
||||
// ServicesBinding.instance.platformDispatcher because this method might be
|
||||
@ -272,6 +295,8 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
|
||||
// ui.PlatformDispatcher.instance because the PlatformDispatcher may be
|
||||
// dependency injected elsewhere with a different instance. However, static
|
||||
// access at this location seems to be the least bad option.
|
||||
// TODO(ianh): Use ServicesBinding.instance once we have better diagnostics
|
||||
// on that getter.
|
||||
ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
|
||||
try {
|
||||
completer.complete(reply);
|
||||
@ -287,70 +312,27 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO(goderbauer): Add pragma (and enable test in
|
||||
// break_on_framework_exceptions_test.dart) when it works on async methods,
|
||||
// https://github.com/dart-lang/sdk/issues/45673
|
||||
// @pragma('vm:notify-debugger-on-exception')
|
||||
Future<void> handlePlatformMessage(
|
||||
String channel,
|
||||
ByteData? data,
|
||||
ui.PlatformMessageResponseCallback? callback,
|
||||
) async {
|
||||
ByteData? response;
|
||||
try {
|
||||
final MessageHandler? handler = _handlers[channel];
|
||||
if (handler != null) {
|
||||
response = await handler(data);
|
||||
} else {
|
||||
ui.channelBuffers.push(channel, data, callback!);
|
||||
callback = null;
|
||||
}
|
||||
} catch (exception, stack) {
|
||||
FlutterError.reportError(FlutterErrorDetails(
|
||||
exception: exception,
|
||||
stack: stack,
|
||||
library: 'services library',
|
||||
context: ErrorDescription('during a platform message callback'),
|
||||
));
|
||||
} finally {
|
||||
if (callback != null) {
|
||||
callback(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ByteData?>? send(String channel, ByteData? message) {
|
||||
final MessageHandler? handler = _mockHandlers[channel];
|
||||
if (handler != null)
|
||||
return handler(message);
|
||||
return _sendPlatformMessage(channel, message);
|
||||
}
|
||||
|
||||
@override
|
||||
void setMessageHandler(String channel, MessageHandler? handler) {
|
||||
if (handler == null) {
|
||||
_handlers.remove(channel);
|
||||
ui.channelBuffers.clearListener(channel);
|
||||
} else {
|
||||
_handlers[channel] = handler;
|
||||
ui.channelBuffers.drain(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
|
||||
await handlePlatformMessage(channel, data, callback);
|
||||
ui.channelBuffers.setListener(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
|
||||
ByteData? response;
|
||||
try {
|
||||
response = await handler(data);
|
||||
} catch (exception, stack) {
|
||||
|
||||
FlutterError.reportError(FlutterErrorDetails(
|
||||
exception: exception,
|
||||
stack: stack,
|
||||
library: 'services library',
|
||||
context: ErrorDescription('during a platform message callback'),
|
||||
));
|
||||
} finally {
|
||||
callback(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool checkMessageHandler(String channel, MessageHandler? handler) => _handlers[channel] == handler;
|
||||
|
||||
@override
|
||||
void setMockMessageHandler(String channel, MessageHandler? handler) {
|
||||
if (handler == null)
|
||||
_mockHandlers.remove(channel);
|
||||
else
|
||||
_mockHandlers[channel] = handler;
|
||||
}
|
||||
|
||||
@override
|
||||
bool checkMockMessageHandler(String channel, MessageHandler? handler) => _mockHandlers[channel] == handler;
|
||||
}
|
||||
|
@ -95,7 +95,6 @@ abstract class MethodCodec {
|
||||
ByteData encodeErrorEnvelope({ required String code, String? message, Object? details});
|
||||
}
|
||||
|
||||
|
||||
/// Thrown to indicate that a platform interaction failed in the platform
|
||||
/// plugin.
|
||||
///
|
||||
|
@ -75,31 +75,10 @@ class BasicMessageChannel<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a mock callback for intercepting messages sent on this channel.
|
||||
/// Messages may be null.
|
||||
///
|
||||
/// The given callback will replace the currently registered mock callback for
|
||||
/// this channel, if any. To remove the mock handler, pass null as the
|
||||
/// `handler` argument.
|
||||
///
|
||||
/// The handler's return value is used as a message reply. It may be null.
|
||||
///
|
||||
/// This is intended for testing. Messages intercepted in this manner are not
|
||||
/// sent to platform plugins.
|
||||
void setMockMessageHandler(Future<T> Function(T? message)? handler) {
|
||||
if (handler == null) {
|
||||
binaryMessenger.setMockMessageHandler(name, null);
|
||||
} else {
|
||||
binaryMessenger.setMockMessageHandler(name, (ByteData? message) async {
|
||||
return codec.encodeMessage(await handler(codec.decodeMessage(message)));
|
||||
});
|
||||
}
|
||||
}
|
||||
// Looking for setMockMessageHandler?
|
||||
// See this shim package: packages/flutter_test/lib/src/deprecated.dart
|
||||
}
|
||||
|
||||
Expando<Object> _methodChannelHandlers = Expando<Object>();
|
||||
Expando<Object> _methodChannelMockHandlers = Expando<Object>();
|
||||
|
||||
/// A named channel for communicating with platform plugins using asynchronous
|
||||
/// method calls.
|
||||
///
|
||||
@ -374,7 +353,6 @@ class MethodChannel {
|
||||
/// similarly to what happens if no method call handler has been set.
|
||||
/// Any other exception results in an error envelope being sent.
|
||||
void setMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) {
|
||||
_methodChannelHandlers[this] = handler;
|
||||
binaryMessenger.setMessageHandler(
|
||||
name,
|
||||
handler == null
|
||||
@ -383,53 +361,7 @@ class MethodChannel {
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns true if the `handler` argument matches the `handler` previously
|
||||
/// passed to [setMethodCallHandler].
|
||||
///
|
||||
/// This method is useful for tests or test harnesses that want to assert the
|
||||
/// handler for the specified channel has not been altered by a previous test.
|
||||
///
|
||||
/// Passing null for the `handler` returns true if the handler for the channel
|
||||
/// is not set.
|
||||
bool checkMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) => _methodChannelHandlers[this] == handler;
|
||||
|
||||
/// Sets a mock callback for intercepting method invocations on this channel.
|
||||
///
|
||||
/// The given callback will replace the currently registered mock callback for
|
||||
/// this channel, if any. To remove the mock handler, pass null as the
|
||||
/// `handler` argument.
|
||||
///
|
||||
/// Later calls to [invokeMethod] will result in a successful result,
|
||||
/// a [PlatformException] or a [MissingPluginException], determined by how
|
||||
/// the future returned by the mock callback completes. The [codec] of this
|
||||
/// channel is used to encode and decode values and errors.
|
||||
///
|
||||
/// This is intended for testing. Method calls intercepted in this manner are
|
||||
/// not sent to platform plugins.
|
||||
///
|
||||
/// The provided `handler` must return a `Future` that completes with the
|
||||
/// return value of the call. The value will be encoded using
|
||||
/// [MethodCodec.encodeSuccessEnvelope], to act as if platform plugin had
|
||||
/// returned that value.
|
||||
void setMockMethodCallHandler(Future<dynamic>? Function(MethodCall call)? handler) {
|
||||
_methodChannelMockHandlers[this] = handler;
|
||||
binaryMessenger.setMockMessageHandler(
|
||||
name,
|
||||
handler == null ? null : (ByteData? message) => _handleAsMethodCall(message, handler),
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns true if the `handler` argument matches the `handler` previously
|
||||
/// passed to [setMockMethodCallHandler].
|
||||
///
|
||||
/// This method is useful for tests or test harnesses that want to assert the
|
||||
/// handler for the specified channel has not been altered by a previous test.
|
||||
///
|
||||
/// Passing null for the `handler` returns true if the handler for the channel
|
||||
/// is not set.
|
||||
bool checkMockMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) => _methodChannelMockHandlers[this] == handler;
|
||||
|
||||
Future<ByteData?> _handleAsMethodCall(ByteData? message, Future<dynamic>? Function(MethodCall call) handler) async {
|
||||
Future<ByteData?> _handleAsMethodCall(ByteData? message, Future<dynamic> Function(MethodCall call) handler) async {
|
||||
final MethodCall call = codec.decodeMethodCall(message);
|
||||
try {
|
||||
return codec.encodeSuccessEnvelope(await handler(call));
|
||||
@ -445,6 +377,9 @@ class MethodChannel {
|
||||
return codec.encodeErrorEnvelope(code: 'error', message: e.toString(), details: null);
|
||||
}
|
||||
}
|
||||
|
||||
// Looking for setMockMethodCallHandler or checkMethodCallHandler?
|
||||
// See this shim package: packages/flutter_test/lib/src/deprecated.dart
|
||||
}
|
||||
|
||||
/// A [MethodChannel] that ignores missing platform plugins.
|
||||
@ -472,7 +407,6 @@ class OptionalMethodChannel extends MethodChannel {
|
||||
final Map<dynamic, dynamic>? result = await invokeMethod<Map<dynamic, dynamic>>(method, arguments);
|
||||
return result?.cast<K, V>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// A named channel for communicating with platform plugins using event streams.
|
||||
|
@ -166,7 +166,6 @@ class RestorationManager extends ChangeNotifier {
|
||||
/// that communications channel, or to set it up differently, as necessary.
|
||||
@protected
|
||||
void initChannels() {
|
||||
assert(!SystemChannels.restoration.checkMethodCallHandler(_methodHandler));
|
||||
SystemChannels.restoration.setMethodCallHandler(_methodHandler);
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,11 @@ class SystemChannels {
|
||||
/// they apply, so that stale messages referencing past transactions can be
|
||||
/// ignored.
|
||||
///
|
||||
/// In debug builds, messages sent with a client ID of -1 are always accepted.
|
||||
/// This allows tests to smuggle messages without having to mock the engine's
|
||||
/// text handling (for example, allowing the engine to still handle the text
|
||||
/// input messages in an integration test).
|
||||
///
|
||||
/// The methods described below are wrapped in a more convenient form by the
|
||||
/// [TextInput] and [TextInputConnection] class.
|
||||
///
|
||||
@ -152,9 +157,15 @@ class SystemChannels {
|
||||
/// is a transaction identifier. Calls for stale transactions should be ignored.
|
||||
///
|
||||
/// * `TextInputClient.updateEditingState`: The user has changed the contents
|
||||
/// of the text control. The second argument is a [String] containing a
|
||||
/// JSON-encoded object with seven keys, in the form expected by
|
||||
/// [TextEditingValue.fromJSON].
|
||||
/// of the text control. The second argument is an object with seven keys,
|
||||
/// in the form expected by [TextEditingValue.fromJSON].
|
||||
///
|
||||
/// * `TextInputClient.updateEditingStateWithTag`: One or more text controls
|
||||
/// were autofilled by the platform's autofill service. The first argument
|
||||
/// (the client ID) is ignored, the second argument is a map of tags to
|
||||
/// objects in the form expected by [TextEditingValue.fromJSON]. See
|
||||
/// [AutofillScope.getAutofillClient] for details on the interpretation of
|
||||
/// the tag.
|
||||
///
|
||||
/// * `TextInputClient.performAction`: The user has triggered an action. The
|
||||
/// second argument is a [String] consisting of the stringification of one
|
||||
@ -165,7 +176,8 @@ class SystemChannels {
|
||||
/// one. The framework should call `TextInput.setClient` and
|
||||
/// `TextInput.setEditingState` again with its most recent information. If
|
||||
/// there is no existing state on the framework side, the call should
|
||||
/// fizzle.
|
||||
/// fizzle. (This call is made without a client ID; indeed, without any
|
||||
/// arguments at all.)
|
||||
///
|
||||
/// * `TextInputClient.onConnectionClosed`: The text input connection closed
|
||||
/// on the platform side. For example the application is moved to
|
||||
|
@ -1327,9 +1327,11 @@ class TextInput {
|
||||
|
||||
final List<dynamic> args = methodCall.arguments as List<dynamic>;
|
||||
|
||||
// The updateEditingStateWithTag request (autofill) can come up even to a
|
||||
// text field that doesn't have a connection.
|
||||
if (method == 'TextInputClient.updateEditingStateWithTag') {
|
||||
assert(_currentConnection!._client != null);
|
||||
final TextInputClient client = _currentConnection!._client;
|
||||
assert(client != null);
|
||||
final AutofillScope? scope = client.currentAutofillScope;
|
||||
final Map<String, dynamic> editingValue = args[1] as Map<String, dynamic>;
|
||||
for (final String tag in editingValue.keys) {
|
||||
@ -1343,9 +1345,22 @@ class TextInput {
|
||||
}
|
||||
|
||||
final int client = args[0] as int;
|
||||
// The incoming message was for a different client.
|
||||
if (client != _currentConnection!._id)
|
||||
return;
|
||||
if (client != _currentConnection!._id) {
|
||||
// If the client IDs don't match, the incoming message was for a different
|
||||
// client.
|
||||
bool debugAllowAnyway = false;
|
||||
assert(() {
|
||||
// In debug builds we allow "-1" as a magical client ID that ignores
|
||||
// this verification step so that tests can always get through, even
|
||||
// when they are not mocking the engine side of text input.
|
||||
if (client == -1)
|
||||
debugAllowAnyway = true;
|
||||
return true;
|
||||
}());
|
||||
if (!debugAllowAnyway)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case 'TextInputClient.updateEditingState':
|
||||
_currentConnection!._client.updateEditingValue(TextEditingValue.fromJSON(args[1] as Map<String, dynamic>));
|
||||
@ -1502,7 +1517,7 @@ class TextInput {
|
||||
assert(shouldSave != null);
|
||||
TextInput._instance._channel.invokeMethod<void>(
|
||||
'TextInput.finishAutofillContext',
|
||||
shouldSave ,
|
||||
shouldSave,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2112,7 +2112,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
if (_hasFocus) {
|
||||
_openInputConnection();
|
||||
} else {
|
||||
widget.focusNode.requestFocus();
|
||||
widget.focusNode.requestFocus(); // This eventually calls _openInputConnection also, see _handleFocusChanged.
|
||||
}
|
||||
}
|
||||
|
||||
@ -2360,11 +2360,13 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
||||
|
||||
void _cursorWaitForStart(Timer timer) {
|
||||
assert(_kCursorBlinkHalfPeriod > _fadeDuration);
|
||||
assert(!EditableText.debugDeterministicCursor);
|
||||
_cursorTimer?.cancel();
|
||||
_cursorTimer = Timer.periodic(_kCursorBlinkHalfPeriod, _cursorTick);
|
||||
}
|
||||
|
||||
void _startCursorTimer() {
|
||||
assert(_cursorTimer == null);
|
||||
_targetCursorVisibility = true;
|
||||
_cursorBlinkOpacityController.value = 1.0;
|
||||
if (EditableText.debugDeterministicCursor)
|
||||
|
@ -201,7 +201,7 @@ void main() {
|
||||
final List<int> selectedItems = <int>[];
|
||||
final List<MethodCall> systemCalls = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
systemCalls.add(methodCall);
|
||||
});
|
||||
|
||||
@ -254,7 +254,7 @@ void main() {
|
||||
final List<int> selectedItems = <int>[];
|
||||
final List<MethodCall> systemCalls = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
systemCalls.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -175,7 +175,7 @@ void main() {
|
||||
testWidgets('drag past threshold triggers refresh task', (WidgetTester tester) async {
|
||||
final List<MethodCall> platformCallLog = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
platformCallLog.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -132,9 +132,9 @@ void main() {
|
||||
await tester.pump();
|
||||
|
||||
int hapticFeedbackCalls = 0;
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'HapticFeedback.vibrate') {
|
||||
hapticFeedbackCalls++;
|
||||
hapticFeedbackCalls += 1;
|
||||
}
|
||||
});
|
||||
|
||||
@ -692,9 +692,9 @@ void main() {
|
||||
await tester.pump();
|
||||
|
||||
int hapticFeedbackCalls = 0;
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'HapticFeedback.vibrate') {
|
||||
hapticFeedbackCalls++;
|
||||
hapticFeedbackCalls += 1;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -47,7 +47,7 @@ void main() {
|
||||
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -87,7 +87,7 @@ void main() {
|
||||
bool value2 = false;
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -154,7 +154,7 @@ void main() {
|
||||
bool value = false;
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -192,7 +192,7 @@ void main() {
|
||||
bool value = false;
|
||||
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -162,7 +162,7 @@ class PathPointsMatcher extends Matcher {
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final MockClipboard mockClipboard = MockClipboard();
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
|
||||
// Returns the first RenderEditable.
|
||||
RenderEditable findRenderEditable(WidgetTester tester) {
|
||||
@ -3228,7 +3228,7 @@ void main() {
|
||||
|
||||
testWidgets('text field respects keyboardAppearance from theme', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -3251,7 +3251,7 @@ void main() {
|
||||
|
||||
testWidgets('text field can override keyboardAppearance from theme', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -66,7 +66,7 @@ const _LongCupertinoLocalizations longLocalizations = _LongCupertinoLocalization
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final MockClipboard mockClipboard = MockClipboard();
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
|
||||
// Returns true iff the button is visually enabled.
|
||||
bool appearsEnabled(WidgetTester tester, String text) {
|
||||
|
@ -21,7 +21,8 @@ class TestServiceExtensionsBinding extends BindingBase
|
||||
PaintingBinding,
|
||||
SemanticsBinding,
|
||||
RendererBinding,
|
||||
WidgetsBinding {
|
||||
WidgetsBinding,
|
||||
TestDefaultBinaryMessengerBinding {
|
||||
|
||||
final Map<String, ServiceExtensionCallback> extensions = <String, ServiceExtensionCallback>{};
|
||||
|
||||
@ -467,7 +468,7 @@ void main() {
|
||||
bool completed;
|
||||
|
||||
completed = false;
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
|
||||
expect(utf8.decode(message!.buffer.asUint8List()), 'test');
|
||||
completed = true;
|
||||
return ByteData(5); // 0x0000000000
|
||||
@ -494,7 +495,7 @@ void main() {
|
||||
});
|
||||
expect(data, isFalse);
|
||||
expect(completed, isTrue);
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', null);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', null);
|
||||
});
|
||||
|
||||
test('Service extensions - exit', () async {
|
||||
|
@ -2,12 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Logically this file should be part of `gesture_binding_test.dart` but is here
|
||||
// due to conflict of `flutter_test` and `package:test`.
|
||||
// See https://github.com/dart-lang/matcher/issues/98
|
||||
// TODO(CareF): Consider combine this file back to `gesture_binding_test.dart`
|
||||
// after #98 is fixed.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:clock/clock.dart';
|
||||
|
@ -267,7 +267,7 @@ void main() {
|
||||
testWidgets('has semantic events', (WidgetTester tester) async {
|
||||
dynamic semanticEvent;
|
||||
bool? checkboxValue = false;
|
||||
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
|
||||
semanticEvent = message;
|
||||
});
|
||||
final SemanticsTester semanticsTester = SemanticsTester(tester);
|
||||
@ -300,7 +300,7 @@ void main() {
|
||||
});
|
||||
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
|
||||
|
||||
SystemChannels.accessibility.setMockMessageHandler(null);
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
|
||||
semanticsTester.dispose();
|
||||
});
|
||||
|
||||
|
@ -27,14 +27,14 @@ void main () {
|
||||
|
||||
setUp(() {
|
||||
semanticEvents = <Map<String, Object>>[];
|
||||
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
|
||||
final Map<dynamic, dynamic> typedMessage = message as Map<dynamic, dynamic>;
|
||||
semanticEvents.add(typedMessage.cast<String, Object>());
|
||||
});
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
SystemChannels.accessibility.setMockMessageHandler(null);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
|
||||
});
|
||||
|
||||
testWidgets('forTap', (WidgetTester tester) async {
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// Tracks how often feedback has been requested since its instantiation.
|
||||
///
|
||||
@ -10,13 +11,7 @@ import 'package:flutter/services.dart';
|
||||
/// cannot be used in combination with other classes that do the same.
|
||||
class FeedbackTester {
|
||||
FeedbackTester() {
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
if (methodCall.method == 'HapticFeedback.vibrate')
|
||||
_hapticCount++;
|
||||
if (methodCall.method == 'SystemSound.play' &&
|
||||
methodCall.arguments == SystemSoundType.click.toString())
|
||||
_clickSoundCount++;
|
||||
});
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, _handler);
|
||||
}
|
||||
|
||||
/// Number of times haptic feedback was requested (vibration).
|
||||
@ -27,8 +22,17 @@ class FeedbackTester {
|
||||
int get clickSoundCount => _clickSoundCount;
|
||||
int _clickSoundCount = 0;
|
||||
|
||||
Future<void> _handler(MethodCall methodCall) async {
|
||||
if (methodCall.method == 'HapticFeedback.vibrate')
|
||||
_hapticCount++;
|
||||
if (methodCall.method == 'SystemSound.play' &&
|
||||
methodCall.arguments == SystemSoundType.click.toString())
|
||||
_clickSoundCount++;
|
||||
}
|
||||
|
||||
/// Stops tracking.
|
||||
void dispose() {
|
||||
SystemChannels.platform.setMockMethodCallHandler(null);
|
||||
assert(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(SystemChannels.platform.name, _handler));
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
|
||||
}
|
||||
}
|
||||
|
@ -241,9 +241,9 @@ void main() {
|
||||
|
||||
// Fill the clipboard so that the Paste option is available in the text
|
||||
// selection menu.
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
|
||||
addTearDown(() => SystemChannels.platform.setMockMethodCallHandler(null));
|
||||
addTearDown(() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null));
|
||||
|
||||
await tester.pumpWidget(_inputDatePickerField(autofocus: true));
|
||||
await tester.pumpAndSettle();
|
||||
|
@ -537,7 +537,7 @@ void main() {
|
||||
final Key key = UniqueKey();
|
||||
dynamic semanticEvent;
|
||||
int? radioValue = 2;
|
||||
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
|
||||
semanticEvent = message;
|
||||
});
|
||||
|
||||
@ -568,7 +568,7 @@ void main() {
|
||||
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
|
||||
|
||||
semantics.dispose();
|
||||
SystemChannels.accessibility.setMockMessageHandler(null);
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
|
||||
});
|
||||
|
||||
testWidgets('RadioListTile can autofocus unless disabled.', (WidgetTester tester) async {
|
||||
|
@ -292,7 +292,7 @@ void main() {
|
||||
final Key key = UniqueKey();
|
||||
dynamic semanticEvent;
|
||||
int? radioValue = 2;
|
||||
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
|
||||
semanticEvent = message;
|
||||
});
|
||||
|
||||
@ -319,7 +319,7 @@ void main() {
|
||||
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
|
||||
|
||||
semantics.dispose();
|
||||
SystemChannels.accessibility.setMockMessageHandler(null);
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
|
||||
});
|
||||
|
||||
testWidgets('Radio ink ripple is displayed correctly', (WidgetTester tester) async {
|
||||
|
@ -32,12 +32,12 @@ void main() {
|
||||
setUp(() async {
|
||||
// Fill the clipboard so that the Paste option is available in the text
|
||||
// selection menu.
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
SystemChannels.platform.setMockMethodCallHandler(null);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
|
||||
});
|
||||
|
||||
testWidgets('Can open and close search', (WidgetTester tester) async {
|
||||
|
@ -577,7 +577,7 @@ void main() {
|
||||
testWidgets('switch has semantic events', (WidgetTester tester) async {
|
||||
dynamic semanticEvent;
|
||||
bool value = false;
|
||||
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
|
||||
semanticEvent = message;
|
||||
});
|
||||
final SemanticsTester semanticsTester = SemanticsTester(tester);
|
||||
@ -615,13 +615,13 @@ void main() {
|
||||
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
|
||||
|
||||
semanticsTester.dispose();
|
||||
SystemChannels.accessibility.setMockMessageHandler(null);
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
|
||||
});
|
||||
|
||||
testWidgets('switch sends semantic events from parent if fully merged', (WidgetTester tester) async {
|
||||
dynamic semanticEvent;
|
||||
bool value = false;
|
||||
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
|
||||
semanticEvent = message;
|
||||
});
|
||||
final SemanticsTester semanticsTester = SemanticsTester(tester);
|
||||
@ -665,7 +665,7 @@ void main() {
|
||||
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
|
||||
|
||||
semanticsTester.dispose();
|
||||
SystemChannels.accessibility.setMockMessageHandler(null);
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
|
||||
});
|
||||
|
||||
testWidgets('Switch.adaptive', (WidgetTester tester) async {
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui' as ui show window, BoxHeightStyle, BoxWidthStyle;
|
||||
|
||||
@ -164,14 +165,20 @@ void main() {
|
||||
|
||||
setUp(() async {
|
||||
debugResetSemanticsIdCounter();
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(
|
||||
SystemChannels.platform,
|
||||
mockClipboard.handleMethodCall,
|
||||
);
|
||||
// Fill the clipboard so that the Paste option is available in the text
|
||||
// selection menu.
|
||||
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
SystemChannels.platform.setMockMethodCallHandler(null);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(
|
||||
SystemChannels.platform,
|
||||
null,
|
||||
);
|
||||
});
|
||||
|
||||
final Key textFieldKey = UniqueKey();
|
||||
@ -339,7 +346,7 @@ void main() {
|
||||
|
||||
testWidgets('TextField has consistent size', (WidgetTester tester) async {
|
||||
final Key textFieldKey = UniqueKey();
|
||||
late String textFieldValue;
|
||||
String? textFieldValue;
|
||||
|
||||
await tester.pumpWidget(
|
||||
overlay(
|
||||
@ -362,15 +369,16 @@ void main() {
|
||||
|
||||
Future<void> checkText(String testValue) async {
|
||||
return TestAsyncUtils.guard(() async {
|
||||
expect(textFieldValue, isNull);
|
||||
await tester.enterText(find.byType(TextField), testValue);
|
||||
// Check that the onChanged event handler fired.
|
||||
expect(textFieldValue, equals(testValue));
|
||||
textFieldValue = null;
|
||||
await skipPastScrollingAnimation(tester);
|
||||
});
|
||||
}
|
||||
|
||||
await checkText(' ');
|
||||
|
||||
expect(findTextFieldBox(), equals(inputBox));
|
||||
expect(inputBox.size, equals(emptyInputSize));
|
||||
|
||||
@ -416,6 +424,8 @@ void main() {
|
||||
text: 'X',
|
||||
selection: TextSelection.collapsed(offset: 1),
|
||||
));
|
||||
await tester.idle();
|
||||
expect(tester.state(find.byType(EditableText)), editableText);
|
||||
await checkCursorToggle();
|
||||
});
|
||||
|
||||
@ -4694,8 +4704,8 @@ void main() {
|
||||
);
|
||||
|
||||
String clipboardContent = '';
|
||||
SystemChannels.platform
|
||||
.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.setData')
|
||||
clipboardContent = methodCall.arguments['text'] as String;
|
||||
else if (methodCall.method == 'Clipboard.getData')
|
||||
@ -4767,8 +4777,8 @@ void main() {
|
||||
);
|
||||
|
||||
String clipboardContent = '';
|
||||
SystemChannels.platform
|
||||
.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.setData')
|
||||
clipboardContent = methodCall.arguments['text'] as String;
|
||||
else if (methodCall.method == 'Clipboard.getData')
|
||||
@ -4840,8 +4850,8 @@ void main() {
|
||||
);
|
||||
|
||||
const String clipboardContent = 'I love Flutter!';
|
||||
SystemChannels.platform
|
||||
.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.getData')
|
||||
return <String, dynamic>{'text': clipboardContent};
|
||||
return null;
|
||||
@ -4890,8 +4900,8 @@ void main() {
|
||||
maxLines: 3,
|
||||
);
|
||||
String clipboardContent = '';
|
||||
SystemChannels.platform
|
||||
.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.setData')
|
||||
clipboardContent = methodCall.arguments['text'] as String;
|
||||
else if (methodCall.method == 'Clipboard.getData')
|
||||
@ -4964,8 +4974,8 @@ void main() {
|
||||
obscureText: true,
|
||||
);
|
||||
String clipboardContent = '';
|
||||
SystemChannels.platform
|
||||
.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.setData')
|
||||
clipboardContent = methodCall.arguments['text'] as String;
|
||||
else if (methodCall.method == 'Clipboard.getData')
|
||||
@ -9370,8 +9380,8 @@ void main() {
|
||||
);
|
||||
|
||||
bool triedToReadClipboard = false;
|
||||
SystemChannels.platform
|
||||
.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger
|
||||
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.getData') {
|
||||
triedToReadClipboard = true;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class MockClipboard {
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final MockClipboard mockClipboard = MockClipboard();
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
|
||||
setUp(() async {
|
||||
// Fill the clipboard so that the Paste option is available in the text
|
||||
|
@ -28,7 +28,7 @@ class MockClipboard {
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final MockClipboard mockClipboard = MockClipboard();
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
|
||||
setUp(() async {
|
||||
await Clipboard.setData(const ClipboardData(text: 'clipboard data'));
|
||||
|
@ -1193,7 +1193,7 @@ void main() {
|
||||
|
||||
testWidgets('has semantic events', (WidgetTester tester) async {
|
||||
final List<dynamic> semanticEvents = <dynamic>[];
|
||||
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
|
||||
semanticEvents.add(message);
|
||||
});
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
@ -1230,7 +1230,7 @@ void main() {
|
||||
},
|
||||
]));
|
||||
semantics.dispose();
|
||||
SystemChannels.accessibility.setMockMessageHandler(null);
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
|
||||
});
|
||||
testWidgets('default Tooltip debugFillProperties', (WidgetTester tester) async {
|
||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||
|
@ -1153,7 +1153,7 @@ void main() {
|
||||
|
||||
testWidgets('has semantic events by default - ThemeData.tooltipTheme', (WidgetTester tester) async {
|
||||
final List<dynamic> semanticEvents = <dynamic>[];
|
||||
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
|
||||
semanticEvents.add(message);
|
||||
});
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
@ -1191,12 +1191,12 @@ void main() {
|
||||
},
|
||||
]));
|
||||
semantics.dispose();
|
||||
SystemChannels.accessibility.setMockMessageHandler(null);
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
|
||||
});
|
||||
|
||||
testWidgets('has semantic events by default - TooltipTheme', (WidgetTester tester) async {
|
||||
final List<dynamic> semanticEvents = <dynamic>[];
|
||||
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
|
||||
semanticEvents.add(message);
|
||||
});
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
@ -1236,7 +1236,7 @@ void main() {
|
||||
},
|
||||
]));
|
||||
semantics.dispose();
|
||||
SystemChannels.accessibility.setMockMessageHandler(null);
|
||||
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
|
||||
});
|
||||
|
||||
testWidgets('default Tooltip debugFillProperties', (WidgetTester tester) async {
|
||||
|
@ -12,11 +12,11 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
final TestRenderBinding binding = TestRenderBinding();
|
||||
test('Flutter dispatches first frame event on the web only', () async {
|
||||
final Completer<void> completer = Completer<void>();
|
||||
final TestRenderBinding binding = TestRenderBinding();
|
||||
const MethodChannel firstFrameChannel = MethodChannel('flutter/service_worker');
|
||||
firstFrameChannel.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
binding.defaultBinaryMessenger.setMockMethodCallHandler(firstFrameChannel, (MethodCall methodCall) async {
|
||||
completer.complete();
|
||||
});
|
||||
|
||||
@ -27,4 +27,10 @@ void main() {
|
||||
}, skip: !kIsWeb);
|
||||
}
|
||||
|
||||
class TestRenderBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding {}
|
||||
class TestRenderBinding extends BindingBase
|
||||
with SchedulerBinding,
|
||||
ServicesBinding,
|
||||
GestureBinding,
|
||||
SemanticsBinding,
|
||||
RendererBinding,
|
||||
TestDefaultBinaryMessengerBinding { }
|
||||
|
@ -56,14 +56,14 @@ void main() {
|
||||
|
||||
setUp(() {
|
||||
_binding.postFrameCallbacks.clear();
|
||||
SystemChannels.mouseCursor.setMockMethodCallHandler((MethodCall call) async {
|
||||
_binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, (MethodCall call) async {
|
||||
if (_methodCallHandler != null)
|
||||
return _methodCallHandler!(call);
|
||||
});
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
SystemChannels.mouseCursor.setMockMethodCallHandler(null);
|
||||
_binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, null);
|
||||
});
|
||||
|
||||
test('Should work on platforms that does not support mouse cursor', () async {
|
||||
|
@ -9,6 +9,7 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart' show TestDefaultBinaryMessengerBinding;
|
||||
|
||||
class _TestHitTester extends RenderBox {
|
||||
_TestHitTester(this.hitTestOverride);
|
||||
@ -24,7 +25,7 @@ class _TestHitTester extends RenderBox {
|
||||
// A binding used to test MouseTracker, allowing the test to override hit test
|
||||
// searching.
|
||||
class TestMouseTrackerFlutterBinding extends BindingBase
|
||||
with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding {
|
||||
with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding, TestDefaultBinaryMessengerBinding {
|
||||
@override
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
|
@ -9,12 +9,12 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart' show EnginePhase, fail;
|
||||
import 'package:flutter_test/flutter_test.dart' show TestDefaultBinaryMessengerBinding, EnginePhase, fail;
|
||||
|
||||
export 'package:flutter/foundation.dart' show FlutterError, FlutterErrorDetails;
|
||||
export 'package:flutter_test/flutter_test.dart' show EnginePhase;
|
||||
export 'package:flutter_test/flutter_test.dart' show TestDefaultBinaryMessengerBinding, EnginePhase;
|
||||
|
||||
class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding {
|
||||
class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, TestDefaultBinaryMessengerBinding {
|
||||
/// Creates a binding for testing rendering library functionality.
|
||||
///
|
||||
/// If [onErrors] is not null, it is called if [FlutterError] caught any errors
|
||||
|
@ -13,12 +13,13 @@ void main() {
|
||||
|
||||
test('Semantic announcement', () async {
|
||||
final List<Map<dynamic, dynamic>> log = <Map<dynamic, dynamic>>[];
|
||||
|
||||
Future<dynamic> handleMessage(dynamic mockMessage) async {
|
||||
final Map<dynamic, dynamic> message = mockMessage as Map<dynamic, dynamic>;
|
||||
log.add(message);
|
||||
}
|
||||
|
||||
SystemChannels.accessibility.setMockMessageHandler(handleMessage);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, handleMessage);
|
||||
|
||||
await SemanticsService.announce('announcement 1', TextDirection.ltr);
|
||||
await SemanticsService.announce('announcement 2', TextDirection.rtl);
|
||||
|
@ -191,15 +191,6 @@ class FakeTextChannel implements MethodChannel {
|
||||
incoming = handler;
|
||||
}
|
||||
|
||||
@override
|
||||
bool checkMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
void setMockMethodCallHandler(Future<void>? Function(MethodCall call)? handler) => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
bool checkMockMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
|
||||
|
||||
void validateOutgoingMethodCalls(List<MethodCall> calls) {
|
||||
expect(outgoingCalls.length, calls.length);
|
||||
bool hasError = false;
|
||||
|
@ -34,7 +34,7 @@ L2Paragraph2
|
||||
|
||||
L2Paragraph3''';
|
||||
|
||||
const String licenses = '''
|
||||
const String combinedLicenses = '''
|
||||
$license1
|
||||
--------------------------------------------------------------------------------
|
||||
$license2
|
||||
@ -42,29 +42,25 @@ $license2
|
||||
|
||||
class TestBinding extends BindingBase with SchedulerBinding, ServicesBinding {
|
||||
@override
|
||||
BinaryMessenger createBinaryMessenger() {
|
||||
return super.createBinaryMessenger()
|
||||
..setMockMessageHandler('flutter/assets', (ByteData? message) async {
|
||||
if (const StringCodec().decodeMessage(message) == 'NOTICES') {
|
||||
return const StringCodec().encodeMessage(licenses);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
..setMockMessageHandler('flutter/assets', (ByteData? message) async {
|
||||
if (const StringCodec().decodeMessage(message) == 'NOTICES.Z' && !kIsWeb) {
|
||||
return Uint8List.fromList(gzip.encode(utf8.encode(licenses))).buffer.asByteData();
|
||||
}
|
||||
if (const StringCodec().decodeMessage(message) == 'NOTICES' && kIsWeb) {
|
||||
return const StringCodec().encodeMessage(licenses);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
TestDefaultBinaryMessenger get defaultBinaryMessenger => super.defaultBinaryMessenger as TestDefaultBinaryMessenger;
|
||||
|
||||
@override
|
||||
TestDefaultBinaryMessenger createBinaryMessenger() {
|
||||
return TestDefaultBinaryMessenger(super.createBinaryMessenger());
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
test('Adds rootBundle LICENSES to LicenseRegistry', () async {
|
||||
TestBinding(); // The test binding registers a mock handler that returns licenses for the LICENSE key
|
||||
TestBinding().defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
|
||||
if (const StringCodec().decodeMessage(message) == 'NOTICES.Z' && !kIsWeb) {
|
||||
return Uint8List.fromList(gzip.encode(utf8.encode(combinedLicenses))).buffer.asByteData();
|
||||
}
|
||||
if (const StringCodec().decodeMessage(message) == 'NOTICES' && kIsWeb) {
|
||||
return const StringCodec().encodeMessage(combinedLicenses);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
final List<LicenseEntry> licenses = await LicenseRegistry.licenses.toList();
|
||||
|
||||
|
@ -2,9 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
@ -19,36 +20,39 @@ void main() {
|
||||
}
|
||||
|
||||
test('default binary messenger calls callback once', () async {
|
||||
int count = 0;
|
||||
int countInbound = 0;
|
||||
int countOutbound = 0;
|
||||
const String channel = 'foo';
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
final ByteData bar = _makeByteData('bar');
|
||||
final Completer<void> done = Completer<void>();
|
||||
ServicesBinding.instance!.channelBuffers.push(
|
||||
channel,
|
||||
_makeByteData('bar'),
|
||||
bar,
|
||||
(ByteData? message) async {
|
||||
count += 1;
|
||||
expect(message, isNull);
|
||||
countOutbound += 1;
|
||||
done.complete();
|
||||
},
|
||||
);
|
||||
expect(count, equals(0));
|
||||
await ui.channelBuffers.drain(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
|
||||
callback(null);
|
||||
});
|
||||
expect(count, equals(1));
|
||||
});
|
||||
|
||||
test('can check the handler', () {
|
||||
Future<ByteData> handler(ByteData? call) => Future<ByteData>.value(null);
|
||||
final BinaryMessenger messenger = ServicesBinding.instance!.defaultBinaryMessenger;
|
||||
|
||||
expect(messenger.checkMessageHandler('test_channel', null), true);
|
||||
expect(messenger.checkMessageHandler('test_channel', handler), false);
|
||||
messenger.setMessageHandler('test_channel', handler);
|
||||
expect(messenger.checkMessageHandler('test_channel', handler), true);
|
||||
messenger.setMessageHandler('test_channel', null);
|
||||
expect(countInbound, equals(0));
|
||||
expect(countOutbound, equals(0));
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMessageHandler(
|
||||
channel,
|
||||
(ByteData? message) async {
|
||||
expect(message, bar);
|
||||
countInbound += 1;
|
||||
},
|
||||
);
|
||||
expect(countInbound, equals(0));
|
||||
expect(countOutbound, equals(0));
|
||||
await done.future;
|
||||
expect(countInbound, equals(1));
|
||||
expect(countOutbound, equals(1));
|
||||
});
|
||||
|
||||
test('can check the mock handler', () {
|
||||
Future<ByteData> handler(ByteData? call) => Future<ByteData>.value(null);
|
||||
final BinaryMessenger messenger = ServicesBinding.instance!.defaultBinaryMessenger;
|
||||
final TestDefaultBinaryMessenger messenger = TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger;
|
||||
|
||||
expect(messenger.checkMockMessageHandler('test_channel', null), true);
|
||||
expect(messenger.checkMockMessageHandler('test_channel', handler), false);
|
||||
|
@ -11,7 +11,7 @@ void main() {
|
||||
test('installDeferredComponent test', () async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.deferredComponent.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.deferredComponent, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -27,7 +27,7 @@ void main() {
|
||||
test('uninstallDeferredComponent test', () async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.deferredComponent.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.deferredComponent, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -8,6 +8,7 @@ import 'dart:typed_data';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// Used in internal testing.
|
||||
class FakePlatformViewController extends PlatformViewController {
|
||||
@ -122,7 +123,7 @@ class FakeAndroidViewController implements AndroidViewController {
|
||||
|
||||
class FakeAndroidPlatformViewsController {
|
||||
FakeAndroidPlatformViewsController() {
|
||||
SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall);
|
||||
}
|
||||
|
||||
Iterable<FakeAndroidPlatformView> get views => _views.values;
|
||||
@ -301,7 +302,7 @@ class FakeAndroidPlatformViewsController {
|
||||
|
||||
class FakeIosPlatformViewsController {
|
||||
FakeIosPlatformViewsController() {
|
||||
SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall);
|
||||
}
|
||||
|
||||
Iterable<FakeUiKitView> get views => _views.values;
|
||||
@ -396,7 +397,7 @@ class FakeIosPlatformViewsController {
|
||||
|
||||
class FakeHtmlPlatformViewsController {
|
||||
FakeHtmlPlatformViewsController() {
|
||||
SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall);
|
||||
}
|
||||
|
||||
Iterable<FakeHtmlPlatformView> get views => _views.values;
|
||||
|
@ -11,7 +11,7 @@ void main() {
|
||||
test('Haptic feedback control test', () async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -25,7 +25,7 @@ void main() {
|
||||
Future<void> callAndVerifyHapticFunction(Function hapticFunction, String platformMethodArgument) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -12,7 +12,7 @@ void main() {
|
||||
const MessageCodec<String?> string = StringCodec();
|
||||
const BasicMessageChannel<String?> channel = BasicMessageChannel<String?>('ch', string);
|
||||
test('can send string message and get reply', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch',
|
||||
(ByteData? message) async => string.encodeMessage(string.decodeMessage(message)! + ' world'),
|
||||
);
|
||||
@ -23,7 +23,7 @@ void main() {
|
||||
test('can receive string message and send reply', () async {
|
||||
channel.setMessageHandler((String? message) async => message! + ' world');
|
||||
String? reply;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
'ch',
|
||||
const StringCodec().encodeMessage('hello'),
|
||||
(ByteData? replyBinary) {
|
||||
@ -40,7 +40,7 @@ void main() {
|
||||
const MethodChannel channel = MethodChannel('ch7', jsonMethod);
|
||||
const OptionalMethodChannel optionalMethodChannel = OptionalMethodChannel('ch8', jsonMethod);
|
||||
test('can invoke method and get result', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch7',
|
||||
(ByteData? message) async {
|
||||
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
|
||||
@ -56,7 +56,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('can invoke list method and get result', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch7',
|
||||
(ByteData? message) async {
|
||||
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
|
||||
@ -72,7 +72,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('can invoke list method and get null result', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch7',
|
||||
(ByteData? message) async {
|
||||
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
|
||||
@ -87,7 +87,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('can invoke map method and get result', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch7',
|
||||
(ByteData? message) async {
|
||||
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
|
||||
@ -103,7 +103,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('can invoke map method and get null result', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch7',
|
||||
(ByteData? message) async {
|
||||
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
|
||||
@ -118,7 +118,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('can invoke method and get error', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch7',
|
||||
(ByteData? message) async {
|
||||
return jsonMessage.encodeMessage(<dynamic>[
|
||||
@ -141,7 +141,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('can invoke unimplemented method', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch7',
|
||||
(ByteData? message) async => null,
|
||||
);
|
||||
@ -157,7 +157,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('can invoke unimplemented method (optional)', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch8',
|
||||
(ByteData? message) async => null,
|
||||
);
|
||||
@ -169,7 +169,7 @@ void main() {
|
||||
channel.setMethodCallHandler(null);
|
||||
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
|
||||
ByteData? envelope;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
envelope = result;
|
||||
});
|
||||
await null; // just in case there's something async happening
|
||||
@ -179,7 +179,7 @@ void main() {
|
||||
test('can handle method call with no registered plugin (setting after)', () async {
|
||||
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
|
||||
ByteData? envelope;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
envelope = result;
|
||||
});
|
||||
channel.setMethodCallHandler(null);
|
||||
@ -193,7 +193,7 @@ void main() {
|
||||
});
|
||||
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
|
||||
ByteData? envelope;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
envelope = result;
|
||||
});
|
||||
expect(envelope, isNull);
|
||||
@ -203,7 +203,7 @@ void main() {
|
||||
channel.setMethodCallHandler((MethodCall call) async => '${call.arguments}, world');
|
||||
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
|
||||
ByteData? envelope;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
envelope = result;
|
||||
});
|
||||
expect(jsonMethod.decodeEnvelope(envelope!), equals('hello, world'));
|
||||
@ -215,7 +215,7 @@ void main() {
|
||||
});
|
||||
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
|
||||
ByteData? envelope;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
envelope = result;
|
||||
});
|
||||
try {
|
||||
@ -235,7 +235,7 @@ void main() {
|
||||
});
|
||||
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
|
||||
ByteData? envelope;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
|
||||
envelope = result;
|
||||
});
|
||||
try {
|
||||
@ -249,24 +249,14 @@ void main() {
|
||||
}
|
||||
});
|
||||
|
||||
test('can check the handler', () {
|
||||
test('can check the mock handler', () async {
|
||||
Future<dynamic> handler(MethodCall call) => Future<dynamic>.value(null);
|
||||
|
||||
const MethodChannel channel = MethodChannel('test_handler');
|
||||
expect(channel.checkMethodCallHandler(null), true);
|
||||
expect(channel.checkMethodCallHandler(handler), false);
|
||||
channel.setMethodCallHandler(handler);
|
||||
expect(channel.checkMethodCallHandler(handler), true);
|
||||
});
|
||||
|
||||
test('can check the mock handler', () {
|
||||
Future<dynamic> handler(MethodCall call) => Future<dynamic>.value(null);
|
||||
|
||||
const MethodChannel channel = MethodChannel('test_handler');
|
||||
expect(channel.checkMockMethodCallHandler(null), true);
|
||||
expect(channel.checkMockMethodCallHandler(handler), false);
|
||||
channel.setMockMethodCallHandler(handler);
|
||||
expect(channel.checkMockMethodCallHandler(handler), true);
|
||||
expect(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel.name, null), true);
|
||||
expect(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel.name, handler), false);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(channel, handler);
|
||||
expect(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel.name, handler), true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -275,7 +265,7 @@ void main() {
|
||||
const MethodCodec jsonMethod = JSONMethodCodec();
|
||||
const EventChannel channel = EventChannel('ch', jsonMethod);
|
||||
void emitEvent(ByteData? event) {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
'ch',
|
||||
event,
|
||||
(ByteData? reply) {},
|
||||
@ -283,7 +273,7 @@ void main() {
|
||||
}
|
||||
test('can receive event stream', () async {
|
||||
bool canceled = false;
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch',
|
||||
(ByteData? message) async {
|
||||
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
|
||||
@ -308,7 +298,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('can receive error event', () async {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'ch',
|
||||
(ByteData? message) async {
|
||||
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
|
||||
|
@ -7,24 +7,23 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('Mock binary message handler control test', () async {
|
||||
// Initialize all bindings because defaultBinaryMessenger.send() needs a window.
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
test('Mock binary message handler control test', () async {
|
||||
final List<ByteData?> log = <ByteData>[];
|
||||
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', (ByteData? message) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', (ByteData? message) async {
|
||||
log.add(message);
|
||||
return null;
|
||||
});
|
||||
|
||||
final ByteData message = ByteData(2)..setUint16(0, 0xABCD);
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.send('test1', message);
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.send('test1', message);
|
||||
expect(log, equals(<ByteData>[message]));
|
||||
log.clear();
|
||||
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', null);
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.send('test1', message);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', null);
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.send('test1', message);
|
||||
expect(log, isEmpty);
|
||||
});
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -30,6 +29,7 @@ void main() {
|
||||
RawKeyboard.instance.removeListener(handleKey);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('No character is produced for non-printables', (WidgetTester tester) async {
|
||||
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'web']) {
|
||||
void handleKey(RawKeyEvent event) {
|
||||
@ -40,6 +40,7 @@ void main() {
|
||||
RawKeyboard.instance.removeListener(handleKey);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('keysPressed is maintained', (WidgetTester tester) async {
|
||||
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'ios']) {
|
||||
RawKeyboard.instance.clearKeysPressed();
|
||||
@ -209,7 +210,7 @@ void main() {
|
||||
// when this event is received, but it's not in keysPressed yet.
|
||||
data['modifiers'] |= RawKeyEventDataMacOs.modifierLeftShift | RawKeyEventDataMacOs.modifierShift;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -234,7 +235,7 @@ void main() {
|
||||
// when this event is received, but it's not in keysPressed yet.
|
||||
data['modifiers'] |= RawKeyEventDataMacOs.modifierLeftShift | RawKeyEventDataMacOs.modifierShift;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -259,7 +260,7 @@ void main() {
|
||||
// when this event is received, but it's not in keysPressed yet.
|
||||
data['modifiers'] |= RawKeyEventDataWindows.modifierLeftShift | RawKeyEventDataWindows.modifierShift;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -284,7 +285,7 @@ void main() {
|
||||
// when this event is received, but it's not in keysPressed yet.
|
||||
data['metaState'] |= RawKeyEventDataAndroid.modifierLeftShift | RawKeyEventDataAndroid.modifierShift;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -309,7 +310,7 @@ void main() {
|
||||
// when this event is received, but it's not in keysPressed yet.
|
||||
data['modifiers'] |= RawKeyEventDataFuchsia.modifierLeftShift;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -334,7 +335,7 @@ void main() {
|
||||
// when this event is received, but it's not in keysPressed yet.
|
||||
data['modifiers'] |= GLFWKeyHelper.modifierShift;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -364,7 +365,7 @@ void main() {
|
||||
isDown: true,
|
||||
)..['metaState'] |= RawKeyEventDataWeb.modifierShift;
|
||||
// Dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -456,7 +457,7 @@ void main() {
|
||||
RawKeyEventDataAndroid.modifierControl |
|
||||
RawKeyEventDataAndroid.modifierMeta;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -494,7 +495,7 @@ void main() {
|
||||
RawKeyEventDataMacOs.modifierCommand |
|
||||
RawKeyEventDataMacOs.modifierControl;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -570,7 +571,7 @@ void main() {
|
||||
RawKeyEventDataWindows.modifierAlt |
|
||||
RawKeyEventDataWindows.modifierControl;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -607,7 +608,7 @@ void main() {
|
||||
GLFWKeyHelper.modifierControl |
|
||||
GLFWKeyHelper.modifierMeta;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -645,7 +646,7 @@ void main() {
|
||||
RawKeyEventDataWeb.modifierControl |
|
||||
RawKeyEventDataWeb.modifierMeta;
|
||||
// dispatch the modified data.
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {},
|
||||
@ -665,12 +666,6 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('RawKeyboard asserts if no keys are in keysPressed after receiving a key down event', (WidgetTester tester) async {
|
||||
FlutterErrorDetails? errorDetails;
|
||||
final FlutterExceptionHandler? oldHandler = FlutterError.onError;
|
||||
FlutterError.onError = (FlutterErrorDetails details) {
|
||||
errorDetails = details;
|
||||
};
|
||||
|
||||
final Map<String, dynamic> keyEventMessage;
|
||||
if (kIsWeb) {
|
||||
keyEventMessage = const <String, dynamic>{
|
||||
@ -692,19 +687,15 @@ void main() {
|
||||
}
|
||||
|
||||
try {
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger
|
||||
.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(keyEventMessage),
|
||||
(ByteData? data) {},
|
||||
(ByteData? data) { },
|
||||
);
|
||||
} finally {
|
||||
FlutterError.onError = oldHandler;
|
||||
fail('Expected an exception, but did not get one.');
|
||||
} on AssertionError catch (error) {
|
||||
expect(error.toString(), contains('Attempted to send a key down event when no keys are in keysPressed'));
|
||||
}
|
||||
expect(errorDetails, isNotNull);
|
||||
expect(errorDetails!.stack, isNotNull);
|
||||
final String fullErrorMessage = errorDetails.toString().replaceAll('\n', ' ');
|
||||
expect(fullErrorMessage, contains('Attempted to send a key down event when no keys are in keysPressed'));
|
||||
});
|
||||
});
|
||||
|
||||
@ -757,6 +748,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('modifier keys are recognized when combined', () {
|
||||
for (final int modifier in modifierTests.keys) {
|
||||
if (modifier == RawKeyEventDataAndroid.modifierFunction) {
|
||||
@ -799,6 +791,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Printable keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(<String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -817,6 +810,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
|
||||
expect(data.keyLabel, equals('a'));
|
||||
});
|
||||
|
||||
test('Control keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -833,6 +827,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('Modifier keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -850,6 +845,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('DPAD keys from a joystick give physical key mappings', () {
|
||||
final RawKeyEvent joystickDpadDown = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -867,6 +863,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('Arrow keys from a keyboard give correct physical key mappings', () {
|
||||
final RawKeyEvent joystickDpadDown = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -883,6 +880,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('DPAD center from a game pad gives physical key mappings', () {
|
||||
final RawKeyEvent joystickDpadCenter = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -900,6 +898,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.select));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('Device id is read from message', () {
|
||||
final RawKeyEvent joystickDpadCenter = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -915,6 +914,7 @@ void main() {
|
||||
final RawKeyEventDataAndroid data = joystickDpadCenter.data as RawKeyEventDataAndroid;
|
||||
expect(data.deviceId, equals(10));
|
||||
});
|
||||
|
||||
test('Repeat count is passed correctly', () {
|
||||
final RawKeyEvent repeatCountEvent = RawKeyEvent.fromMessage(<String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -931,6 +931,7 @@ void main() {
|
||||
final RawKeyEventDataAndroid data = repeatCountEvent.data as RawKeyEventDataAndroid;
|
||||
expect(data.repeatCount, equals(42));
|
||||
});
|
||||
|
||||
testWidgets('Key events are responded to correctly.', (WidgetTester tester) async {
|
||||
expect(RawKeyboard.instance.keysPressed, isEmpty);
|
||||
// Generate the data for a regular key down event.
|
||||
@ -940,7 +941,7 @@ void main() {
|
||||
isDown: true,
|
||||
);
|
||||
Map<String, dynamic>? message;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {
|
||||
@ -963,7 +964,7 @@ void main() {
|
||||
focusNode.requestFocus();
|
||||
await tester.pump();
|
||||
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {
|
||||
@ -971,7 +972,7 @@ void main() {
|
||||
},
|
||||
);
|
||||
expect(message, equals(<String, dynamic>{ 'handled': true }));
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(SystemChannels.keyEvent.name, null);
|
||||
tester.binding.defaultBinaryMessenger.setMockMessageHandler(SystemChannels.keyEvent.name, null);
|
||||
});
|
||||
}, skip: isBrowser); // This is an Android-specific group.
|
||||
|
||||
@ -1019,6 +1020,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('modifier keys are recognized when combined', () {
|
||||
for (final int modifier in modifierTests.keys) {
|
||||
if (modifier == RawKeyEventDataFuchsia.modifierCapsLock) {
|
||||
@ -1052,6 +1054,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Printable keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(<String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1065,6 +1068,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
|
||||
expect(data.keyLabel, equals('a'));
|
||||
});
|
||||
|
||||
test('Control keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1136,6 +1140,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('modifier keys are recognized when combined', () {
|
||||
for (final int modifier in modifierTests.keys) {
|
||||
if (modifier == RawKeyEventDataMacOs.modifierCapsLock) {
|
||||
@ -1175,6 +1180,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Printable keyboard keys are correctly translated', () {
|
||||
const String unmodifiedCharacter = 'a';
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
@ -1190,6 +1196,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
|
||||
expect(data.keyLabel, equals('a'));
|
||||
});
|
||||
|
||||
test('Control keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1281,6 +1288,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('modifier keys are recognized when combined', () {
|
||||
for (final int modifier in modifierTests.keys) {
|
||||
if (modifier == RawKeyEventDataIos.modifierCapsLock) {
|
||||
@ -1320,6 +1328,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Printable keyboard keys are correctly translated', () {
|
||||
const String unmodifiedCharacter = 'a';
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
@ -1335,6 +1344,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
|
||||
expect(data.keyLabel, equals('a'));
|
||||
});
|
||||
|
||||
test('Control keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1427,6 +1437,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('modifier keys are recognized when combined', () {
|
||||
for (final int modifier in modifierTests.keys) {
|
||||
if (modifier == RawKeyEventDataWindows.modifierCaps) {
|
||||
@ -1466,6 +1477,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Printable keyboard keys are correctly translated', () {
|
||||
const int unmodifiedCharacter = 97; // ASCII value for 'a'.
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
@ -1481,6 +1493,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
|
||||
expect(data.keyLabel, equals('a'));
|
||||
});
|
||||
|
||||
test('Control keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1495,6 +1508,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('Modifier keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1509,6 +1523,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('Unprintable keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent leftArrowKey = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1522,6 +1537,7 @@ void main() {
|
||||
expect(data.physicalKey, equals(PhysicalKeyboardKey.arrowLeft));
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowLeft));
|
||||
});
|
||||
|
||||
testWidgets('Win32 VK_PROCESSKEY events are skipped', (WidgetTester tester) async {
|
||||
const String platform = 'windows';
|
||||
bool lastHandled = true;
|
||||
@ -1620,6 +1636,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('modifier keys are recognized when combined', () {
|
||||
for (final int modifier in modifierTests.keys) {
|
||||
if (modifier == GLFWKeyHelper.modifierControl) {
|
||||
@ -1660,6 +1677,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Printable keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1675,6 +1693,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.keyQ));
|
||||
expect(data.keyLabel, equals('q'));
|
||||
});
|
||||
|
||||
test('Code points with two Unicode scalar values are allowed', () {
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1723,6 +1742,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('Modifier keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1804,6 +1824,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('modifier keys are recognized when combined', () {
|
||||
for (final int modifier in modifierTests.keys) {
|
||||
if (modifier == GtkKeyHelper.modifierControl) {
|
||||
@ -1844,6 +1865,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Printable keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1859,6 +1881,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.keyQ));
|
||||
expect(data.keyLabel, equals('q'));
|
||||
});
|
||||
|
||||
test('Code points with two Unicode scalar values are allowed', () {
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1907,6 +1930,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('Modifier keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -1960,6 +1984,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('modifier keys are recognized when combined', () {
|
||||
for (final int modifier in modifierTests.keys) {
|
||||
if (modifier == RawKeyEventDataWeb.modifierMeta) {
|
||||
@ -1992,6 +2017,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Printable keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -2005,6 +2031,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
|
||||
expect(data.keyLabel, equals('a'));
|
||||
});
|
||||
|
||||
test('Control keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -2017,6 +2044,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('Modifier keyboard keys are correctly translated', () {
|
||||
final RawKeyEvent shiftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
@ -2029,6 +2057,7 @@ void main() {
|
||||
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
|
||||
expect(data.keyLabel, isEmpty);
|
||||
});
|
||||
|
||||
test('Arrow keys from a keyboard give correct physical key mappings', () {
|
||||
final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||
'type': 'keydown',
|
||||
|
@ -18,7 +18,7 @@ void main() {
|
||||
testWidgets('root bucket retrieval', (WidgetTester tester) async {
|
||||
final List<MethodCall> callsToEngine = <MethodCall>[];
|
||||
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
|
||||
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
|
||||
callsToEngine.add(call);
|
||||
return result.future;
|
||||
});
|
||||
@ -64,7 +64,7 @@ void main() {
|
||||
testWidgets('root bucket received from engine before retrieval', (WidgetTester tester) async {
|
||||
SystemChannels.restoration.setMethodCallHandler(null);
|
||||
final List<MethodCall> callsToEngine = <MethodCall>[];
|
||||
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) async {
|
||||
callsToEngine.add(call);
|
||||
});
|
||||
final RestorationManager manager = RestorationManager();
|
||||
@ -83,7 +83,7 @@ void main() {
|
||||
SystemChannels.restoration.setMethodCallHandler(null);
|
||||
final List<MethodCall> callsToEngine = <MethodCall>[];
|
||||
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
|
||||
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
|
||||
callsToEngine.add(call);
|
||||
return result.future;
|
||||
});
|
||||
@ -110,7 +110,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('root bucket is properly replaced when new data is available', (WidgetTester tester) async {
|
||||
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) async {
|
||||
return _createEncodedRestorationData1();
|
||||
});
|
||||
final RestorationManager manager = RestorationManager();
|
||||
@ -152,7 +152,7 @@ void main() {
|
||||
testWidgets('returns null as root bucket when restoration is disabled', (WidgetTester tester) async {
|
||||
final List<MethodCall> callsToEngine = <MethodCall>[];
|
||||
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
|
||||
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
|
||||
callsToEngine.add(call);
|
||||
return result.future;
|
||||
});
|
||||
@ -195,7 +195,7 @@ void main() {
|
||||
testWidgets('flushData', (WidgetTester tester) async {
|
||||
final List<MethodCall> callsToEngine = <MethodCall>[];
|
||||
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
|
||||
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
|
||||
callsToEngine.add(call);
|
||||
return result.future;
|
||||
});
|
||||
@ -230,7 +230,7 @@ void main() {
|
||||
|
||||
testWidgets('isReplacing', (WidgetTester tester) async {
|
||||
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
|
||||
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
|
||||
return result.future;
|
||||
});
|
||||
|
||||
|
@ -7,6 +7,8 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
testWidgets('SystemChrome overlay style test', (WidgetTester tester) async {
|
||||
// The first call is a cache miss and will queue a microtask
|
||||
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
|
||||
@ -24,7 +26,7 @@ void main() {
|
||||
test('setPreferredOrientations control test', () async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -42,7 +44,7 @@ void main() {
|
||||
test('setApplicationSwitcherDescription control test', () async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -60,7 +62,7 @@ void main() {
|
||||
test('setApplicationSwitcherDescription missing plugin', () async {
|
||||
final List<ByteData?> log = <ByteData>[];
|
||||
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/platform', (ByteData? message) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/platform', (ByteData? message) async {
|
||||
log.add(message);
|
||||
});
|
||||
|
||||
@ -74,7 +76,7 @@ void main() {
|
||||
test('setEnabledSystemUIOverlays control test', () async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -12,7 +12,7 @@ void main() {
|
||||
test('System navigator control test', () async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -12,7 +12,7 @@ void main() {
|
||||
test('System sound control test', () async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -442,16 +442,6 @@ class FakeTextChannel implements MethodChannel {
|
||||
@override
|
||||
void setMethodCallHandler(Future<void> Function(MethodCall call)? handler) => incoming = handler;
|
||||
|
||||
@override
|
||||
bool checkMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
|
||||
|
||||
|
||||
@override
|
||||
void setMockMethodCallHandler(Future<void>? Function(MethodCall call)? handler) => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
bool checkMockMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
|
||||
|
||||
void validateOutgoingMethodCalls(List<MethodCall> calls) {
|
||||
expect(outgoingCalls.length, calls.length);
|
||||
bool hasError = false;
|
||||
|
@ -3107,7 +3107,7 @@ Future<void> _testLongPressDraggableHapticFeedback({ required WidgetTester teste
|
||||
bool onDragStartedCalled = false;
|
||||
|
||||
int hapticFeedbackCalls = 0;
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'HapticFeedback.vibrate') {
|
||||
hapticFeedbackCalls++;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ void main() {
|
||||
|
||||
// Populate a fake clipboard.
|
||||
const String clipboardContent = ' ';
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.getData')
|
||||
return const <String, dynamic>{'text': clipboardContent};
|
||||
return null;
|
||||
@ -131,7 +131,7 @@ void main() {
|
||||
|
||||
// Populate a fake clipboard.
|
||||
const String clipboardContent = ' ';
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.getData')
|
||||
return const <String, dynamic>{'text': clipboardContent};
|
||||
return null;
|
||||
@ -853,7 +853,7 @@ void main() {
|
||||
|
||||
// Populate a fake clipboard.
|
||||
const String clipboardContent = 'Hello world!';
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.getData')
|
||||
return const <String, dynamic>{'text': clipboardContent};
|
||||
return null;
|
||||
@ -911,7 +911,7 @@ void main() {
|
||||
|
||||
// Populate a fake clipboard.
|
||||
const String clipboardContent = 'Hello world!';
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.getData')
|
||||
return const <String, dynamic>{'text': clipboardContent};
|
||||
return null;
|
||||
|
@ -65,9 +65,9 @@ class MockClipboard {
|
||||
}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final MockClipboard mockClipboard = MockClipboard();
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
(TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding)
|
||||
.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
|
||||
setUp(() async {
|
||||
debugResetSemanticsIdCounter();
|
||||
@ -1982,7 +1982,7 @@ void main() {
|
||||
await tester.pump(); // An extra pump to allow focus request to go through.
|
||||
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -3234,7 +3234,7 @@ void main() {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/22212.
|
||||
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -3265,7 +3265,7 @@ void main() {
|
||||
|
||||
testWidgets('location of widget is sent on show keyboard', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -3302,7 +3302,7 @@ void main() {
|
||||
|
||||
testWidgets('transform and size is reset when text connection opens', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -3390,7 +3390,7 @@ void main() {
|
||||
|
||||
testWidgets('size and transform are sent when they change', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -3432,7 +3432,7 @@ void main() {
|
||||
|
||||
testWidgets('text styling info is sent on show keyboard', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -3519,7 +3519,7 @@ void main() {
|
||||
await tester.showKeyboard(find.byType(EditableText));
|
||||
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
setState(() {
|
||||
@ -3748,7 +3748,7 @@ void main() {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/22212.
|
||||
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -5720,7 +5720,7 @@ void main() {
|
||||
testWidgets('Synchronous test of local and remote editing values', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/65059
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) {
|
||||
@ -5848,7 +5848,7 @@ void main() {
|
||||
testWidgets('Send text input state to engine when the input formatter rejects user input', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/67828
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) {
|
||||
@ -5927,7 +5927,7 @@ void main() {
|
||||
testWidgets('Repeatedly receiving [TextEditingValue] will not trigger a keyboard request', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/66036
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
final TextEditingController controller = TextEditingController();
|
||||
@ -6048,7 +6048,7 @@ void main() {
|
||||
testWidgets('TextEditingController.clear() behavior test', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/66316
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
final TextEditingController controller = TextEditingController();
|
||||
|
@ -159,7 +159,7 @@ void main() {
|
||||
testWidgets('ModalBarrier plays system alert sound when user tries to dismiss it', (WidgetTester tester) async {
|
||||
final List<String> playedSystemSounds = <String>[];
|
||||
try {
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'SystemSound.play')
|
||||
playedSystemSounds.add(methodCall.arguments as String);
|
||||
});
|
||||
@ -176,7 +176,7 @@ void main() {
|
||||
await tester.tap(find.text('target'), warnIfMissed: false);
|
||||
await tester.pumpWidget(subject);
|
||||
} finally {
|
||||
SystemChannels.platform.setMockMethodCallHandler(null);
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
|
||||
}
|
||||
expect(playedSystemSounds, hasLength(1));
|
||||
expect(playedSystemSounds[0], SystemSoundType.alert.toString());
|
||||
|
@ -1591,7 +1591,7 @@ void main() {
|
||||
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||
await gesture.addPointer(location: const Offset(100, 100));
|
||||
addTearDown(gesture.removePointer);
|
||||
SystemChannels.mouseCursor.setMockMethodCallHandler((_) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, (_) async {
|
||||
logCursors.add('cursor');
|
||||
});
|
||||
|
||||
|
@ -1075,7 +1075,7 @@ void main() {
|
||||
await tester.pump();
|
||||
|
||||
late int lastPlatformViewTextClient;
|
||||
SystemChannels.textInput.setMockMethodCallHandler((MethodCall call) {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall call) {
|
||||
if (call.method == 'TextInput.setPlatformViewClient') {
|
||||
lastPlatformViewTextClient = call.arguments as int;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ void main() {
|
||||
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -110,7 +110,7 @@ void main() {
|
||||
|
||||
testWidgets('Navigator does not report route name by default', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -160,7 +160,7 @@ void main() {
|
||||
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -215,7 +215,7 @@ void main() {
|
||||
|
||||
testWidgets('Nameless routes should send platform messages', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
@ -262,7 +262,7 @@ void main() {
|
||||
|
||||
testWidgets('PlatformRouteInformationProvider reports URL', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -124,7 +124,7 @@ double getOpacity(WidgetTester tester, Finder finder) {
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final MockClipboard mockClipboard = MockClipboard();
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
|
||||
const String kThreeLines =
|
||||
'First line of text is\n'
|
||||
@ -1626,7 +1626,7 @@ void main() {
|
||||
final FocusNode focusNode = FocusNode();
|
||||
|
||||
String clipboardContent = '';
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
if (methodCall.method == 'Clipboard.setData')
|
||||
clipboardContent = methodCall.arguments['text'] as String;
|
||||
else if (methodCall.method == 'Clipboard.getData')
|
||||
|
@ -19,15 +19,15 @@ class MockClipboard {
|
||||
'text': null,
|
||||
};
|
||||
|
||||
Future<dynamic> handleMethodCall(MethodCall methodCall) async {
|
||||
Future<Object?> handleMethodCall(MethodCall methodCall) async {
|
||||
switch (methodCall.method) {
|
||||
case 'Clipboard.getData':
|
||||
if (getDataThrows) {
|
||||
if (getDataThrows)
|
||||
throw Exception();
|
||||
}
|
||||
return _clipboardData;
|
||||
case 'Clipboard.setData':
|
||||
_clipboardData = methodCall.arguments;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -758,11 +758,11 @@ void main() {
|
||||
group('when Clipboard fails', () {
|
||||
setUp(() {
|
||||
final MockClipboard mockClipboard = MockClipboard(getDataThrows: true);
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
SystemChannels.platform.setMockMethodCallHandler(null);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
|
||||
});
|
||||
|
||||
test('Clipboard API failure is gracefully recovered from', () async {
|
||||
@ -778,11 +778,11 @@ void main() {
|
||||
final MockClipboard mockClipboard = MockClipboard();
|
||||
|
||||
setUp(() {
|
||||
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
SystemChannels.platform.setMockMethodCallHandler(null);
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
|
||||
});
|
||||
|
||||
test('update sets value based on clipboard contents', () async {
|
||||
|
@ -36,7 +36,7 @@ void main() {
|
||||
testWidgets('should not pass "null" to setApplicationSwitcherDescription', (WidgetTester tester) async {
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
});
|
||||
|
||||
|
@ -30,7 +30,7 @@ const String _extensionMethodName = 'driver';
|
||||
/// eventually completes to a string response.
|
||||
typedef DataHandler = Future<String> Function(String? message);
|
||||
|
||||
class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
|
||||
class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding, TestDefaultBinaryMessengerBinding {
|
||||
_DriverBinding(this._handler, this._silenceErrors, this._enableTextEntryEmulation, this.finders, this.commands);
|
||||
|
||||
final DataHandler? _handler;
|
||||
@ -51,11 +51,6 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
|
||||
registerWebServiceExtension(extension.call);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
BinaryMessenger createBinaryMessenger() {
|
||||
return TestDefaultBinaryMessenger(super.createBinaryMessenger());
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables Flutter Driver VM service extension.
|
||||
@ -330,11 +325,11 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory,
|
||||
registerTextInput();
|
||||
}
|
||||
|
||||
for(final FinderExtension finder in finders) {
|
||||
for (final FinderExtension finder in finders) {
|
||||
_finderExtensions[finder.finderType] = finder;
|
||||
}
|
||||
|
||||
for(final CommandExtension command in commands) {
|
||||
for (final CommandExtension command in commands) {
|
||||
_commandExtensions[command.commandKind] = command;
|
||||
}
|
||||
}
|
||||
@ -418,7 +413,7 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory,
|
||||
@override
|
||||
Command deserializeCommand(Map<String, String> params, DeserializeFinderFactory finderFactory) {
|
||||
final String? kind = params['command'];
|
||||
if(_commandExtensions.containsKey(kind)) {
|
||||
if (_commandExtensions.containsKey(kind)) {
|
||||
return _commandExtensions[kind]!.deserialize(params, finderFactory, this);
|
||||
}
|
||||
|
||||
@ -434,7 +429,7 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory,
|
||||
@override
|
||||
Future<Result> handleCommand(Command command, WidgetController prober, CreateFinderFactory finderFactory) {
|
||||
final String kind = command.kind;
|
||||
if(_commandExtensions.containsKey(kind)) {
|
||||
if (_commandExtensions.containsKey(kind)) {
|
||||
return _commandExtensions[kind]!.call(command, prober, finderFactory, this);
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@ void main() {
|
||||
'waiting for NoPendingPlatformMessages returns until a single method channel call returns', (WidgetTester tester) async {
|
||||
const MethodChannel channel = MethodChannel('helloChannel', JSONMethodCodec());
|
||||
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 10),
|
||||
@ -313,7 +313,7 @@ void main() {
|
||||
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
|
||||
// Configures channel 1
|
||||
const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel1', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 10),
|
||||
@ -322,7 +322,7 @@ void main() {
|
||||
|
||||
// Configures channel 2
|
||||
const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel2', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 20),
|
||||
@ -362,7 +362,7 @@ void main() {
|
||||
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
|
||||
// Configures channel 1
|
||||
const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel1', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 10),
|
||||
@ -371,7 +371,7 @@ void main() {
|
||||
|
||||
// Configures channel 2
|
||||
const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel2', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 20),
|
||||
@ -413,7 +413,7 @@ void main() {
|
||||
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
|
||||
// Configures channel 1
|
||||
const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel1', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 20),
|
||||
@ -422,7 +422,7 @@ void main() {
|
||||
|
||||
// Configures channel 2
|
||||
const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel2', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 10),
|
||||
|
@ -61,6 +61,7 @@ export 'src/all_elements.dart';
|
||||
export 'src/animation_sheet.dart';
|
||||
export 'src/binding.dart';
|
||||
export 'src/controller.dart';
|
||||
export 'src/deprecated.dart';
|
||||
export 'src/event_simulation.dart';
|
||||
export 'src/finders.dart';
|
||||
export 'src/frame_timing_summarizer.dart';
|
||||
@ -73,6 +74,7 @@ export 'src/restoration.dart';
|
||||
export 'src/stack_manipulation.dart';
|
||||
export 'src/test_async_utils.dart';
|
||||
export 'src/test_compat.dart';
|
||||
export 'src/test_default_binary_messenger.dart';
|
||||
export 'src/test_exception_reporter.dart';
|
||||
export 'src/test_pointer.dart';
|
||||
export 'src/test_text_input.dart';
|
||||
|
@ -13,8 +13,8 @@ import 'package:path/path.dart' as path;
|
||||
// ignore: deprecated_member_use
|
||||
import 'package:test_api/test_api.dart' as test_package;
|
||||
|
||||
|
||||
import 'binding.dart';
|
||||
import 'deprecated.dart';
|
||||
|
||||
/// Ensure the [WidgetsBinding] is initialized.
|
||||
WidgetsBinding ensureInitialized([@visibleForTesting Map<String, String>? environment]) {
|
||||
|
@ -15,8 +15,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart' show TestWindow;
|
||||
import 'package:stack_trace/stack_trace.dart' as stack_trace;
|
||||
// ignore: deprecated_member_use
|
||||
import 'package:test_api/test_api.dart' as test_package;
|
||||
import 'package:test_api/test_api.dart' as test_package; // ignore: deprecated_member_use
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '_binding_io.dart' if (dart.library.html) '_binding_web.dart' as binding;
|
||||
@ -25,6 +24,7 @@ import 'platform.dart';
|
||||
import 'restoration.dart';
|
||||
import 'stack_manipulation.dart';
|
||||
import 'test_async_utils.dart';
|
||||
import 'test_default_binary_messenger.dart';
|
||||
import 'test_exception_reporter.dart';
|
||||
import 'test_text_input.dart';
|
||||
|
||||
@ -79,74 +79,29 @@ enum TestBindingEventSource {
|
||||
|
||||
const Size _kDefaultTestViewportSize = Size(800.0, 600.0);
|
||||
|
||||
/// A [BinaryMessenger] subclass that is used as the default binary messenger
|
||||
/// under testing environment.
|
||||
/// Overrides the [ServicesBinding]'s binary messenger logic to use
|
||||
/// [TestDefaultBinaryMessenger].
|
||||
///
|
||||
/// It tracks status of data sent across the Flutter platform barrier, which is
|
||||
/// useful for testing frameworks to monitor and synchronize against the
|
||||
/// platform messages.
|
||||
class TestDefaultBinaryMessenger extends BinaryMessenger {
|
||||
/// Creates a [TestDefaultBinaryMessenger] instance.
|
||||
///
|
||||
/// The [delegate] instance must not be null.
|
||||
TestDefaultBinaryMessenger(this.delegate): assert(delegate != null);
|
||||
|
||||
/// The delegate [BinaryMessenger].
|
||||
final BinaryMessenger delegate;
|
||||
|
||||
final List<Future<ByteData?>> _pendingMessages = <Future<ByteData?>>[];
|
||||
|
||||
/// The number of incomplete/pending calls sent to the platform channels.
|
||||
int get pendingMessageCount => _pendingMessages.length;
|
||||
|
||||
/// Test bindings that are used by tests that mock message handlers for plugins
|
||||
/// should mix in this binding to enable the use of the
|
||||
/// [TestDefaultBinaryMessenger] APIs.
|
||||
mixin TestDefaultBinaryMessengerBinding on BindingBase, ServicesBinding {
|
||||
@override
|
||||
Future<ByteData?>? send(String channel, ByteData? message) {
|
||||
final Future<ByteData?>? resultFuture = delegate.send(channel, message);
|
||||
if (resultFuture != null) {
|
||||
_pendingMessages.add(resultFuture);
|
||||
resultFuture
|
||||
.catchError((Object error) { /* errors are the responsibility of the caller */ })
|
||||
.whenComplete(() => _pendingMessages.remove(resultFuture));
|
||||
}
|
||||
return resultFuture;
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
/// Returns a Future that completes after all the platform calls are finished.
|
||||
///
|
||||
/// If a new platform message is sent after this method is called, this new
|
||||
/// message is not tracked. Use with [pendingMessageCount] to guarantee no
|
||||
/// pending message calls.
|
||||
Future<void> get platformMessagesFinished {
|
||||
return Future.wait<void>(_pendingMessages);
|
||||
}
|
||||
/// The current [TestDefaultBinaryMessengerBinding], if one has been created.
|
||||
static TestDefaultBinaryMessengerBinding? get instance => _instance;
|
||||
static TestDefaultBinaryMessengerBinding? _instance;
|
||||
|
||||
@override
|
||||
Future<void> handlePlatformMessage(
|
||||
String channel,
|
||||
ByteData? data,
|
||||
ui.PlatformMessageResponseCallback? callback,
|
||||
) {
|
||||
return delegate.handlePlatformMessage(channel, data, callback);
|
||||
}
|
||||
TestDefaultBinaryMessenger get defaultBinaryMessenger => super.defaultBinaryMessenger as TestDefaultBinaryMessenger;
|
||||
|
||||
@override
|
||||
void setMessageHandler(String channel, MessageHandler? handler) {
|
||||
delegate.setMessageHandler(channel, handler);
|
||||
}
|
||||
|
||||
@override
|
||||
bool checkMessageHandler(String channel, MessageHandler? handler) {
|
||||
return delegate.checkMessageHandler(channel, handler);
|
||||
}
|
||||
|
||||
@override
|
||||
void setMockMessageHandler(String channel, MessageHandler? handler) {
|
||||
delegate.setMockMessageHandler(channel, handler);
|
||||
}
|
||||
|
||||
@override
|
||||
bool checkMockMessageHandler(String channel, MessageHandler? handler) {
|
||||
return delegate.checkMockMessageHandler(channel, handler);
|
||||
TestDefaultBinaryMessenger createBinaryMessenger() {
|
||||
return TestDefaultBinaryMessenger(super.createBinaryMessenger());
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +126,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
SemanticsBinding,
|
||||
RendererBinding,
|
||||
PaintingBinding,
|
||||
WidgetsBinding {
|
||||
WidgetsBinding,
|
||||
TestDefaultBinaryMessengerBinding {
|
||||
|
||||
/// Constructor for [TestWidgetsFlutterBinding].
|
||||
///
|
||||
@ -195,9 +151,15 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
|
||||
/// Called by the test framework at the beginning of a widget test to
|
||||
/// prepare the binding for the next test.
|
||||
///
|
||||
/// If [registerTestTextInput] returns true when this method is called,
|
||||
/// the [testTextInput] is configured to simulate the keyboard.
|
||||
void reset() {
|
||||
_restorationManager = null;
|
||||
resetGestureBinding();
|
||||
testTextInput.reset();
|
||||
if (registerTestTextInput)
|
||||
_testTextInput.register();
|
||||
}
|
||||
|
||||
@override
|
||||
@ -237,7 +199,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
@protected
|
||||
bool get overrideHttpClient => true;
|
||||
|
||||
/// Determines whether the binding automatically registers [testTextInput].
|
||||
/// Determines whether the binding automatically registers [testTextInput] as
|
||||
/// a fake keyboard implementation.
|
||||
///
|
||||
/// Unit tests make use of this to mock out text input communication for
|
||||
/// widgets. An integration test would set this to false, to test real IME
|
||||
@ -245,6 +208,19 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
///
|
||||
/// [TestTextInput.isRegistered] reports whether the text input mock is
|
||||
/// registered or not.
|
||||
///
|
||||
/// Some of the properties and methods on [testTextInput] are only valid if
|
||||
/// [registerTestTextInput] returns true when a test starts. If those
|
||||
/// members are accessed when using a binding that sets this flag to false,
|
||||
/// they will throw.
|
||||
///
|
||||
/// If this property returns true when a test ends, the [testTextInput] is
|
||||
/// unregistered.
|
||||
///
|
||||
/// This property should not change the value it returns during the lifetime
|
||||
/// of the binding. Changing the value of this property risks very confusing
|
||||
/// behavior as the [TestTextInput] may be inconsistently registered or
|
||||
/// unregistered.
|
||||
@protected
|
||||
bool get registerTestTextInput => true;
|
||||
|
||||
@ -319,9 +295,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
binding.setupHttpOverrides();
|
||||
}
|
||||
_testTextInput = TestTextInput(onCleared: _resetFocusedEditable);
|
||||
if (registerTestTextInput) {
|
||||
_testTextInput.register();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@ -331,11 +304,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
// doesn't get generated for tests.
|
||||
}
|
||||
|
||||
@override
|
||||
BinaryMessenger createBinaryMessenger() {
|
||||
return TestDefaultBinaryMessenger(super.createBinaryMessenger());
|
||||
}
|
||||
|
||||
/// Whether there is currently a test executing.
|
||||
bool get inTest;
|
||||
|
||||
@ -515,12 +483,20 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
TestTextInput get testTextInput => _testTextInput;
|
||||
late TestTextInput _testTextInput;
|
||||
|
||||
/// The current client of the onscreen keyboard. Callers must pump
|
||||
/// an additional frame after setting this property to complete the
|
||||
/// focus change.
|
||||
/// The [State] of the current [EditableText] client of the onscreen keyboard.
|
||||
///
|
||||
/// Setting this property to a new value causes the given [EditableTextState]
|
||||
/// to focus itself and request the keyboard to establish a
|
||||
/// [TextInputConnection].
|
||||
///
|
||||
/// Callers must pump an additional frame after setting this property to
|
||||
/// complete the focus change.
|
||||
///
|
||||
/// Instead of setting this directly, consider using
|
||||
/// [WidgetTester.showKeyboard].
|
||||
//
|
||||
// TODO(ianh): We should just remove this property and move the call to
|
||||
// requestKeyboard to the WidgetTester.showKeyboard method.
|
||||
EditableTextState? get focusedEditable => _focusedEditable;
|
||||
EditableTextState? _focusedEditable;
|
||||
set focusedEditable(EditableTextState? value) {
|
||||
@ -799,6 +775,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
// alone so that we don't cause more spurious errors.
|
||||
runApp(Container(key: UniqueKey(), child: _postTestMessage)); // Unmount any remaining widgets.
|
||||
await pump();
|
||||
if (registerTestTextInput)
|
||||
_testTextInput.unregister();
|
||||
invariantTester();
|
||||
_verifyAutoUpdateGoldensUnset(autoUpdateGoldensBeforeTest && !isBrowser);
|
||||
_verifyReportTestExceptionUnset(reportTestExceptionBeforeTest);
|
||||
|
109
packages/flutter_test/lib/src/deprecated.dart
Normal file
109
packages/flutter_test/lib/src/deprecated.dart
Normal file
@ -0,0 +1,109 @@
|
||||
// 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 'binding.dart';
|
||||
|
||||
// TODO(ianh): Once https://github.com/dart-lang/dartdoc/issues/2033 is fixed, update the hyperlinks marked HYPERLINK below.
|
||||
// TODO(ianh): Once cocoon and other customer_tests are migrated, deprecate these transitional APIs
|
||||
|
||||
/// Shim to support the obsolete [setMockMessageHandler] and
|
||||
/// [checkMockMessageHandler] methods on [BinaryMessenger] in tests.
|
||||
///
|
||||
/// The implementations defer to [TestDefaultBinaryMessengerBinding.defaultBinaryMessenger].
|
||||
///
|
||||
/// Rather than calling [setMockMessageHandler] on the
|
||||
/// `ServicesBinding.defaultBinaryMessenger`, use
|
||||
/// `tester.binding.defaultBinaryMessenger.setMockMessageHandler` directly. This
|
||||
/// more accurately represents the actual method invocation.
|
||||
extension TestBinaryMessengerExtension on BinaryMessenger {
|
||||
/// Shim for `TestDefaultBinaryMessenger.setMockMessageHandler`.
|
||||
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// TODO(ianh): deprecate this method: @NotYetDeprecated(
|
||||
// 'Use tester.binding.defaultBinaryMessenger.setMockMessageHandler or '
|
||||
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.setMockMessageHandler instead. '
|
||||
// 'This feature was deprecated after v2.1.0-10.0.pre.'
|
||||
// )
|
||||
void setMockMessageHandler(String channel, MessageHandler? handler) {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(channel, handler);
|
||||
}
|
||||
|
||||
/// Shim for `TestDefaultBinaryMessenger.checkMockMessageHandler`.
|
||||
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// TODO(ianh): deprecate this method: @NotYetDeprecated(
|
||||
// 'Use tester.binding.defaultBinaryMessenger.checkMockMessageHandler or '
|
||||
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.checkMockMessageHandler instead.'
|
||||
// 'This feature was deprecated after v2.1.0-10.0.pre.'
|
||||
// )
|
||||
bool checkMockMessageHandler(String channel, Object? handler) {
|
||||
return TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel, handler);
|
||||
}
|
||||
}
|
||||
|
||||
/// Shim to support the obsolete [setMockMessageHandler] and
|
||||
/// [checkMockMessageHandler] methods on [BasicMessageChannel] in tests.
|
||||
///
|
||||
/// The implementations defer to [TestDefaultBinaryMessengerBinding.defaultBinaryMessenger].
|
||||
///
|
||||
/// Rather than calling [setMockMessageHandler] on the message channel, use
|
||||
/// `tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler`
|
||||
/// directly. This more accurately represents the actual method invocation.
|
||||
extension TestBasicMessageChannelExtension<T> on BasicMessageChannel<T> {
|
||||
/// Shim for `TestDefaultBinaryMessenger.setMockDecodedMessageHandler`.
|
||||
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// TODO(ianh): deprecate this method: @NotYetDeprecated(
|
||||
// 'Use tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler or '
|
||||
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.setMockDecodedMessageHandler instead. '
|
||||
// 'This feature was deprecated after v2.1.0-10.0.pre.'
|
||||
// )
|
||||
void setMockMessageHandler(Future<T> Function(T? message)? handler) {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<T>(this, handler);
|
||||
}
|
||||
|
||||
/// Shim for `TestDefaultBinaryMessenger.checkMockMessageHandler`.
|
||||
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// TODO(ianh): deprecate this method: @NotYetDeprecated(
|
||||
// 'Use tester.binding.defaultBinaryMessenger.checkMockMessageHandler or '
|
||||
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.checkMockMessageHandler instead. '
|
||||
// 'For the first argument, pass channel.name. '
|
||||
// 'This feature was deprecated after v2.1.0-10.0.pre.'
|
||||
// )
|
||||
bool checkMockMessageHandler(Object? handler) {
|
||||
return TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(name, handler);
|
||||
}
|
||||
}
|
||||
|
||||
/// Shim to support the obsolete [setMockMethodCallHandler] and
|
||||
/// [checkMockMethodCallHandler] methods on [MethodChannel] in tests.
|
||||
///
|
||||
/// The implementations defer to [TestDefaultBinaryMessengerBinding.defaultBinaryMessenger].
|
||||
///
|
||||
/// Rather than calling [setMockMethodCallHandler] on the method channel, use
|
||||
/// `tester.binding.defaultBinaryMessenger.setMockMethodCallHandler` directly.
|
||||
/// This more accurately represents the actual method invocation.
|
||||
extension TestMethodChannelExtension on MethodChannel {
|
||||
/// Shim for `TestDefaultBinaryMessenger.setMockMethodCallHandler`.
|
||||
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// TODO(ianh): deprecate this method: @NotYetDeprecated(
|
||||
// 'Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or '
|
||||
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. '
|
||||
// 'This feature was deprecated after v2.1.0-10.0.pre.'
|
||||
// )
|
||||
void setMockMethodCallHandler(Future<dynamic>? Function(MethodCall call)? handler) {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(this, handler);
|
||||
}
|
||||
|
||||
/// Shim for `TestDefaultBinaryMessenger.checkMockMessageHandler`.
|
||||
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// TODO(ianh): deprecate this method: @NotYetDeprecated(
|
||||
// 'Use tester.binding.defaultBinaryMessenger.checkMockMessageHandler or '
|
||||
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.checkMockMessageHandler instead. '
|
||||
// 'For the first argument, pass channel.name. '
|
||||
// 'This feature was deprecated after v2.1.0-10.0.pre.'
|
||||
// )
|
||||
bool checkMockMethodCallHandler(Object? handler) {
|
||||
return TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(name, handler);
|
||||
}
|
||||
}
|
@ -2,10 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'binding.dart';
|
||||
import 'test_async_utils.dart';
|
||||
|
||||
// TODO(gspencergoog): Replace this with more robust key simulation code once
|
||||
@ -637,21 +640,20 @@ class KeyEventSimulator {
|
||||
assert(_osIsSupported(platform!), 'Platform $platform not supported for key simulation');
|
||||
|
||||
final Map<String, dynamic> data = getKeyData(key, platform: platform!, isDown: true, physicalKey: physicalKey);
|
||||
bool result = false;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
final Completer<bool> result = Completer<bool>();
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {
|
||||
if (data == null) {
|
||||
result.complete(false);
|
||||
return;
|
||||
}
|
||||
final Map<String, dynamic> decoded = SystemChannels.keyEvent.codec.decodeMessage(data) as Map<String, dynamic>;
|
||||
if (decoded['handled'] as bool) {
|
||||
result = true;
|
||||
}
|
||||
result.complete(decoded['handled'] as bool);
|
||||
}
|
||||
);
|
||||
return result;
|
||||
return result.future;
|
||||
});
|
||||
}
|
||||
|
||||
@ -677,7 +679,7 @@ class KeyEventSimulator {
|
||||
|
||||
final Map<String, dynamic> data = getKeyData(key, platform: platform!, isDown: false, physicalKey: physicalKey);
|
||||
bool result = false;
|
||||
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.keyEvent.name,
|
||||
SystemChannels.keyEvent.codec.encodeMessage(data),
|
||||
(ByteData? data) {
|
||||
|
306
packages/flutter_test/lib/src/test_default_binary_messenger.dart
Normal file
306
packages/flutter_test/lib/src/test_default_binary_messenger.dart
Normal file
@ -0,0 +1,306 @@
|
||||
// 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 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:fake_async/fake_async.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// A [BinaryMessenger] subclass that is used as the default binary messenger
|
||||
/// under testing environment.
|
||||
///
|
||||
/// It tracks status of data sent across the Flutter platform barrier, which is
|
||||
/// useful for testing frameworks to monitor and synchronize against the
|
||||
/// platform messages.
|
||||
///
|
||||
/// ## Messages from the framework to the platform
|
||||
///
|
||||
/// Messages are sent from the framework to the platform via the
|
||||
/// [send] method.
|
||||
///
|
||||
/// To intercept a message sent from the framework to the platform,
|
||||
/// consider using [setMockMessageHandler],
|
||||
/// [setMockDecodedMessageHandler], and [setMockMethodCallHandler]
|
||||
/// (see also [checkMockMessageHandler]).
|
||||
///
|
||||
/// To wait for all pending framework-to-platform messages, the
|
||||
/// [platformMessagesFinished] getter provides an appropriate
|
||||
/// [Future]. The [pendingMessageCount] getter returns the current
|
||||
/// number of outstanding messages.
|
||||
///
|
||||
/// ## Messages from the platform to the framework
|
||||
///
|
||||
/// The platform sends messages via the [ChannelBuffers] API. Mock
|
||||
/// messages can be sent to the framework using
|
||||
/// [handlePlatformMessage].
|
||||
///
|
||||
/// Listeners for these messages are configured using [setMessageHandler].
|
||||
class TestDefaultBinaryMessenger extends BinaryMessenger {
|
||||
/// Creates a [TestDefaultBinaryMessenger] instance.
|
||||
///
|
||||
/// The [delegate] instance must not be null.
|
||||
TestDefaultBinaryMessenger(this.delegate): assert(delegate != null);
|
||||
|
||||
/// The delegate [BinaryMessenger].
|
||||
final BinaryMessenger delegate;
|
||||
|
||||
// The handlers for messages from the engine (including fake
|
||||
// messages sent by handlePlatformMessage).
|
||||
final Map<String, MessageHandler> _inboundHandlers = <String, MessageHandler>{};
|
||||
|
||||
/// Send a mock message to the framework as if it came from the platform.
|
||||
///
|
||||
/// If a listener has been set using [setMessageHandler], that listener is
|
||||
/// invoked to handle the message, and this method returns a future that
|
||||
/// completes with that handler's result.
|
||||
///
|
||||
/// {@template flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
|
||||
/// It is strongly recommended that all handlers used with this API be
|
||||
/// synchronous (not requiring any microtasks to complete), because
|
||||
/// [testWidgets] tests run in a [FakeAsync] zone in which microtasks do not
|
||||
/// progress except when time is explicitly advanced (e.g. with
|
||||
/// [WidgetTester.pump]), which means that `await`ing a [Future] will result
|
||||
/// in the test hanging.
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// If no listener is configured, this method returns right away with null.
|
||||
///
|
||||
/// The `callback` argument, if non-null, will be called just before this
|
||||
/// method's future completes, either with the result of the listener
|
||||
/// registered with [setMessageHandler], or with null if no listener has
|
||||
/// been registered.
|
||||
///
|
||||
/// Messages can also be sent via [ChannelBuffers.push] (see
|
||||
/// [ServicesBinding.channelBuffers]); the effect is the same, though that API
|
||||
/// will not wait for a response.
|
||||
// TODO(ianh): When the superclass `handlePlatformMessage` is removed,
|
||||
// remove this @override (but leave the method).
|
||||
@override
|
||||
Future<ByteData?> handlePlatformMessage(
|
||||
String channel,
|
||||
ByteData? data,
|
||||
ui.PlatformMessageResponseCallback? callback,
|
||||
) {
|
||||
Future<ByteData?>? result;
|
||||
if (_inboundHandlers.containsKey(channel))
|
||||
result = _inboundHandlers[channel]!(data);
|
||||
result ??= Future<ByteData?>.value(null);
|
||||
if (callback != null)
|
||||
result = result.then((ByteData? result) { callback(result); return result; });
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
void setMessageHandler(String channel, MessageHandler? handler) {
|
||||
if (handler == null) {
|
||||
_inboundHandlers.remove(channel);
|
||||
delegate.setMessageHandler(channel, null);
|
||||
} else {
|
||||
_inboundHandlers[channel] = handler; // used to handle fake messages sent via handlePlatformMessage
|
||||
delegate.setMessageHandler(channel, handler); // used to handle real messages from the engine
|
||||
}
|
||||
}
|
||||
|
||||
final List<Future<ByteData?>> _pendingMessages = <Future<ByteData?>>[];
|
||||
|
||||
/// The number of incomplete/pending calls sent to the platform channels.
|
||||
int get pendingMessageCount => _pendingMessages.length;
|
||||
|
||||
// Handlers that intercept and respond to outgoing messages,
|
||||
// pretending to be the platform.
|
||||
final Map<String, MessageHandler> _outboundHandlers = <String, MessageHandler>{};
|
||||
|
||||
// The outbound callbacks that were actually registered, so that we
|
||||
// can implement the [checkMockMessageHandler] method.
|
||||
final Map<String, Object> _outboundHandlerIdentities = <String, Object>{};
|
||||
|
||||
@override
|
||||
Future<ByteData?>? send(String channel, ByteData? message) {
|
||||
final Future<ByteData?>? resultFuture;
|
||||
final MessageHandler? handler = _outboundHandlers[channel];
|
||||
if (handler != null) {
|
||||
resultFuture = handler(message);
|
||||
} else {
|
||||
resultFuture = delegate.send(channel, message);
|
||||
}
|
||||
if (resultFuture != null) {
|
||||
_pendingMessages.add(resultFuture);
|
||||
resultFuture
|
||||
.catchError((Object error) { /* errors are the responsibility of the caller */ })
|
||||
.whenComplete(() => _pendingMessages.remove(resultFuture));
|
||||
}
|
||||
return resultFuture;
|
||||
}
|
||||
|
||||
/// Returns a Future that completes after all the platform calls are finished.
|
||||
///
|
||||
/// If a new platform message is sent after this method is called, this new
|
||||
/// message is not tracked. Use with [pendingMessageCount] to guarantee no
|
||||
/// pending message calls.
|
||||
Future<void> get platformMessagesFinished {
|
||||
return Future.wait<void>(_pendingMessages);
|
||||
}
|
||||
|
||||
/// Set a callback for intercepting messages sent to the platform on
|
||||
/// the given channel, without decoding them.
|
||||
///
|
||||
/// Intercepted messages are not forwarded to the platform.
|
||||
///
|
||||
/// The given callback will replace the currently registered
|
||||
/// callback for that channel, if any. To stop intercepting messages
|
||||
/// at all, pass null as the handler.
|
||||
///
|
||||
/// The handler's return value, if non-null, is used as a response,
|
||||
/// unencoded.
|
||||
///
|
||||
/// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
|
||||
///
|
||||
/// The `identity` argument, if non-null, is used to identify the
|
||||
/// callback when checked by [checkMockMessageHandler]. If null, the
|
||||
/// `handler` is used instead. (This allows closures to be passed as
|
||||
/// the `handler` with an alias used as the `identity` so that a
|
||||
/// reference to the closure need not be used. In practice, this is
|
||||
/// used by [setMockDecodedMessageHandler] and
|
||||
/// [setMockMethodCallHandler] to allow [checkMockMessageHandler] to
|
||||
/// recognize the closures that were passed to those methods even
|
||||
/// though those methods wrap those closures when passing them to
|
||||
/// this method.)
|
||||
///
|
||||
/// Registered callbacks are cleared after each test.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [checkMockMessageHandler], which can verify if a handler is still
|
||||
/// registered, which is useful in tests to ensure that no unexpected
|
||||
/// handlers are being registered.
|
||||
///
|
||||
/// * [setMockDecodedMessageHandler], which wraps this method but
|
||||
/// decodes the messages using a [MessageCodec].
|
||||
///
|
||||
/// * [setMockMethodCallHandler], which wraps this method but decodes
|
||||
/// the messages using a [MethodCodec].
|
||||
void setMockMessageHandler(String channel, MessageHandler? handler, [ Object? identity ]) {
|
||||
if (handler == null) {
|
||||
_outboundHandlers.remove(channel);
|
||||
_outboundHandlerIdentities.remove(channel);
|
||||
} else {
|
||||
identity ??= handler;
|
||||
_outboundHandlers[channel] = handler;
|
||||
_outboundHandlerIdentities[channel] = identity;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a callback for intercepting messages sent to the platform on
|
||||
/// the given channel.
|
||||
///
|
||||
/// Intercepted messages are not forwarded to the platform.
|
||||
///
|
||||
/// The given callback will replace the currently registered
|
||||
/// callback for that channel, if any. To stop intercepting messages
|
||||
/// at all, pass null as the handler.
|
||||
///
|
||||
/// Messages are decoded using the codec of the channel.
|
||||
///
|
||||
/// The handler's return value, if non-null, is used as a response,
|
||||
/// after encoding it using the channel's codec.
|
||||
///
|
||||
/// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
|
||||
///
|
||||
/// Registered callbacks are cleared after each test.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [checkMockMessageHandler], which can verify if a handler is still
|
||||
/// registered, which is useful in tests to ensure that no unexpected
|
||||
/// handlers are being registered.
|
||||
///
|
||||
/// * [setMockMessageHandler], which is similar but provides raw
|
||||
/// access to the underlying bytes.
|
||||
///
|
||||
/// * [setMockMethodCallHandler], which is similar but decodes
|
||||
/// the messages using a [MethodCodec].
|
||||
void setMockDecodedMessageHandler<T>(BasicMessageChannel<T> channel, Future<T> Function(T? message)? handler) {
|
||||
if (handler == null) {
|
||||
setMockMessageHandler(channel.name, null);
|
||||
return;
|
||||
}
|
||||
setMockMessageHandler(channel.name, (ByteData? message) async {
|
||||
return channel.codec.encodeMessage(await handler(channel.codec.decodeMessage(message)));
|
||||
}, handler);
|
||||
}
|
||||
|
||||
/// Set a callback for intercepting method calls sent to the
|
||||
/// platform on the given channel.
|
||||
///
|
||||
/// Intercepted method calls are not forwarded to the platform.
|
||||
///
|
||||
/// The given callback will replace the currently registered
|
||||
/// callback for that channel, if any. To stop intercepting messages
|
||||
/// at all, pass null as the handler.
|
||||
///
|
||||
/// Methods are decoded using the codec of the channel.
|
||||
///
|
||||
/// The handler's return value, if non-null, is used as a response,
|
||||
/// after re-encoding it using the channel's codec.
|
||||
///
|
||||
/// To send an error, throw a [PlatformException] in the handler.
|
||||
/// Other exceptions are not caught.
|
||||
///
|
||||
/// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
|
||||
///
|
||||
/// Registered callbacks are cleared after each test.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [checkMockMessageHandler], which can verify if a handler is still
|
||||
/// registered, which is useful in tests to ensure that no unexpected
|
||||
/// handlers are being registered.
|
||||
///
|
||||
/// * [setMockMessageHandler], which is similar but provides raw
|
||||
/// access to the underlying bytes.
|
||||
///
|
||||
/// * [setMockDecodedMessageHandler], which is similar but decodes
|
||||
/// the messages using a [MessageCodec].
|
||||
void setMockMethodCallHandler(MethodChannel channel, Future<Object?>? Function(MethodCall message)? handler) {
|
||||
if (handler == null) {
|
||||
setMockMessageHandler(channel.name, null);
|
||||
return;
|
||||
}
|
||||
setMockMessageHandler(channel.name, (ByteData? message) async {
|
||||
final MethodCall call = channel.codec.decodeMethodCall(message);
|
||||
try {
|
||||
return channel.codec.encodeSuccessEnvelope(await handler(call));
|
||||
} on PlatformException catch (error) {
|
||||
return channel.codec.encodeErrorEnvelope(
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
details: error.details,
|
||||
);
|
||||
} on MissingPluginException {
|
||||
return null;
|
||||
} catch (error) {
|
||||
return channel.codec.encodeErrorEnvelope(code: 'error', message: '$error', details: null);
|
||||
}
|
||||
}, handler);
|
||||
}
|
||||
|
||||
/// Returns true if the `handler` argument matches the `handler`
|
||||
/// previously passed to [setMockMessageHandler],
|
||||
/// [setMockDecodedMessageHandler], or [setMockMethodCallHandler].
|
||||
///
|
||||
/// Specifically, it compares the argument provided to the `identity`
|
||||
/// argument provided to [setMockMessageHandler], defaulting to the
|
||||
/// `handler` argument passed to that method is `identity` was null.
|
||||
///
|
||||
/// This method is useful for tests or test harnesses that want to assert the
|
||||
/// mock handler for the specified channel has not been altered by a previous
|
||||
/// test.
|
||||
///
|
||||
/// Passing null for the `handler` returns true if the handler for the
|
||||
/// `channel` is not set.
|
||||
///
|
||||
/// Registered callbacks are cleared after each test.
|
||||
bool checkMockMessageHandler(String channel, Object? handler) => _outboundHandlerIdentities[channel] == handler;
|
||||
}
|
@ -8,12 +8,28 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'binding.dart' show TestDefaultBinaryMessengerBinding;
|
||||
import 'deprecated.dart';
|
||||
import 'test_async_utils.dart';
|
||||
|
||||
export 'package:flutter/services.dart' show TextEditingValue, TextInputAction;
|
||||
|
||||
/// A testing stub for the system's onscreen keyboard.
|
||||
///
|
||||
/// Typical app tests will not need to use this class directly.
|
||||
///
|
||||
/// The [TestWidgetsFlutterBinding] class registers a [TestTextInput] instance
|
||||
/// ([TestWidgetsFlutterBinding.testTextInput]) as a stub keyboard
|
||||
/// implementation if its [TestWidgetsFlutterBinding.registerTestTextInput]
|
||||
/// property returns true when a test starts, and unregisters it when the test
|
||||
/// ends (unless it ends with a failure).
|
||||
///
|
||||
/// See [register], [unregister], and [isRegistered] for details.
|
||||
///
|
||||
/// The [enterText], [updateEditingValue], [receiveAction], and
|
||||
/// [closeConnection] methods can be used even when the [TestTextInput] is not
|
||||
/// registered. All other methods will assert if [isRegistered] is false.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [WidgetTester.enterText], which uses this class to simulate keyboard input.
|
||||
@ -33,61 +49,76 @@ class TestTextInput {
|
||||
/// first be requested, e.g. using [WidgetTester.showKeyboard].
|
||||
final VoidCallback? onCleared;
|
||||
|
||||
/// The messenger which sends the bytes for this channel, not null.
|
||||
BinaryMessenger get _binaryMessenger => ServicesBinding.instance!.defaultBinaryMessenger;
|
||||
|
||||
/// Resets any internal state of this object and calls [register].
|
||||
///
|
||||
/// This method is invoked by the testing framework between tests. It should
|
||||
/// not ordinarily be called by tests directly.
|
||||
void resetAndRegister() {
|
||||
log.clear();
|
||||
editingState = null;
|
||||
setClientArgs = null;
|
||||
_client = 0;
|
||||
_isVisible = false;
|
||||
register();
|
||||
}
|
||||
/// Installs this object as a mock handler for [SystemChannels.textInput].
|
||||
void register() => SystemChannels.textInput.setMockMethodCallHandler(_handleTextInputCall);
|
||||
|
||||
/// Removes this object as a mock handler for [SystemChannels.textInput].
|
||||
///
|
||||
/// After calling this method, the channel will exchange messages with the
|
||||
/// Flutter engine. Use this with [FlutterDriver] tests that need to display
|
||||
/// on-screen keyboard provided by the operating system.
|
||||
void unregister() => SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
/// Log for method calls.
|
||||
///
|
||||
/// For all registered channels, handled calls are added to the list. Can
|
||||
/// be cleaned using `log.clear()`.
|
||||
final List<MethodCall> log = <MethodCall>[];
|
||||
|
||||
/// Installs this object as a mock handler for [SystemChannels.textInput].
|
||||
///
|
||||
/// Called by the binding at the top of a test when
|
||||
/// [TestWidgetsFlutterBinding.registerTestTextInput] is true.
|
||||
void register() => SystemChannels.textInput.setMockMethodCallHandler(_handleTextInputCall);
|
||||
|
||||
/// Removes this object as a mock handler for [SystemChannels.textInput].
|
||||
///
|
||||
/// After calling this method, the channel will exchange messages with the
|
||||
/// Flutter engine instead of the stub.
|
||||
///
|
||||
/// Called by the binding at the end of a (successful) test when
|
||||
/// [TestWidgetsFlutterBinding.registerTestTextInput] is true.
|
||||
void unregister() => SystemChannels.textInput.setMockMethodCallHandler(null);
|
||||
|
||||
/// Whether this [TestTextInput] is registered with [SystemChannels.textInput].
|
||||
///
|
||||
/// Use [register] and [unregister] methods to control this value.
|
||||
/// The binding uses the [register] and [unregister] methods to control this
|
||||
/// value when [TestWidgetsFlutterBinding.registerTestTextInput] is true.
|
||||
bool get isRegistered => SystemChannels.textInput.checkMockMethodCallHandler(_handleTextInputCall);
|
||||
|
||||
int? _client;
|
||||
|
||||
/// Whether there are any active clients listening to text input.
|
||||
bool get hasAnyClients {
|
||||
assert(isRegistered);
|
||||
return _client > 0;
|
||||
return _client != null && _client! > 0;
|
||||
}
|
||||
|
||||
int _client = 0;
|
||||
|
||||
/// Arguments supplied to the TextInput.setClient method call.
|
||||
/// The last set of arguments supplied to the `TextInput.setClient` and
|
||||
/// `TextInput.updateConfig` methods of this stub implementation.
|
||||
Map<String, dynamic>? setClientArgs;
|
||||
|
||||
/// The last set of arguments that [TextInputConnection.setEditingState] sent
|
||||
/// to the embedder.
|
||||
/// to this stub implementation (i.e. the arguments set to
|
||||
/// `TextInput.setEditingState`).
|
||||
///
|
||||
/// This is a map representation of a [TextEditingValue] object. For example,
|
||||
/// it will have a `text` entry whose value matches the most recent
|
||||
/// [TextEditingValue.text] that was sent to the embedder.
|
||||
Map<String, dynamic>? editingState;
|
||||
|
||||
/// Whether the onscreen keyboard is visible to the user.
|
||||
///
|
||||
/// Specifically, this reflects the last call to `TextInput.show` or
|
||||
/// `TextInput.hide` received by the stub implementation.
|
||||
bool get isVisible {
|
||||
assert(isRegistered);
|
||||
return _isVisible;
|
||||
}
|
||||
bool _isVisible = false;
|
||||
|
||||
/// Resets any internal state of this object.
|
||||
///
|
||||
/// This method is invoked by the testing framework between tests. It should
|
||||
/// not ordinarily be called by tests directly.
|
||||
void reset() {
|
||||
log.clear();
|
||||
_client = null;
|
||||
setClientArgs = null;
|
||||
editingState = null;
|
||||
_isVisible = false;
|
||||
}
|
||||
|
||||
Future<dynamic> _handleTextInputCall(MethodCall methodCall) async {
|
||||
log.add(methodCall);
|
||||
switch (methodCall.method) {
|
||||
@ -99,7 +130,7 @@ class TestTextInput {
|
||||
setClientArgs = methodCall.arguments as Map<String, dynamic>;
|
||||
break;
|
||||
case 'TextInput.clearClient':
|
||||
_client = 0;
|
||||
_client = null;
|
||||
_isVisible = false;
|
||||
onCleared?.call();
|
||||
break;
|
||||
@ -115,87 +146,86 @@ class TestTextInput {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the onscreen keyboard is visible to the user.
|
||||
bool get isVisible {
|
||||
assert(isRegistered);
|
||||
return _isVisible;
|
||||
}
|
||||
bool _isVisible = false;
|
||||
|
||||
/// Simulates the user changing the [TextEditingValue] to the given value.
|
||||
void updateEditingValue(TextEditingValue value) {
|
||||
assert(isRegistered);
|
||||
// Not using the `expect` function because in the case of a FlutterDriver
|
||||
// test this code does not run in a package:test test zone.
|
||||
if (_client == 0)
|
||||
throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
|
||||
_binaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.textInput.name,
|
||||
SystemChannels.textInput.codec.encodeMethodCall(
|
||||
MethodCall(
|
||||
'TextInputClient.updateEditingState',
|
||||
<dynamic>[_client, value.toJSON()],
|
||||
),
|
||||
),
|
||||
(ByteData? data) { /* response from framework is discarded */ },
|
||||
);
|
||||
}
|
||||
|
||||
/// Simulates the user closing the text input connection.
|
||||
/// Simulates the user hiding the onscreen keyboard.
|
||||
///
|
||||
/// For example:
|
||||
/// - User pressed the home button and sent the application to background.
|
||||
/// - User closed the virtual keyboard.
|
||||
void closeConnection() {
|
||||
/// This does nothing but set the internal flag.
|
||||
void hide() {
|
||||
assert(isRegistered);
|
||||
// Not using the `expect` function because in the case of a FlutterDriver
|
||||
// test this code does not run in a package:test test zone.
|
||||
if (_client == 0)
|
||||
throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
|
||||
_binaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.textInput.name,
|
||||
SystemChannels.textInput.codec.encodeMethodCall(
|
||||
MethodCall(
|
||||
'TextInputClient.onConnectionClosed',
|
||||
<dynamic>[_client,]
|
||||
),
|
||||
),
|
||||
(ByteData? data) { /* response from framework is discarded */ },
|
||||
);
|
||||
_isVisible = false;
|
||||
}
|
||||
|
||||
/// Simulates the user typing the given text.
|
||||
/// Simulates the user changing the text of the focused text field, and resets
|
||||
/// the selection.
|
||||
///
|
||||
/// Calling this method replaces the content of the connected input field with
|
||||
/// `text`, and places the caret at the end of the text.
|
||||
///
|
||||
/// To update the UI under test after this method is invoked, use
|
||||
/// [WidgetTester.pump].
|
||||
///
|
||||
/// This can be called even if the [TestTextInput] has not been [register]ed.
|
||||
///
|
||||
/// If this is used to inject text when there is a real IME connection, for
|
||||
/// example when using the [integration_test] library, there is a risk that
|
||||
/// the real IME will become confused as to the current state of input.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [updateEditingValue], which takes a [TextEditingValue] so that one can
|
||||
/// also change the selection.
|
||||
void enterText(String text) {
|
||||
assert(isRegistered);
|
||||
updateEditingValue(TextEditingValue(
|
||||
text: text,
|
||||
selection: TextSelection.collapsed(offset: text.length),
|
||||
));
|
||||
}
|
||||
|
||||
/// Simulates the user changing the [TextEditingValue] to the given value.
|
||||
///
|
||||
/// To update the UI under test after this method is invoked, use
|
||||
/// [WidgetTester.pump].
|
||||
///
|
||||
/// This can be called even if the [TestTextInput] has not been [register]ed.
|
||||
///
|
||||
/// If this is used to inject text when there is a real IME connection, for
|
||||
/// example when using the [integration_test] library, there is a risk that
|
||||
/// the real IME will become confused as to the current state of input.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [enterText], which is similar but takes only a String and resets the
|
||||
/// selection.
|
||||
void updateEditingValue(TextEditingValue value) {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.textInput.name,
|
||||
SystemChannels.textInput.codec.encodeMethodCall(
|
||||
MethodCall(
|
||||
'TextInputClient.updateEditingState',
|
||||
<dynamic>[_client ?? -1, value.toJSON()],
|
||||
),
|
||||
),
|
||||
(ByteData? data) { /* ignored */ },
|
||||
);
|
||||
}
|
||||
|
||||
/// Simulates the user pressing one of the [TextInputAction] buttons.
|
||||
/// Does not check that the [TextInputAction] performed is an acceptable one
|
||||
/// based on the `inputAction` [setClientArgs].
|
||||
///
|
||||
/// This can be called even if the [TestTextInput] has not been [register]ed.
|
||||
///
|
||||
/// If this is used to inject an action when there is a real IME connection,
|
||||
/// for example when using the [integration_test] library, there is a risk
|
||||
/// that the real IME will become confused as to the current state of input.
|
||||
Future<void> receiveAction(TextInputAction action) async {
|
||||
assert(isRegistered);
|
||||
return TestAsyncUtils.guard(() {
|
||||
// Not using the `expect` function because in the case of a FlutterDriver
|
||||
// test this code does not run in a package:test test zone.
|
||||
if (_client == 0) {
|
||||
throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
|
||||
}
|
||||
|
||||
final Completer<void> completer = Completer<void>();
|
||||
|
||||
_binaryMessenger.handlePlatformMessage(
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.textInput.name,
|
||||
SystemChannels.textInput.codec.encodeMethodCall(
|
||||
MethodCall(
|
||||
'TextInputClient.performAction',
|
||||
<dynamic>[_client, action.toString()],
|
||||
<dynamic>[_client ?? -1, action.toString()],
|
||||
),
|
||||
),
|
||||
(ByteData? data) {
|
||||
@ -204,8 +234,7 @@ class TestTextInput {
|
||||
// Decoding throws a PlatformException if the data represents an
|
||||
// error, and that's all we care about here.
|
||||
SystemChannels.textInput.codec.decodeEnvelope(data!);
|
||||
|
||||
// No error was found. Complete without issue.
|
||||
// If we reach here then no error was found. Complete without issue.
|
||||
completer.complete();
|
||||
} catch (error) {
|
||||
// An exception occurred as a result of receiveAction()'ing. Report
|
||||
@ -214,14 +243,32 @@ class TestTextInput {
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return completer.future;
|
||||
});
|
||||
}
|
||||
|
||||
/// Simulates the user hiding the onscreen keyboard.
|
||||
void hide() {
|
||||
assert(isRegistered);
|
||||
_isVisible = false;
|
||||
/// Simulates the user closing the text input connection.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// * User pressed the home button and sent the application to background.
|
||||
/// * User closed the virtual keyboard.
|
||||
///
|
||||
/// This can be called even if the [TestTextInput] has not been [register]ed.
|
||||
///
|
||||
/// If this is used to inject text when there is a real IME connection, for
|
||||
/// example when using the [integration_test] library, there is a risk that
|
||||
/// the real IME will become confused as to the current state of input.
|
||||
void closeConnection() {
|
||||
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
|
||||
SystemChannels.textInput.name,
|
||||
SystemChannels.textInput.codec.encodeMethodCall(
|
||||
MethodCall(
|
||||
'TextInputClient.onConnectionClosed',
|
||||
<dynamic>[_client ?? -1],
|
||||
),
|
||||
),
|
||||
(ByteData? data) { /* response from framework is discarded */ },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ void testWidgets(
|
||||
dynamic tags,
|
||||
}) {
|
||||
assert(variant != null);
|
||||
assert(variant.values.isNotEmpty, 'There must be at least on value to test in the testing variant');
|
||||
assert(variant.values.isNotEmpty, 'There must be at least one value to test in the testing variant.');
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
|
||||
final WidgetTester tester = WidgetTester._(binding);
|
||||
for (final dynamic value in variant.values) {
|
||||
@ -147,9 +147,8 @@ void testWidgets(
|
||||
test_package.addTearDown(binding.postTest);
|
||||
return binding.runTest(
|
||||
() async {
|
||||
binding.reset();
|
||||
binding.reset(); // TODO(ianh): the binding should just do this itself in _runTest
|
||||
debugResetSemanticsIdCounter();
|
||||
tester.resetTestTextInput();
|
||||
Object? memento;
|
||||
try {
|
||||
memento = await variant.setUp(value);
|
||||
@ -918,10 +917,12 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
/// Acts as if the application went idle.
|
||||
///
|
||||
/// Runs all remaining microtasks, including those scheduled as a result of
|
||||
/// running them, until there are no more microtasks scheduled.
|
||||
/// running them, until there are no more microtasks scheduled. Then, runs any
|
||||
/// previously scheduled timers with zero time, and completes the returned future.
|
||||
///
|
||||
/// Does not run timers. May result in an infinite loop or run out of memory
|
||||
/// if microtasks continue to recursively schedule new microtasks.
|
||||
/// May result in an infinite loop or run out of memory if microtasks continue
|
||||
/// to recursively schedule new microtasks. Will not run any timers scheduled
|
||||
/// after this method was invoked, even if they are zero-time timers.
|
||||
Future<void> idle() {
|
||||
return TestAsyncUtils.guard<void>(() => binding.idle());
|
||||
}
|
||||
@ -1002,18 +1003,13 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
///
|
||||
/// Typical app tests will not need to use this value. To add text to widgets
|
||||
/// like [TextField] or [TextFormField], call [enterText].
|
||||
TestTextInput get testTextInput => binding.testTextInput;
|
||||
|
||||
/// Ensures that [testTextInput] is registered and [TestTextInput.log] is
|
||||
/// reset.
|
||||
///
|
||||
/// This is called by the testing framework before test runs, so that if a
|
||||
/// previous test has set its own handler on [SystemChannels.textInput], the
|
||||
/// [testTextInput] regains control and the log is fresh for the new test.
|
||||
/// It should not typically need to be called by tests.
|
||||
void resetTestTextInput() {
|
||||
testTextInput.resetAndRegister();
|
||||
}
|
||||
/// Some of the properties and methods on this value are only valid if the
|
||||
/// binding's [TestWidgetsFlutterBinding.registerTestTextInput] flag is set to
|
||||
/// true as a test is starting (meaning that the keyboard is to be simulated
|
||||
/// by the test framework). If those members are accessed when using a binding
|
||||
/// that sets this flag to false, they will throw.
|
||||
TestTextInput get testTextInput => binding.testTextInput;
|
||||
|
||||
/// Give the text input widget specified by [finder] the focus, as if the
|
||||
/// onscreen keyboard had appeared.
|
||||
@ -1035,6 +1031,9 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
matchRoot: true,
|
||||
),
|
||||
);
|
||||
// Setting focusedEditable causes the binding to call requestKeyboard()
|
||||
// on the EditableTextState, which itself eventually calls TextInput.attach
|
||||
// to establish the connection.
|
||||
binding.focusedEditable = editable;
|
||||
await pump();
|
||||
});
|
||||
@ -1052,6 +1051,12 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
///
|
||||
/// To just give [finder] the focus without entering any text,
|
||||
/// see [showKeyboard].
|
||||
///
|
||||
/// To enter text into other widgets (e.g. a custom widget that maintains a
|
||||
/// TextInputConnection the way that a [EditableText] does), first ensure that
|
||||
/// that widget has an open connection (e.g. by using [tap] to to focus it),
|
||||
/// then call `testTextInput.enterText` directly (see
|
||||
/// [TestTextInput.enterText]).
|
||||
Future<void> enterText(Finder finder, String text) async {
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
await showKeyboard(finder);
|
||||
|
@ -379,8 +379,16 @@ class TestWindow implements ui.SingletonFlutterWindow {
|
||||
platformDispatcher.sendPlatformMessage(name, data, callback);
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
'Instead of calling this callback, use ServicesBinding.instance.channelBuffers.push. '
|
||||
'This feature was deprecated after v2.1.0-10.0.pre.'
|
||||
)
|
||||
@override
|
||||
ui.PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage;
|
||||
@Deprecated(
|
||||
'Instead of setting this callback, use ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler. '
|
||||
'This feature was deprecated after v2.1.0-10.0.pre.'
|
||||
)
|
||||
@override
|
||||
set onPlatformMessage(ui.PlatformMessageCallback? callback) {
|
||||
platformDispatcher.onPlatformMessage = callback;
|
||||
|
@ -11,6 +11,8 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:test_api/test_api.dart' as test_package;
|
||||
|
||||
void main() {
|
||||
final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding();
|
||||
|
||||
group(TestViewConfiguration, () {
|
||||
test('is initialized with top-level window if one is not provided', () {
|
||||
// The code below will throw without the default.
|
||||
@ -20,15 +22,32 @@ void main() {
|
||||
|
||||
group(AutomatedTestWidgetsFlutterBinding, () {
|
||||
test('allows setting defaultTestTimeout to 5 minutes', () {
|
||||
final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding();
|
||||
binding.defaultTestTimeout = const test_package.Timeout(Duration(minutes: 5));
|
||||
expect(binding.defaultTestTimeout.duration, const Duration(minutes: 5));
|
||||
});
|
||||
});
|
||||
|
||||
// The next three tests must run in order -- first using `test`, then `testWidgets`, then `test` again.
|
||||
|
||||
int order = 0;
|
||||
|
||||
test('Initializes httpOverrides and testTextInput', () async {
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
|
||||
expect(binding.testTextInput.isRegistered, true);
|
||||
assert(order == 0);
|
||||
expect(binding.testTextInput, isNotNull);
|
||||
expect(binding.testTextInput.isRegistered, isFalse);
|
||||
expect(HttpOverrides.current, isNotNull);
|
||||
order += 1;
|
||||
});
|
||||
|
||||
testWidgets('Registers testTextInput', (WidgetTester tester) async {
|
||||
assert(order == 1);
|
||||
expect(tester.testTextInput.isRegistered, isTrue);
|
||||
order += 1;
|
||||
});
|
||||
|
||||
test('Unregisters testTextInput', () async {
|
||||
assert(order == 2);
|
||||
expect(binding.testTextInput.isRegistered, isFalse);
|
||||
order += 1;
|
||||
});
|
||||
}
|
||||
|
@ -20,12 +20,6 @@ class TestDelegate extends BinaryMessenger {
|
||||
Future<void> handlePlatformMessage(String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback) => throw UnimplementedError();
|
||||
@override
|
||||
void setMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
|
||||
@override
|
||||
bool checkMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
|
||||
@override
|
||||
void setMockMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
|
||||
@override
|
||||
bool checkMockMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
@ -61,7 +61,7 @@ class Registrar extends BinaryMessenger {
|
||||
/// the [dart:ui] library. That function is only available when
|
||||
/// compiling for the web.
|
||||
void registerMessageHandler() {
|
||||
// The function below is only defined in the Web dart:ui.
|
||||
// The `ui.webOnlySetPluginHandler` function below is only defined in the Web dart:ui.
|
||||
// ignore: undefined_function
|
||||
ui.webOnlySetPluginHandler(handleFrameworkMessage);
|
||||
}
|
||||
@ -141,7 +141,7 @@ class Registrar extends BinaryMessenger {
|
||||
@override
|
||||
Future<ByteData?> send(String channel, ByteData? message) {
|
||||
final Completer<ByteData?> completer = Completer<ByteData?>();
|
||||
ui.window.onPlatformMessage!(channel, message, (ByteData? reply) {
|
||||
ui.channelBuffers.push(channel, message, (ByteData? reply) {
|
||||
try {
|
||||
completer.complete(reply);
|
||||
} catch (exception, stack) {
|
||||
@ -163,26 +163,6 @@ class Registrar extends BinaryMessenger {
|
||||
else
|
||||
_handlers[channel] = handler;
|
||||
}
|
||||
|
||||
@override
|
||||
bool checkMessageHandler(String channel, MessageHandler? handler) => _handlers[channel] == handler;
|
||||
|
||||
@override
|
||||
void setMockMessageHandler(
|
||||
String channel,
|
||||
MessageHandler? handler,
|
||||
) {
|
||||
throw FlutterError(
|
||||
'Setting mock handlers is not supported on the platform side.',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool checkMockMessageHandler(String channel, MessageHandler? handler) {
|
||||
throw FlutterError(
|
||||
'Setting mock handlers is not supported on the platform side.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// This class was previously separate from [Registrar] but was merged into it
|
||||
|
@ -71,12 +71,5 @@ void main() {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger
|
||||
.setMessageHandler('test_send', null);
|
||||
});
|
||||
|
||||
test('throws when trying to set a mock handler', () {
|
||||
expect(
|
||||
() => pluginBinaryMessenger.setMockMessageHandler(
|
||||
'test', (ByteData? data) async => ByteData(0)),
|
||||
throwsFlutterError);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user