mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Flutter_driver nnbd (#74856)
This commit is contained in:
parent
650b240634
commit
3ece9c63d9
@ -669,7 +669,7 @@ Future<void> _runFrameworkTests() async {
|
||||
await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world'), options: soundNullSafetyOptions);
|
||||
await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'), options: soundNullSafetyOptions);
|
||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'benchmarks', 'test_apps', 'stocks'));
|
||||
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tests: <String>[path.join('test', 'src', 'real_tests')]);
|
||||
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tests: <String>[path.join('test', 'src', 'real_tests')], options: soundNullSafetyOptions);
|
||||
await _runFlutterTest(path.join(flutterRoot, 'packages', 'integration_test'));
|
||||
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_goldens'), options: soundNullSafetyOptions);
|
||||
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), options: soundNullSafetyOptions);
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
/// Provides API to test Flutter applications that run on real
|
||||
/// devices and emulators.
|
||||
///
|
||||
|
@ -14,10 +14,10 @@ class DriverError extends Error {
|
||||
final String message;
|
||||
|
||||
/// The error object that was caught and wrapped by this error object, if any.
|
||||
final dynamic originalError;
|
||||
final Object? originalError;
|
||||
|
||||
/// The stack trace that was caught and wrapped by this error object, if any.
|
||||
final dynamic originalStackTrace;
|
||||
final Object? originalStackTrace;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
/// Convenience methods for Flutter application driving on Fuchsia. Can
|
||||
/// be run on either a host machine (making a remote connection to a Fuchsia
|
||||
/// device), or on the target Fuchsia machine.
|
||||
@ -40,13 +38,13 @@ class _DummySshCommandRunner implements SshCommandRunner {
|
||||
}
|
||||
|
||||
@override
|
||||
String get sshConfigPath => null;
|
||||
String get sshConfigPath => '';
|
||||
|
||||
@override
|
||||
String get address => InternetAddress.loopbackIPv4.address;
|
||||
|
||||
@override
|
||||
String get interface => null;
|
||||
String get interface => '';
|
||||
|
||||
@override
|
||||
Future<List<String>> run(String command) async {
|
||||
@ -72,8 +70,8 @@ class _DummySshCommandRunner implements SshCommandRunner {
|
||||
Future<PortForwarder> _dummyPortForwardingFunction(
|
||||
String address,
|
||||
int remotePort, [
|
||||
String interface = '',
|
||||
String configFile,
|
||||
String? interface,
|
||||
String? configFile,
|
||||
]) async {
|
||||
return _DummyPortForwarder(remotePort, remotePort);
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:file/file.dart';
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
@ -95,14 +93,14 @@ abstract class FlutterDriver {
|
||||
/// for the VM.
|
||||
@visibleForTesting
|
||||
factory FlutterDriver.connectedTo({
|
||||
FlutterWebConnection webConnection,
|
||||
vms.VmService serviceClient,
|
||||
vms.Isolate appIsolate,
|
||||
FlutterWebConnection? webConnection,
|
||||
vms.VmService? serviceClient,
|
||||
vms.Isolate? appIsolate,
|
||||
}) {
|
||||
if (webConnection != null) {
|
||||
return WebFlutterDriver.connectedTo(webConnection);
|
||||
}
|
||||
return VMServiceFlutterDriver.connectedTo(serviceClient, appIsolate);
|
||||
return VMServiceFlutterDriver.connectedTo(serviceClient!, appIsolate!);
|
||||
}
|
||||
|
||||
/// Connects to a Flutter application.
|
||||
@ -140,13 +138,13 @@ abstract class FlutterDriver {
|
||||
/// fail (completing with an error). A timeout can be applied by the caller
|
||||
/// using [Future.timeout] if necessary.
|
||||
static Future<FlutterDriver> connect({
|
||||
String dartVmServiceUrl,
|
||||
String? dartVmServiceUrl,
|
||||
bool printCommunication = false,
|
||||
bool logCommunicationToFile = true,
|
||||
int isolateNumber,
|
||||
Pattern fuchsiaModuleTarget,
|
||||
Duration timeout,
|
||||
Map<String, dynamic> headers,
|
||||
int? isolateNumber,
|
||||
Pattern? fuchsiaModuleTarget,
|
||||
Duration? timeout,
|
||||
Map<String, dynamic>? headers,
|
||||
}) async {
|
||||
if (Platform.environment['FLUTTER_WEB_TEST'] != null) {
|
||||
return WebFlutterDriver.connectWeb(hostUrl: dartVmServiceUrl, timeout: timeout);
|
||||
@ -185,22 +183,22 @@ abstract class FlutterDriver {
|
||||
Future<Map<String, dynamic>> sendCommand(Command command) async => throw UnimplementedError();
|
||||
|
||||
/// Checks the status of the Flutter Driver extension.
|
||||
Future<Health> checkHealth({ Duration timeout }) async {
|
||||
Future<Health> checkHealth({ Duration? timeout }) async {
|
||||
return Health.fromJson(await sendCommand(GetHealth(timeout: timeout)));
|
||||
}
|
||||
|
||||
/// Returns a dump of the render tree.
|
||||
Future<RenderTree> getRenderTree({ Duration timeout }) async {
|
||||
Future<RenderTree> getRenderTree({ Duration? timeout }) async {
|
||||
return RenderTree.fromJson(await sendCommand(GetRenderTree(timeout: timeout)));
|
||||
}
|
||||
|
||||
/// Returns a dump of the layer tree.
|
||||
Future<LayerTree> getLayerTree({ Duration timeout }) async {
|
||||
Future<LayerTree> getLayerTree({ Duration? timeout }) async {
|
||||
return LayerTree.fromJson(await sendCommand(GetLayerTree(timeout: timeout)));
|
||||
}
|
||||
|
||||
/// Taps at the center of the widget located by [finder].
|
||||
Future<void> tap(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<void> tap(SerializableFinder finder, { Duration? timeout }) async {
|
||||
await sendCommand(Tap(finder, timeout: timeout));
|
||||
}
|
||||
|
||||
@ -213,17 +211,17 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// * [FlutterDriver.runUnsynchronized], which will execute an action
|
||||
/// with frame sync disabled even while frames are pending.
|
||||
Future<void> waitFor(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<void> waitFor(SerializableFinder finder, { Duration? timeout }) async {
|
||||
await sendCommand(WaitFor(finder, timeout: timeout));
|
||||
}
|
||||
|
||||
/// Waits until [finder] can no longer locate the target.
|
||||
Future<void> waitForAbsent(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<void> waitForAbsent(SerializableFinder finder, { Duration? timeout }) async {
|
||||
await sendCommand(WaitForAbsent(finder, timeout: timeout));
|
||||
}
|
||||
|
||||
/// Waits until the given [waitCondition] is satisfied.
|
||||
Future<void> waitForCondition(SerializableWaitCondition waitCondition, {Duration timeout}) async {
|
||||
Future<void> waitForCondition(SerializableWaitCondition waitCondition, {Duration? timeout}) async {
|
||||
await sendCommand(WaitForCondition(waitCondition, timeout: timeout));
|
||||
}
|
||||
|
||||
@ -231,7 +229,7 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// Use this method when you need to wait for the moment when the application
|
||||
/// becomes "stable", for example, prior to taking a [screenshot].
|
||||
Future<void> waitUntilNoTransientCallbacks({ Duration timeout }) async {
|
||||
Future<void> waitUntilNoTransientCallbacks({ Duration? timeout }) async {
|
||||
await sendCommand(WaitForCondition(const NoTransientCallbacks(), timeout: timeout));
|
||||
}
|
||||
|
||||
@ -246,7 +244,7 @@ abstract class FlutterDriver {
|
||||
await sendCommand(const WaitForCondition(FirstFrameRasterized()));
|
||||
}
|
||||
|
||||
Future<DriverOffset> _getOffset(SerializableFinder finder, OffsetType type, { Duration timeout }) async {
|
||||
Future<DriverOffset> _getOffset(SerializableFinder finder, OffsetType type, { Duration? timeout }) async {
|
||||
final GetOffset command = GetOffset(finder, type, timeout: timeout);
|
||||
final GetOffsetResult result = GetOffsetResult.fromJson(await sendCommand(command));
|
||||
return DriverOffset(result.dx, result.dy);
|
||||
@ -256,7 +254,7 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// The offset is expressed in logical pixels and can be translated to
|
||||
/// device pixels via [dart:ui.FlutterView.devicePixelRatio].
|
||||
Future<DriverOffset> getTopLeft(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<DriverOffset> getTopLeft(SerializableFinder finder, { Duration? timeout }) async {
|
||||
return _getOffset(finder, OffsetType.topLeft, timeout: timeout);
|
||||
}
|
||||
|
||||
@ -264,7 +262,7 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// The offset is expressed in logical pixels and can be translated to
|
||||
/// device pixels via [dart:ui.FlutterView.devicePixelRatio].
|
||||
Future<DriverOffset> getTopRight(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<DriverOffset> getTopRight(SerializableFinder finder, { Duration? timeout }) async {
|
||||
return _getOffset(finder, OffsetType.topRight, timeout: timeout);
|
||||
}
|
||||
|
||||
@ -272,7 +270,7 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// The offset is expressed in logical pixels and can be translated to
|
||||
/// device pixels via [dart:ui.FlutterView.devicePixelRatio].
|
||||
Future<DriverOffset> getBottomLeft(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<DriverOffset> getBottomLeft(SerializableFinder finder, { Duration? timeout }) async {
|
||||
return _getOffset(finder, OffsetType.bottomLeft, timeout: timeout);
|
||||
}
|
||||
|
||||
@ -280,7 +278,7 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// The offset is expressed in logical pixels and can be translated to
|
||||
/// device pixels via [dart:ui.FlutterView.devicePixelRatio].
|
||||
Future<DriverOffset> getBottomRight(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<DriverOffset> getBottomRight(SerializableFinder finder, { Duration? timeout }) async {
|
||||
return _getOffset(finder, OffsetType.bottomRight, timeout: timeout);
|
||||
}
|
||||
|
||||
@ -288,7 +286,7 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// The offset is expressed in logical pixels and can be translated to
|
||||
/// device pixels via [dart:ui.FlutterView.devicePixelRatio].
|
||||
Future<DriverOffset> getCenter(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<DriverOffset> getCenter(SerializableFinder finder, { Duration? timeout }) async {
|
||||
return _getOffset(finder, OffsetType.center, timeout: timeout);
|
||||
}
|
||||
|
||||
@ -317,7 +315,7 @@ abstract class FlutterDriver {
|
||||
SerializableFinder finder, {
|
||||
int subtreeDepth = 0,
|
||||
bool includeProperties = true,
|
||||
Duration timeout,
|
||||
Duration? timeout,
|
||||
}) async {
|
||||
return sendCommand(GetDiagnosticsTree(
|
||||
finder,
|
||||
@ -325,7 +323,7 @@ abstract class FlutterDriver {
|
||||
subtreeDepth: subtreeDepth,
|
||||
includeProperties: includeProperties,
|
||||
timeout: timeout,
|
||||
));
|
||||
)) as Map<String, Object>;
|
||||
}
|
||||
|
||||
/// Returns a JSON map of the [DiagnosticsNode] that is associated with the
|
||||
@ -350,7 +348,7 @@ abstract class FlutterDriver {
|
||||
SerializableFinder finder, {
|
||||
int subtreeDepth = 0,
|
||||
bool includeProperties = true,
|
||||
Duration timeout,
|
||||
Duration? timeout,
|
||||
}) async {
|
||||
return sendCommand(GetDiagnosticsTree(
|
||||
finder,
|
||||
@ -358,7 +356,7 @@ abstract class FlutterDriver {
|
||||
subtreeDepth: subtreeDepth,
|
||||
includeProperties: includeProperties,
|
||||
timeout: timeout,
|
||||
));
|
||||
)) as Map<String, Object>;
|
||||
}
|
||||
|
||||
/// Tell the driver to perform a scrolling action.
|
||||
@ -374,7 +372,7 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// The move events are generated at a given [frequency] in Hz (or events per
|
||||
/// second). It defaults to 60Hz.
|
||||
Future<void> scroll(SerializableFinder finder, double dx, double dy, Duration duration, { int frequency = 60, Duration timeout }) async {
|
||||
Future<void> scroll(SerializableFinder finder, double dx, double dy, Duration duration, { int frequency = 60, Duration? timeout }) async {
|
||||
await sendCommand(Scroll(finder, dx, dy, duration, frequency, timeout: timeout));
|
||||
}
|
||||
|
||||
@ -385,7 +383,7 @@ abstract class FlutterDriver {
|
||||
/// that lazily creates its children, like [ListView] or [CustomScrollView],
|
||||
/// then this method may fail because [finder] doesn't actually exist.
|
||||
/// The [scrollUntilVisible] method can be used in this case.
|
||||
Future<void> scrollIntoView(SerializableFinder finder, { double alignment = 0.0, Duration timeout }) async {
|
||||
Future<void> scrollIntoView(SerializableFinder finder, { double alignment = 0.0, Duration? timeout }) async {
|
||||
await sendCommand(ScrollIntoView(finder, alignment: alignment, timeout: timeout));
|
||||
}
|
||||
|
||||
@ -417,7 +415,7 @@ abstract class FlutterDriver {
|
||||
double alignment = 0.0,
|
||||
double dxScroll = 0.0,
|
||||
double dyScroll = 0.0,
|
||||
Duration timeout,
|
||||
Duration? timeout,
|
||||
}) async {
|
||||
assert(scrollable != null);
|
||||
assert(item != null);
|
||||
@ -442,7 +440,7 @@ abstract class FlutterDriver {
|
||||
}
|
||||
|
||||
/// Returns the text in the `Text` widget located by [finder].
|
||||
Future<String> getText(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<String> getText(SerializableFinder finder, { Duration? timeout }) async {
|
||||
return GetTextResult.fromJson(await sendCommand(GetText(finder, timeout: timeout))).text;
|
||||
}
|
||||
|
||||
@ -478,7 +476,7 @@ abstract class FlutterDriver {
|
||||
/// await driver.waitFor(find.text('World!')); // verify new text appears
|
||||
/// });
|
||||
/// ```
|
||||
Future<void> enterText(String text, { Duration timeout }) async {
|
||||
Future<void> enterText(String text, { Duration? timeout }) async {
|
||||
await sendCommand(EnterText(text, timeout: timeout));
|
||||
}
|
||||
|
||||
@ -495,7 +493,7 @@ abstract class FlutterDriver {
|
||||
/// When enabled, the operating system's configured keyboard will not be
|
||||
/// invoked when the widget is focused, as the [SystemChannels.textInput]
|
||||
/// channel will be mocked out.
|
||||
Future<void> setTextEntryEmulation({ @required bool enabled, Duration timeout }) async {
|
||||
Future<void> setTextEntryEmulation({ required bool enabled, Duration? timeout }) async {
|
||||
assert(enabled != null);
|
||||
await sendCommand(SetTextEntryEmulation(enabled, timeout: timeout));
|
||||
}
|
||||
@ -506,7 +504,7 @@ abstract class FlutterDriver {
|
||||
/// It's expected that the application has registered a [DataHandler]
|
||||
/// callback in [enableFlutterDriverExtension] that can successfully handle
|
||||
/// these requests.
|
||||
Future<String> requestData(String message, { Duration timeout }) async {
|
||||
Future<String> requestData(String message, { Duration? timeout }) async {
|
||||
return RequestDataResult.fromJson(await sendCommand(RequestData(message, timeout: timeout))).message;
|
||||
}
|
||||
|
||||
@ -514,7 +512,7 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// Returns true when the call actually changed the state from on to off or
|
||||
/// vice versa.
|
||||
Future<bool> setSemantics(bool enabled, { Duration timeout }) async {
|
||||
Future<bool> setSemantics(bool enabled, { Duration? timeout }) async {
|
||||
final SetSemanticsResult result = SetSemanticsResult.fromJson(await sendCommand(SetSemantics(enabled, timeout: timeout)));
|
||||
return result.changedState;
|
||||
}
|
||||
@ -527,7 +525,7 @@ abstract class FlutterDriver {
|
||||
///
|
||||
/// Semantics must be enabled to use this method, either using a platform
|
||||
/// specific shell command or [setSemantics].
|
||||
Future<int> getSemanticsId(SerializableFinder finder, { Duration timeout }) async {
|
||||
Future<int> getSemanticsId(SerializableFinder finder, { Duration? timeout }) async {
|
||||
final Map<String, dynamic> jsonResponse = await sendCommand(GetSemanticsId(finder, timeout: timeout));
|
||||
final GetSemanticsIdResult result = GetSemanticsIdResult.fromJson(jsonResponse);
|
||||
return result.id;
|
||||
@ -693,7 +691,7 @@ abstract class FlutterDriver {
|
||||
/// With frame sync disabled, it's the responsibility of the test author to
|
||||
/// ensure that no action is performed while the app is undergoing a
|
||||
/// transition to avoid flakiness.
|
||||
Future<T> runUnsynchronized<T>(Future<T> action(), { Duration timeout }) async {
|
||||
Future<T> runUnsynchronized<T>(Future<T> action(), { Duration? timeout }) async {
|
||||
await sendCommand(SetFrameSync(false, timeout: timeout));
|
||||
T result;
|
||||
try {
|
||||
@ -750,8 +748,8 @@ class CommonFinders {
|
||||
/// If `firstMatchOnly` is true then only the first ancestor matching
|
||||
/// `matching` will be returned. Defaults to false.
|
||||
SerializableFinder ancestor({
|
||||
@required SerializableFinder of,
|
||||
@required SerializableFinder matching,
|
||||
required SerializableFinder of,
|
||||
required SerializableFinder matching,
|
||||
bool matchRoot = false,
|
||||
bool firstMatchOnly = false,
|
||||
}) => Ancestor(of: of, matching: matching, matchRoot: matchRoot, firstMatchOnly: firstMatchOnly);
|
||||
@ -765,8 +763,8 @@ class CommonFinders {
|
||||
/// If `firstMatchOnly` is true then only the first descendant matching
|
||||
/// `matching` will be returned. Defaults to false.
|
||||
SerializableFinder descendant({
|
||||
@required SerializableFinder of,
|
||||
@required SerializableFinder matching,
|
||||
required SerializableFinder of,
|
||||
required SerializableFinder matching,
|
||||
bool matchRoot = false,
|
||||
bool firstMatchOnly = false,
|
||||
}) => Descendant(of: of, matching: matching, matchRoot: matchRoot, firstMatchOnly: firstMatchOnly);
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
/// Returns the [p]-th percentile element from the [doubles].
|
||||
/// `List<doubles>` will be sorted.
|
||||
double findPercentile(List<double> doubles, double p) {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'percentile_utils.dart';
|
||||
import 'timeline.dart';
|
||||
|
||||
@ -63,7 +61,7 @@ class ProfilingSummarizer {
|
||||
assert(kProfilingEvents.contains(event.name));
|
||||
final ProfileType type = _getProfileType(event.name);
|
||||
eventsByType[type] ??= <TimelineEvent>[];
|
||||
eventsByType[type].add(event);
|
||||
eventsByType[type]!.add(event);
|
||||
}
|
||||
return ProfilingSummarizer._(eventsByType);
|
||||
}
|
||||
@ -96,7 +94,7 @@ class ProfilingSummarizer {
|
||||
/// Returns true if there are events in the timeline corresponding to [profileType].
|
||||
bool hasProfilingInfo(ProfileType profileType) {
|
||||
if (eventByType.containsKey(profileType)) {
|
||||
return eventByType[profileType].isNotEmpty;
|
||||
return eventByType[profileType]!.isNotEmpty;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -104,7 +102,7 @@ class ProfilingSummarizer {
|
||||
|
||||
/// Computes the average of the `profileType` over the recorded events.
|
||||
double computeAverage(ProfileType profileType) {
|
||||
final List<TimelineEvent> events = eventByType[profileType];
|
||||
final List<TimelineEvent> events = eventByType[profileType]!;
|
||||
assert(events.isNotEmpty);
|
||||
final double total = events
|
||||
.map((TimelineEvent e) => _getProfileValue(profileType, e))
|
||||
@ -114,7 +112,7 @@ class ProfilingSummarizer {
|
||||
|
||||
/// The [percentile]-th percentile `profileType` over the recorded events.
|
||||
double computePercentile(ProfileType profileType, double percentile) {
|
||||
final List<TimelineEvent> events = eventByType[profileType];
|
||||
final List<TimelineEvent> events = eventByType[profileType]!;
|
||||
assert(events.isNotEmpty);
|
||||
final List<double> doubles = events
|
||||
.map((TimelineEvent e) => _getProfileValue(profileType, e))
|
||||
@ -122,7 +120,7 @@ class ProfilingSummarizer {
|
||||
return findPercentile(doubles, percentile);
|
||||
}
|
||||
|
||||
static ProfileType _getProfileType(String eventName) {
|
||||
static ProfileType _getProfileType(String? eventName) {
|
||||
switch (eventName) {
|
||||
case _kCpuProfile:
|
||||
return ProfileType.CPU;
|
||||
@ -147,13 +145,11 @@ class ProfilingSummarizer {
|
||||
_getArgValue('owned_shared_memory_usage', e);
|
||||
return dirtyMem + ownedSharedMem;
|
||||
}
|
||||
|
||||
throw Exception('Invalid $profileType.');
|
||||
}
|
||||
|
||||
double _getArgValue(String argKey, TimelineEvent e) {
|
||||
assert(e.arguments.containsKey(argKey));
|
||||
final dynamic argVal = e.arguments[argKey];
|
||||
assert(e.arguments!.containsKey(argKey));
|
||||
final dynamic argVal = e.arguments![argKey];
|
||||
assert(argVal is String);
|
||||
return double.parse(argVal as String);
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'percentile_utils.dart';
|
||||
import 'timeline.dart';
|
||||
|
||||
@ -68,8 +66,8 @@ class SceneDisplayLagSummarizer {
|
||||
|
||||
double _getVsyncTransitionsMissed(TimelineEvent e) {
|
||||
assert(e.name == kSceneDisplayLagEvent);
|
||||
assert(e.arguments.containsKey(_kVsyncTransitionsMissed));
|
||||
final dynamic transitionsMissed = e.arguments[_kVsyncTransitionsMissed];
|
||||
assert(e.arguments!.containsKey(_kVsyncTransitionsMissed));
|
||||
final dynamic transitionsMissed = e.arguments![_kVsyncTransitionsMissed];
|
||||
assert(transitionsMissed is String);
|
||||
return double.parse(transitionsMissed as String);
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
/// Timeline data recorded by the Flutter runtime.
|
||||
class Timeline {
|
||||
/// Creates a timeline given JSON-encoded timeline data.
|
||||
@ -25,27 +23,29 @@ class Timeline {
|
||||
///
|
||||
/// This is parsed from "traceEvents" data within [json] and sorted by
|
||||
/// timestamp. Anything without a valid timestamp is put in the beginning.
|
||||
final List<TimelineEvent> events;
|
||||
///
|
||||
/// This will be null if there are are no "traceEvents" in the [json].
|
||||
final List<TimelineEvent>? events;
|
||||
}
|
||||
|
||||
/// A single timeline event.
|
||||
class TimelineEvent {
|
||||
/// Creates a timeline event given JSON-encoded event data.
|
||||
TimelineEvent(this.json)
|
||||
: name = json['name'] as String,
|
||||
category = json['cat'] as String,
|
||||
phase = json['ph'] as String,
|
||||
processId = json['pid'] as int,
|
||||
threadId = json['tid'] as int,
|
||||
: name = json['name'] as String?,
|
||||
category = json['cat'] as String?,
|
||||
phase = json['ph'] as String?,
|
||||
processId = json['pid'] as int?,
|
||||
threadId = json['tid'] as int?,
|
||||
duration = json['dur'] != null
|
||||
? Duration(microseconds: json['dur'] as int)
|
||||
: null,
|
||||
threadDuration = json['tdur'] != null
|
||||
? Duration(microseconds: json['tdur'] as int)
|
||||
: null,
|
||||
timestampMicros = json['ts'] as int,
|
||||
threadTimestampMicros = json['tts'] as int,
|
||||
arguments = json['args'] as Map<String, dynamic>;
|
||||
timestampMicros = json['ts'] as int?,
|
||||
threadTimestampMicros = json['tts'] as int?,
|
||||
arguments = json['args'] as Map<String, dynamic>?;
|
||||
|
||||
/// The original event JSON.
|
||||
final Map<String, dynamic> json;
|
||||
@ -53,28 +53,28 @@ class TimelineEvent {
|
||||
/// The name of the event.
|
||||
///
|
||||
/// Corresponds to the "name" field in the JSON event.
|
||||
final String name;
|
||||
final String? name;
|
||||
|
||||
/// Event category. Events with different names may share the same category.
|
||||
///
|
||||
/// Corresponds to the "cat" field in the JSON event.
|
||||
final String category;
|
||||
final String? category;
|
||||
|
||||
/// For a given long lasting event, denotes the phase of the event, such as
|
||||
/// "B" for "event began", and "E" for "event ended".
|
||||
///
|
||||
/// Corresponds to the "ph" field in the JSON event.
|
||||
final String phase;
|
||||
final String? phase;
|
||||
|
||||
/// ID of process that emitted the event.
|
||||
///
|
||||
/// Corresponds to the "pid" field in the JSON event.
|
||||
final int processId;
|
||||
final int? processId;
|
||||
|
||||
/// ID of thread that issues the event.
|
||||
///
|
||||
/// Corresponds to the "tid" field in the JSON event.
|
||||
final int threadId;
|
||||
final int? threadId;
|
||||
|
||||
/// The duration of the event.
|
||||
///
|
||||
@ -82,7 +82,7 @@ class TimelineEvent {
|
||||
/// pair of begin/end events.
|
||||
///
|
||||
/// Corresponds to the "dur" field in the JSON event.
|
||||
final Duration duration;
|
||||
final Duration? duration;
|
||||
|
||||
/// The thread duration of the event.
|
||||
///
|
||||
@ -90,32 +90,31 @@ class TimelineEvent {
|
||||
/// pair of begin/end events.
|
||||
///
|
||||
/// Corresponds to the "tdur" field in the JSON event.
|
||||
final Duration threadDuration;
|
||||
final Duration? threadDuration;
|
||||
|
||||
/// Time passed since tracing was enabled, in microseconds.
|
||||
///
|
||||
/// Corresponds to the "ts" field in the JSON event.
|
||||
final int timestampMicros;
|
||||
final int? timestampMicros;
|
||||
|
||||
/// Thread clock time, in microseconds.
|
||||
///
|
||||
/// Corresponds to the "tts" field in the JSON event.
|
||||
final int threadTimestampMicros;
|
||||
final int? threadTimestampMicros;
|
||||
|
||||
/// Arbitrary data attached to the event.
|
||||
///
|
||||
/// Corresponds to the "args" field in the JSON event.
|
||||
final Map<String, dynamic> arguments;
|
||||
final Map<String, dynamic>? arguments;
|
||||
}
|
||||
|
||||
List<TimelineEvent> _parseEvents(Map<String, dynamic> json) {
|
||||
final List<dynamic> jsonEvents = json['traceEvents'] as List<dynamic>;
|
||||
List<TimelineEvent>? _parseEvents(Map<String, dynamic> json) {
|
||||
final List<dynamic>? jsonEvents = json['traceEvents'] as List<dynamic>?;
|
||||
|
||||
if (jsonEvents == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO(vegorov): use instance method version of castFrom when it is available.
|
||||
final List<TimelineEvent> timelineEvents =
|
||||
Iterable.castFrom<dynamic, Map<String, dynamic>>(jsonEvents)
|
||||
.map<TimelineEvent>(
|
||||
@ -123,8 +122,8 @@ List<TimelineEvent> _parseEvents(Map<String, dynamic> json) {
|
||||
.toList();
|
||||
|
||||
timelineEvents.sort((TimelineEvent e1, TimelineEvent e2) {
|
||||
final int ts1 = e1.timestampMicros;
|
||||
final int ts2 = e2.timestampMicros;
|
||||
final int? ts1 = e1.timestampMicros;
|
||||
final int? ts2 = e2.timestampMicros;
|
||||
if (ts1 == null) {
|
||||
if (ts2 == null) {
|
||||
return 0;
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:convert' show json, JsonEncoder;
|
||||
import 'dart:math' as math;
|
||||
|
||||
@ -197,7 +195,7 @@ class TimelineSummary {
|
||||
/// * [Timeline.fromJson], which explains detail about the timeline data.
|
||||
Future<void> writeTimelineToFile(
|
||||
String traceName, {
|
||||
String destinationDirectory,
|
||||
String? destinationDirectory,
|
||||
bool pretty = false,
|
||||
}) async {
|
||||
destinationDirectory ??= testOutputsDirectory;
|
||||
@ -209,7 +207,7 @@ class TimelineSummary {
|
||||
/// Writes [summaryJson] to a file.
|
||||
Future<void> writeSummaryToFile(
|
||||
String traceName, {
|
||||
String destinationDirectory,
|
||||
String? destinationDirectory,
|
||||
bool pretty = false,
|
||||
}) async {
|
||||
destinationDirectory ??= testOutputsDirectory;
|
||||
@ -225,13 +223,13 @@ class TimelineSummary {
|
||||
}
|
||||
|
||||
List<TimelineEvent> _extractNamedEvents(String name) {
|
||||
return _timeline.events
|
||||
return _timeline.events!
|
||||
.where((TimelineEvent event) => event.name == name)
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<TimelineEvent> _extractEventsWithNames(Set<String> names) {
|
||||
return _timeline.events
|
||||
return _timeline.events!
|
||||
.where((TimelineEvent event) => names.contains(event.name))
|
||||
.toList();
|
||||
}
|
||||
@ -244,7 +242,7 @@ class TimelineSummary {
|
||||
final List<TimelineEvent> events = _extractNamedEvents(name);
|
||||
|
||||
// Timeline does not guarantee that the first event is the "begin" event.
|
||||
TimelineEvent begin;
|
||||
TimelineEvent? begin;
|
||||
for (final TimelineEvent event in events) {
|
||||
if (event.phase == 'B') {
|
||||
begin = event;
|
||||
@ -273,7 +271,7 @@ class TimelineSummary {
|
||||
return _extractDurations(
|
||||
name,
|
||||
(TimelineEvent beginEvent, TimelineEvent endEvent) {
|
||||
return Duration(microseconds: endEvent.timestampMicros - beginEvent.timestampMicros);
|
||||
return Duration(microseconds: endEvent.timestampMicros! - beginEvent.timestampMicros!);
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -282,7 +280,7 @@ class TimelineSummary {
|
||||
final List<Duration> result = _extractDurations(
|
||||
name,
|
||||
(TimelineEvent beginEvent, TimelineEvent endEvent) {
|
||||
return Duration(microseconds: beginEvent.timestampMicros);
|
||||
return Duration(microseconds: beginEvent.timestampMicros!);
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -2,15 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:file/file.dart' as f;
|
||||
import 'package:fuchsia_remote_debug_protocol/fuchsia_remote_debug_protocol.dart' as fuchsia;
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:vm_service/vm_service.dart' as vms;
|
||||
import 'package:webdriver/async_io.dart' as async_io;
|
||||
@ -41,12 +38,12 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
///
|
||||
/// See [FlutterDriver.connect] for more documentation.
|
||||
static Future<FlutterDriver> connect({
|
||||
String dartVmServiceUrl,
|
||||
String? dartVmServiceUrl,
|
||||
bool printCommunication = false,
|
||||
bool logCommunicationToFile = true,
|
||||
int isolateNumber,
|
||||
Pattern fuchsiaModuleTarget,
|
||||
Map<String, dynamic> headers,
|
||||
int? isolateNumber,
|
||||
Pattern? fuchsiaModuleTarget,
|
||||
Map<String, dynamic>? headers,
|
||||
}) async {
|
||||
// If running on a Fuchsia device, connect to the first isolate whose name
|
||||
// matches FUCHSIA_MODULE_TARGET.
|
||||
@ -93,32 +90,32 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
_log('Connecting to Flutter application at $dartVmServiceUrl');
|
||||
final vms.VmService client = await vmServiceConnectFunction(dartVmServiceUrl, headers);
|
||||
|
||||
Future<vms.IsolateRef> _waitForRootIsolate() async {
|
||||
Future<vms.IsolateRef?> _waitForRootIsolate() async {
|
||||
bool _checkIsolate(vms.IsolateRef ref) => ref.number == isolateNumber.toString();
|
||||
while (true) {
|
||||
final vms.VM vm = await client.getVM();
|
||||
if (vm.isolates.isEmpty || (isolateNumber != null && !vm.isolates.any(_checkIsolate))) {
|
||||
if (vm.isolates!.isEmpty || (isolateNumber != null && !vm.isolates!.any(_checkIsolate))) {
|
||||
await Future<void>.delayed(_kPauseBetweenReconnectAttempts);
|
||||
continue;
|
||||
}
|
||||
return isolateNumber == null
|
||||
? vm.isolates.first
|
||||
: vm.isolates.firstWhere(_checkIsolate);
|
||||
? vm.isolates!.first
|
||||
: vm.isolates!.firstWhere(_checkIsolate);
|
||||
}
|
||||
}
|
||||
|
||||
final vms.IsolateRef isolateRef = await _warnIfSlow<vms.IsolateRef>(
|
||||
final vms.IsolateRef isolateRef = (await _warnIfSlow<vms.IsolateRef?>(
|
||||
future: _waitForRootIsolate(),
|
||||
timeout: kUnusuallyLongTimeout,
|
||||
message: isolateNumber == null
|
||||
? 'The root isolate is taking an unuusally long time to start.'
|
||||
: 'Isolate $isolateNumber is taking an unusually long time to start.',
|
||||
);
|
||||
))!;
|
||||
_log('Isolate found with number: ${isolateRef.number}');
|
||||
vms.Isolate isolate = await client.getIsolate(isolateRef.id);
|
||||
vms.Isolate isolate = await client.getIsolate(isolateRef.id!);
|
||||
|
||||
if (isolate.pauseEvent.kind == vms.EventKind.kNone) {
|
||||
isolate = await client.getIsolate(isolateRef.id);
|
||||
if (isolate.pauseEvent!.kind == vms.EventKind.kNone) {
|
||||
isolate = await client.getIsolate(isolateRef.id!);
|
||||
}
|
||||
|
||||
final VMServiceFlutterDriver driver = VMServiceFlutterDriver.connectedTo(
|
||||
@ -143,7 +140,7 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
_log('Failed to set pause_isolates_on_start=false, proceeding. Error: $e');
|
||||
}
|
||||
|
||||
return client.resume(isolate.id).catchError((dynamic e) {
|
||||
return client.resume(isolate.id!).catchError((Object e) {
|
||||
const int vmMustBePausedCode = 101;
|
||||
if (e is vms.RPCError && e.code == vmMustBePausedCode) {
|
||||
// No biggie; something else must have resumed the isolate
|
||||
@ -167,9 +164,9 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
await client.streamListen(vms.EventStreams.kIsolate);
|
||||
|
||||
final Future<void> extensionAlreadyAdded = client
|
||||
.getIsolate(isolateRef.id)
|
||||
.getIsolate(isolateRef.id!)
|
||||
.then((vms.Isolate isolate) async {
|
||||
if (isolate.extensionRPCs.contains(_flutterExtensionMethodName)) {
|
||||
if (isolate.extensionRPCs!.contains(_flutterExtensionMethodName)) {
|
||||
return;
|
||||
}
|
||||
// Never complete. Rely on the stream listener to find the service
|
||||
@ -178,7 +175,7 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
});
|
||||
|
||||
final Completer<void> extensionAdded = Completer<void>();
|
||||
StreamSubscription<vms.Event> isolateAddedSubscription;
|
||||
late StreamSubscription<vms.Event> isolateAddedSubscription;
|
||||
|
||||
isolateAddedSubscription = client.onIsolateEvent.listen(
|
||||
(vms.Event data) {
|
||||
@ -200,19 +197,19 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
}
|
||||
|
||||
// Attempt to resume isolate if it was paused
|
||||
if (isolate.pauseEvent.kind == vms.EventKind.kPauseStart) {
|
||||
if (isolate.pauseEvent!.kind == vms.EventKind.kPauseStart) {
|
||||
_log('Isolate is paused at start.');
|
||||
|
||||
await resumeLeniently();
|
||||
} else if (isolate.pauseEvent.kind == vms.EventKind.kPauseExit ||
|
||||
isolate.pauseEvent.kind == vms.EventKind.kPauseBreakpoint ||
|
||||
isolate.pauseEvent.kind == vms.EventKind.kPauseException ||
|
||||
isolate.pauseEvent.kind == vms.EventKind.kPauseInterrupted) {
|
||||
} else if (isolate.pauseEvent!.kind == vms.EventKind.kPauseExit ||
|
||||
isolate.pauseEvent!.kind == vms.EventKind.kPauseBreakpoint ||
|
||||
isolate.pauseEvent!.kind == vms.EventKind.kPauseException ||
|
||||
isolate.pauseEvent!.kind == vms.EventKind.kPauseInterrupted) {
|
||||
// If the isolate is paused for any other reason, assume the extension is
|
||||
// already there.
|
||||
_log('Isolate is paused mid-flight.');
|
||||
await resumeLeniently();
|
||||
} else if (isolate.pauseEvent.kind == vms.EventKind.kResume) {
|
||||
} else if (isolate.pauseEvent!.kind == vms.EventKind.kResume) {
|
||||
_log('Isolate is not paused. Assuming application is ready.');
|
||||
} else {
|
||||
_log(
|
||||
@ -306,7 +303,7 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> sendCommand(Command command) async {
|
||||
Map<String, dynamic> response;
|
||||
late Map<String, dynamic> response;
|
||||
try {
|
||||
final Map<String, String> serialized = command.serialize();
|
||||
_logCommunication('>>> $serialized');
|
||||
@ -314,12 +311,12 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
_flutterExtensionMethodName,
|
||||
isolateId: _appIsolate.id,
|
||||
args: serialized,
|
||||
).then<Map<String, dynamic>>((vms.Response value) => value.json);
|
||||
response = await _warnIfSlow<Map<String, dynamic>>(
|
||||
).then<Map<String, dynamic>>((vms.Response value) => value.json!);
|
||||
response = (await _warnIfSlow<Map<String, dynamic>>(
|
||||
future: future,
|
||||
timeout: command.timeout ?? kUnusuallyLongTimeout,
|
||||
message: '${command.kind} message is taking a long time to complete...',
|
||||
);
|
||||
))!;
|
||||
_logCommunication('<<< $response');
|
||||
} catch (error, stackTrace) {
|
||||
throw DriverError(
|
||||
@ -328,7 +325,7 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
stackTrace,
|
||||
);
|
||||
}
|
||||
if (response['isError'] as bool)
|
||||
if ((response['isError'] as bool?) == true)
|
||||
throw DriverError('Error in Flutter application: ${response['response']}');
|
||||
return response['response'] as Map<String, dynamic>;
|
||||
}
|
||||
@ -348,14 +345,14 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
await Future<void>.delayed(const Duration(seconds: 2));
|
||||
|
||||
final vms.Response result = await _serviceClient.callMethod('_flutter.screenshot');
|
||||
return base64.decode(result.json['screenshot'] as String);
|
||||
return base64.decode(result.json!['screenshot'] as String);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Map<String, dynamic>>> getVmFlags() async {
|
||||
final vms.FlagList result = await _serviceClient.getFlagList();
|
||||
return result != null
|
||||
? result.flags.map((vms.Flag flag) => flag.toJson()).toList()
|
||||
return result.flags != null
|
||||
? result.flags!.map((vms.Flag flag) => flag.toJson()).toList()
|
||||
: const <Map<String, dynamic>>[];
|
||||
}
|
||||
|
||||
@ -390,8 +387,8 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
@override
|
||||
Future<Timeline> stopTracingAndDownloadTimeline({
|
||||
Duration timeout = kUnusuallyLongTimeout,
|
||||
int startTime,
|
||||
int endTime,
|
||||
int? startTime,
|
||||
int? endTime,
|
||||
}) async {
|
||||
assert(timeout != null);
|
||||
assert((startTime == null && endTime == null) ||
|
||||
@ -405,12 +402,12 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
);
|
||||
if (startTime == null) {
|
||||
final vms.Timeline timeline = await _serviceClient.getVMTimeline();
|
||||
return Timeline.fromJson(timeline.json);
|
||||
return Timeline.fromJson(timeline.json!);
|
||||
}
|
||||
const int kSecondInMicros = 1000000;
|
||||
int currentStart = startTime;
|
||||
int currentEnd = startTime + kSecondInMicros; // 1 second of timeline
|
||||
final List<Map<String, Object>> chunks = <Map<String, Object>>[];
|
||||
final List<Map<String, Object?>?> chunks = <Map<String, Object>?>[];
|
||||
do {
|
||||
final vms.Timeline chunk = await _serviceClient.getVMTimeline(
|
||||
timeOriginMicros: currentStart,
|
||||
@ -421,11 +418,11 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
chunks.add(chunk.json);
|
||||
currentStart = currentEnd;
|
||||
currentEnd += kSecondInMicros;
|
||||
} while (currentStart < endTime);
|
||||
} while (currentStart < endTime!);
|
||||
return Timeline.fromJson(<String, Object>{
|
||||
'traceEvents': <Object> [
|
||||
for (Map<String, Object> chunk in chunks)
|
||||
...chunk['traceEvents'] as List<Object>,
|
||||
for (Map<String, Object?>? chunk in chunks)
|
||||
...chunk!['traceEvents']! as List<Object>,
|
||||
],
|
||||
});
|
||||
} catch (error, stackTrace) {
|
||||
@ -502,7 +499,7 @@ class VMServiceFlutterDriver extends FlutterDriver {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<T> runUnsynchronized<T>(Future<T> action(), { Duration timeout }) async {
|
||||
Future<T> runUnsynchronized<T>(Future<T> action(), { Duration? timeout }) async {
|
||||
await sendCommand(SetFrameSync(false, timeout: timeout));
|
||||
T result;
|
||||
try {
|
||||
@ -560,10 +557,10 @@ String _getWebSocketUrl(String url) {
|
||||
|
||||
/// Waits for a real Dart VM service to become available, then connects using
|
||||
/// the [VMServiceClient].
|
||||
Future<vms.VmService> _waitAndConnect(String url, Map<String, dynamic> headers) async {
|
||||
Future<vms.VmService> _waitAndConnect(String url, Map<String, dynamic>? headers) async {
|
||||
final String webSocketUrl = _getWebSocketUrl(url);
|
||||
int attempts = 0;
|
||||
WebSocket socket;
|
||||
late WebSocket socket;
|
||||
while (true) {
|
||||
try {
|
||||
socket = await WebSocket.connect(webSocketUrl, headers: headers);
|
||||
@ -585,7 +582,7 @@ Future<vms.VmService> _waitAndConnect(String url, Map<String, dynamic> headers)
|
||||
await service.getVersion();
|
||||
return service;
|
||||
} catch (e) {
|
||||
await socket?.close();
|
||||
await socket.close();
|
||||
if (attempts > 5) {
|
||||
_log('It is taking an unusually long time to connect to the VM...');
|
||||
}
|
||||
@ -623,10 +620,11 @@ List<String> _timelineStreamsToString(List<TimelineStream> streams) {
|
||||
void _log(String message) {
|
||||
driverLog('VMServiceFlutterDriver', message);
|
||||
}
|
||||
Future<T> _warnIfSlow<T>({
|
||||
@required Future<T> future,
|
||||
@required Duration timeout,
|
||||
@required String message,
|
||||
|
||||
Future<T?> _warnIfSlow<T>({
|
||||
required Future<T?> future,
|
||||
required Duration timeout,
|
||||
required String message,
|
||||
}) {
|
||||
assert(future != null);
|
||||
assert(timeout != null);
|
||||
@ -637,10 +635,10 @@ Future<T> _warnIfSlow<T>({
|
||||
return null;
|
||||
})
|
||||
// Don't duplicate errors if [future] completes with an error.
|
||||
.catchError((dynamic e) => null);
|
||||
.catchError((Object e, StackTrace s) => null);
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
/// A function that connects to a Dart VM service given the `url` and `headers`.
|
||||
typedef VMServiceConnectFunction = Future<vms.VmService> Function(String url, Map<String, dynamic> headers);
|
||||
typedef VMServiceConnectFunction = Future<vms.VmService> Function(String url, Map<String, dynamic>? headers);
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
@ -53,7 +51,7 @@ class WebFlutterDriver extends FlutterDriver {
|
||||
/// DRIVER_SESSION_CAPABILITIES and ANDROID_CHROME_ON_EMULATOR for
|
||||
/// configurations.
|
||||
static Future<FlutterDriver> connectWeb(
|
||||
{String hostUrl, Duration timeout}) async {
|
||||
{String? hostUrl, Duration? timeout}) async {
|
||||
hostUrl ??= Platform.environment['VM_SERVICE_URL'];
|
||||
final Map<String, dynamic> settings = <String, dynamic>{
|
||||
'support-timeline-action': Platform.environment['SUPPORT_TIMELINE_ACTION'] == 'true',
|
||||
@ -64,7 +62,7 @@ class WebFlutterDriver extends FlutterDriver {
|
||||
'session-capabilities': Platform.environment['DRIVER_SESSION_CAPABILITIES'],
|
||||
};
|
||||
final FlutterWebConnection connection = await FlutterWebConnection.connect
|
||||
(hostUrl, settings, timeout: timeout);
|
||||
(hostUrl!, settings, timeout: timeout);
|
||||
return WebFlutterDriver.connectedTo(connection);
|
||||
}
|
||||
|
||||
@ -90,7 +88,7 @@ class WebFlutterDriver extends FlutterDriver {
|
||||
final Map<String, String> serialized = command.serialize();
|
||||
try {
|
||||
final dynamic data = await _connection.sendCommand("window.\$flutterDriver('${jsonEncode(serialized)}')", command.timeout);
|
||||
response = data != null ? json.decode(data as String) as Map<String, dynamic> : <String, dynamic>{};
|
||||
response = data != null ? (json.decode(data as String) as Map<String, dynamic>?)! : <String, dynamic>{};
|
||||
} catch (error, stackTrace) {
|
||||
throw DriverError("Failed to respond to $command due to remote error\n : \$flutterDriver('${jsonEncode(serialized)}')",
|
||||
error,
|
||||
@ -132,7 +130,7 @@ class WebFlutterDriver extends FlutterDriver {
|
||||
final List<Map<String, dynamic>> events = <Map<String, dynamic>>[];
|
||||
for (final async_io.LogEntry entry in await _connection.logs.toList()) {
|
||||
if (_startTime.isBefore(entry.timestamp)) {
|
||||
final Map<String, dynamic> data = jsonDecode(entry.message)['message'] as Map<String, dynamic>;
|
||||
final Map<String, dynamic> data = jsonDecode(entry.message!)['message'] as Map<String, dynamic>;
|
||||
if (data['method'] == 'Tracing.dataCollected') {
|
||||
// 'ts' data collected from Chrome is in double format, conversion needed
|
||||
try {
|
||||
@ -142,7 +140,7 @@ class WebFlutterDriver extends FlutterDriver {
|
||||
// data is corrupted, skip
|
||||
continue;
|
||||
}
|
||||
events.add(data['params'] as Map<String, dynamic>);
|
||||
events.add(data['params']! as Map<String, dynamic>);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -203,7 +201,7 @@ class FlutterWebConnection {
|
||||
static Future<FlutterWebConnection> connect(
|
||||
String url,
|
||||
Map<String, dynamic> settings,
|
||||
{Duration timeout}) async {
|
||||
{Duration? timeout}) async {
|
||||
final String sessionId = settings['session-id'].toString();
|
||||
final Uri sessionUri = Uri.parse(settings['session-uri'].toString());
|
||||
final async_io.WebDriver driver = async_io.WebDriver(
|
||||
@ -226,7 +224,7 @@ class FlutterWebConnection {
|
||||
}
|
||||
|
||||
/// Sends command via WebDriver to Flutter web application.
|
||||
Future<dynamic> sendCommand(String script, Duration duration) async {
|
||||
Future<dynamic> sendCommand(String script, Duration? duration) async {
|
||||
dynamic result;
|
||||
try {
|
||||
await _driver.execute(script, <void>[]);
|
||||
@ -265,7 +263,7 @@ class FlutterWebConnection {
|
||||
}
|
||||
|
||||
/// Waits until extension is installed.
|
||||
Future<void> waitUntilExtensionInstalled(async_io.WebDriver driver, Duration timeout) async {
|
||||
Future<void> waitUntilExtensionInstalled(async_io.WebDriver driver, Duration? timeout) async {
|
||||
await waitFor<void>(() =>
|
||||
driver.execute(r'return typeof(window.$flutterDriver)', <String>[]),
|
||||
matcher: 'function',
|
||||
|
@ -8,16 +8,16 @@ environment:
|
||||
|
||||
dependencies:
|
||||
file: 6.0.0-nullsafety.4
|
||||
meta: 1.3.0-nullsafety.6
|
||||
path: 1.8.0-nullsafety.3
|
||||
vm_service: 6.0.1-nullsafety.0
|
||||
webdriver: 3.0.0-nullsafety.1
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
fuchsia_remote_debug_protocol:
|
||||
sdk: flutter
|
||||
path: 1.8.0-nullsafety.3
|
||||
meta: 1.3.0-nullsafety.6
|
||||
vm_service: 6.0.1-nullsafety.0
|
||||
webdriver: 3.0.0-nullsafety.1
|
||||
|
||||
archive: 3.0.0-nullsafety.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
async: 2.5.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
@ -27,7 +27,6 @@ dependencies:
|
||||
clock: 1.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
collection: 1.15.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
crypto: 3.0.0-nullsafety.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
fake_async: 1.2.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
matcher: 0.12.10-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
platform: 3.0.0-nullsafety.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
process: 4.0.0-nullsafety.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
@ -42,7 +41,7 @@ dependencies:
|
||||
vector_math: 2.1.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
|
||||
dev_dependencies:
|
||||
quiver: 2.1.5
|
||||
fake_async: 1.2.0-nullsafety.3
|
||||
test: 1.16.0-nullsafety.16
|
||||
|
||||
_fe_analyzer_shared: 14.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
@ -77,4 +76,4 @@ dev_dependencies:
|
||||
webkit_inspection_protocol: 0.7.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
yaml: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
|
||||
# PUBSPEC CHECKSUM: 91b1
|
||||
# PUBSPEC CHECKSUM: 62c3
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_driver/src/common/error.dart';
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
@ -13,8 +11,8 @@ import 'package:flutter_driver/src/common/layer_tree.dart';
|
||||
import 'package:flutter_driver/src/common/wait.dart';
|
||||
import 'package:flutter_driver/src/driver/driver.dart';
|
||||
import 'package:flutter_driver/src/driver/timeline.dart';
|
||||
import 'package:fake_async/fake_async.dart';
|
||||
import 'package:vm_service/vm_service.dart' as vms;
|
||||
import 'package:quiver/testing/async.dart';
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
@ -31,9 +29,9 @@ void main() {
|
||||
};
|
||||
|
||||
group('VMServiceFlutterDriver.connect', () {
|
||||
FakeVmService fakeClient;
|
||||
FakeVM fakeVM;
|
||||
FakeIsolate fakeIsolate;
|
||||
late FakeVmService fakeClient;
|
||||
late FakeVM fakeVM;
|
||||
late FakeIsolate fakeIsolate;
|
||||
|
||||
void expectLogContains(String message) {
|
||||
expect(log, anyElement(contains(message)));
|
||||
@ -44,7 +42,7 @@ void main() {
|
||||
fakeIsolate = FakeIsolate();
|
||||
fakeVM = FakeVM(fakeIsolate);
|
||||
fakeClient = FakeVmService(fakeVM);
|
||||
vmServiceConnectFunction = (String url, Map<String, dynamic> headers) async {
|
||||
vmServiceConnectFunction = (String url, Map<String, dynamic>? headers) async {
|
||||
return fakeClient;
|
||||
};
|
||||
fakeClient.responses['get_health'] = makeFakeResponse(<String, dynamic>{'status': 'ok'});
|
||||
@ -176,10 +174,10 @@ void main() {
|
||||
});
|
||||
|
||||
group('VMServiceFlutterDriver', () {
|
||||
FakeVmService fakeClient;
|
||||
late FakeVmService fakeClient;
|
||||
FakeVM fakeVM;
|
||||
FakeIsolate fakeIsolate;
|
||||
VMServiceFlutterDriver driver;
|
||||
late VMServiceFlutterDriver driver;
|
||||
|
||||
setUp(() {
|
||||
fakeIsolate = FakeIsolate();
|
||||
@ -230,10 +228,6 @@ void main() {
|
||||
});
|
||||
|
||||
group('tap', () {
|
||||
test('requires a target reference', () async {
|
||||
expect(driver.tap(null), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('sends the tap command', () async {
|
||||
await driver.tap(find.text('foo'), timeout: _kTestTimeout);
|
||||
expect(fakeClient.commandLog, <String>[
|
||||
@ -243,10 +237,6 @@ void main() {
|
||||
});
|
||||
|
||||
group('getText', () {
|
||||
test('requires a target reference', () async {
|
||||
expect(driver.getText(null), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('sends the getText command', () async {
|
||||
fakeClient.responses['get_text'] = makeFakeResponse(<String, dynamic>{'text': 'hello'});
|
||||
final String result = await driver.getText(find.byValueKey(123), timeout: _kTestTimeout);
|
||||
@ -274,10 +264,6 @@ void main() {
|
||||
});
|
||||
|
||||
group('waitFor', () {
|
||||
test('requires a target reference', () async {
|
||||
expect(driver.waitFor(null), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('sends the waitFor command', () async {
|
||||
fakeClient.responses['waitFor'] = makeFakeResponse(<String, dynamic>{});
|
||||
await driver.waitFor(find.byTooltip('foo'), timeout: _kTestTimeout);
|
||||
@ -363,14 +349,6 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
test('requires a target reference', () async {
|
||||
expect(driver.getCenter(null), throwsAssertionError);
|
||||
expect(driver.getTopLeft(null), throwsAssertionError);
|
||||
expect(driver.getTopRight(null), throwsAssertionError);
|
||||
expect(driver.getBottomLeft(null), throwsAssertionError);
|
||||
expect(driver.getBottomRight(null), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('sends the getCenter command', () async {
|
||||
final DriverOffset result = await driver.getCenter(find.byValueKey(123), timeout: _kTestTimeout);
|
||||
expect(result, const DriverOffset(11, 12));
|
||||
@ -432,7 +410,7 @@ void main() {
|
||||
'setVMTimelineFlags []',
|
||||
'getVMTimeline null null',
|
||||
]);
|
||||
expect(timeline.events.single.name, 'test event');
|
||||
expect(timeline.events!.single.name, 'test event');
|
||||
});
|
||||
|
||||
test('with clearing timeline', () async {
|
||||
@ -450,7 +428,7 @@ void main() {
|
||||
'setVMTimelineFlags []',
|
||||
'getVMTimeline 1 999999',
|
||||
]);
|
||||
expect(timeline.events.single.name, 'test event');
|
||||
expect(timeline.events!.single.name, 'test event');
|
||||
});
|
||||
|
||||
test('with time interval', () async {
|
||||
@ -479,7 +457,7 @@ void main() {
|
||||
'getVMTimeline 1 999999',
|
||||
'getVMTimeline 1000001 999999',
|
||||
]);
|
||||
expect(timeline.events.map((TimelineEvent event) => event.name), <String>[
|
||||
expect(timeline.events!.map((TimelineEvent event) => event.name), <String>[
|
||||
'test event',
|
||||
'test event 2',
|
||||
]);
|
||||
@ -508,7 +486,7 @@ void main() {
|
||||
'getVMTimeline null null'
|
||||
]);
|
||||
|
||||
expect(timeline.events.single.name, 'test event');
|
||||
expect(timeline.events!.single.name, 'test event');
|
||||
});
|
||||
});
|
||||
|
||||
@ -545,7 +523,7 @@ void main() {
|
||||
fail('expected an exception');
|
||||
} catch (error) {
|
||||
expect(error, isA<DriverError>());
|
||||
expect(error.message, 'Error in Flutter application: {message: This is a failure}');
|
||||
expect((error as DriverError).message, 'Error in Flutter application: {message: This is a failure}');
|
||||
}
|
||||
});
|
||||
|
||||
@ -570,10 +548,10 @@ void main() {
|
||||
});
|
||||
|
||||
group('VMServiceFlutterDriver with custom timeout', () {
|
||||
FakeVmService fakeClient;
|
||||
late FakeVmService fakeClient;
|
||||
FakeVM fakeVM;
|
||||
FakeIsolate fakeIsolate;
|
||||
VMServiceFlutterDriver driver;
|
||||
late VMServiceFlutterDriver driver;
|
||||
|
||||
setUp(() {
|
||||
fakeIsolate = FakeIsolate();
|
||||
@ -601,8 +579,8 @@ void main() {
|
||||
});
|
||||
|
||||
group('WebFlutterDriver', () {
|
||||
FakeFlutterWebConnection fakeConnection;
|
||||
WebFlutterDriver driver;
|
||||
late FakeFlutterWebConnection fakeConnection;
|
||||
late WebFlutterDriver driver;
|
||||
|
||||
setUp(() {
|
||||
fakeConnection = FakeFlutterWebConnection();
|
||||
@ -648,10 +626,6 @@ void main() {
|
||||
});
|
||||
|
||||
group('tap', () {
|
||||
test('requires a target reference', () async {
|
||||
expect(driver.tap(null), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('sends the tap command', () async {
|
||||
fakeConnection.responses['tap'] = jsonEncode(makeFakeResponse(<String, dynamic>{}));
|
||||
await driver.tap(find.text('foo'), timeout: _kTestTimeout);
|
||||
@ -662,10 +636,6 @@ void main() {
|
||||
});
|
||||
|
||||
group('getText', () {
|
||||
test('requires a target reference', () async {
|
||||
expect(driver.getText(null), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('sends the getText command', () async {
|
||||
fakeConnection.responses['get_text'] = jsonEncode(makeFakeResponse(<String, dynamic>{'text': 'hello'}));
|
||||
final String result = await driver.getText(find.byValueKey(123), timeout: _kTestTimeout);
|
||||
@ -677,10 +647,6 @@ void main() {
|
||||
});
|
||||
|
||||
group('waitFor', () {
|
||||
test('requires a target reference', () async {
|
||||
expect(driver.waitFor(null), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('sends the waitFor command', () async {
|
||||
fakeConnection.responses['waitFor'] = jsonEncode(makeFakeResponse(<String, dynamic>{'text': 'hello'}));
|
||||
await driver.waitFor(find.byTooltip('foo'), timeout: _kTestTimeout);
|
||||
@ -737,13 +703,6 @@ void main() {
|
||||
'dy': 12,
|
||||
}));
|
||||
});
|
||||
test('requires a target reference', () async {
|
||||
expect(driver.getCenter(null), throwsAssertionError);
|
||||
expect(driver.getTopLeft(null), throwsAssertionError);
|
||||
expect(driver.getTopRight(null), throwsAssertionError);
|
||||
expect(driver.getBottomLeft(null), throwsAssertionError);
|
||||
expect(driver.getBottomRight(null), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('sends the getCenter command', () async {
|
||||
final DriverOffset result = await driver.getCenter(find.byValueKey(123), timeout: _kTestTimeout);
|
||||
@ -824,7 +783,7 @@ void main() {
|
||||
|
||||
group('WebFlutterDriver with non-chrome browser', () {
|
||||
FakeFlutterWebConnection fakeConnection;
|
||||
WebFlutterDriver driver;
|
||||
late WebFlutterDriver driver;
|
||||
|
||||
setUp(() {
|
||||
fakeConnection = FakeFlutterWebConnection();
|
||||
@ -848,15 +807,15 @@ void main() {
|
||||
/// and return the actual script.
|
||||
/// script will be in the following format:
|
||||
// window.flutterDriver('[actual script]')
|
||||
String _checkAndEncode(dynamic script) {
|
||||
String? _checkAndEncode(dynamic script) {
|
||||
expect(script, isA<String>());
|
||||
expect(script.startsWith(_kWebScriptPrefix), isTrue);
|
||||
expect(script.endsWith(_kWebScriptSuffix), isTrue);
|
||||
// Strip prefix and suffix
|
||||
return script.substring(_kWebScriptPrefix.length, script.length - 2) as String;
|
||||
return script.substring(_kWebScriptPrefix.length, script.length - 2) as String?;
|
||||
}
|
||||
|
||||
vms.Response makeFakeResponse(
|
||||
vms.Response? makeFakeResponse(
|
||||
Map<String, dynamic> response, {
|
||||
bool isError = false,
|
||||
}) {
|
||||
@ -873,9 +832,9 @@ class FakeFlutterWebConnection extends Fake implements FlutterWebConnection {
|
||||
Map<String, dynamic> responses = <String, dynamic>{};
|
||||
List<String> commandLog = <String>[];
|
||||
@override
|
||||
Future<dynamic> sendCommand(String script, Duration duration) async {
|
||||
Future<dynamic> sendCommand(String script, Duration? duration) async {
|
||||
commandLog.add('$script $duration');
|
||||
final Map<String, dynamic> decoded = jsonDecode(_checkAndEncode(script)) as Map<String, dynamic>;
|
||||
final Map<String, dynamic> decoded = jsonDecode(_checkAndEncode(script)!) as Map<String, dynamic>;
|
||||
final dynamic response = responses[decoded['command']];
|
||||
assert(response != null, 'Missing ${decoded['command']} in responses.');
|
||||
return response;
|
||||
@ -890,27 +849,27 @@ class FakeFlutterWebConnection extends Fake implements FlutterWebConnection {
|
||||
class FakeVmService extends Fake implements vms.VmService {
|
||||
FakeVmService(this.vm);
|
||||
|
||||
FakeVM vm;
|
||||
FakeVM? vm;
|
||||
bool failOnSetFlag = false;
|
||||
bool failOnResumeWith101 = false;
|
||||
|
||||
final List<String> connectionLog = <String>[];
|
||||
|
||||
@override
|
||||
Future<vms.VM> getVM() async => vm;
|
||||
Future<vms.VM> getVM() async => vm!;
|
||||
|
||||
@override
|
||||
Future<vms.Isolate> getIsolate(String isolateId) async {
|
||||
connectionLog.add('getIsolate');
|
||||
if (isolateId == vm.isolate.id) {
|
||||
return vm.isolate;
|
||||
if (isolateId == vm!.isolate!.id) {
|
||||
return vm!.isolate!;
|
||||
}
|
||||
return null;
|
||||
throw UnimplementedError('getIsolate called with unrecognized $isolateId');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<vms.Success> resume(String isolateId, {String step, int frameIndex}) async {
|
||||
assert(isolateId == vm.isolate.id);
|
||||
Future<vms.Success> resume(String isolateId, {String? step, int? frameIndex}) async {
|
||||
assert(isolateId == vm!.isolate!.id);
|
||||
connectionLog.add('resume');
|
||||
if (failOnResumeWith101) {
|
||||
throw vms.RPCError('resume', 101, '');
|
||||
@ -950,15 +909,15 @@ class FakeVmService extends Fake implements vms.VmService {
|
||||
}
|
||||
|
||||
List<String> commandLog = <String>[];
|
||||
Map<String, vms.Response> responses = <String, vms.Response>{};
|
||||
Future<void> artificialExtensionDelay;
|
||||
Map<String, vms.Response?> responses = <String, vms.Response?>{};
|
||||
Future<void>? artificialExtensionDelay;
|
||||
|
||||
@override
|
||||
Future<vms.Response> callServiceExtension(String method, {Map<dynamic, dynamic> args, String isolateId}) async {
|
||||
Future<vms.Response> callServiceExtension(String method, {Map<dynamic, dynamic>? args, String? isolateId}) async {
|
||||
commandLog.add('$method $args');
|
||||
await artificialExtensionDelay;
|
||||
|
||||
final vms.Response response = responses[args['command']];
|
||||
final vms.Response response = responses[args!['command']]!;
|
||||
assert(response != null, 'Failed to create a response for ${args['command']}');
|
||||
return response;
|
||||
}
|
||||
@ -993,7 +952,7 @@ class FakeVmService extends Fake implements vms.VmService {
|
||||
return vms.Success();
|
||||
}
|
||||
|
||||
final Map<int, vms.Timeline> timelineResponses = <int, vms.Timeline>{
|
||||
final Map<int, vms.Timeline?> timelineResponses = <int, vms.Timeline?>{
|
||||
1: vms.Timeline.parse(<String, dynamic>{
|
||||
'traceEvents': <dynamic>[
|
||||
<String, dynamic>{
|
||||
@ -1006,9 +965,9 @@ class FakeVmService extends Fake implements vms.VmService {
|
||||
};
|
||||
|
||||
@override
|
||||
Future<vms.Timeline> getVMTimeline({int timeOriginMicros, int timeExtentMicros}) async {
|
||||
Future<vms.Timeline> getVMTimeline({int? timeOriginMicros, int? timeExtentMicros}) async {
|
||||
connectionLog.add('getVMTimeline $timeOriginMicros $timeExtentMicros');
|
||||
final vms.Timeline timeline = timelineResponses[timeOriginMicros ?? 1];
|
||||
final vms.Timeline timeline = timelineResponses[timeOriginMicros ?? 1]!;
|
||||
assert(timeline != null, 'Missing entry in timelineResponses[$timeOriginMicros]');
|
||||
return timeline;
|
||||
}
|
||||
@ -1025,7 +984,7 @@ class FakeVmService extends Fake implements vms.VmService {
|
||||
class FakeVM extends Fake implements vms.VM {
|
||||
FakeVM(this.isolate);
|
||||
|
||||
vms.Isolate isolate;
|
||||
vms.Isolate? isolate;
|
||||
|
||||
int numberOfTriesBeforeResolvingIsolate = 0;
|
||||
|
||||
@ -1034,7 +993,7 @@ class FakeVM extends Fake implements vms.VM {
|
||||
numberOfTriesBeforeResolvingIsolate -= 1;
|
||||
return <vms.Isolate>[
|
||||
if (numberOfTriesBeforeResolvingIsolate <= 0)
|
||||
isolate,
|
||||
isolate!,
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1047,7 +1006,7 @@ class FakeIsolate extends Fake implements vms.Isolate {
|
||||
String get id => number;
|
||||
|
||||
@override
|
||||
vms.Event pauseEvent;
|
||||
vms.Event? pauseEvent;
|
||||
|
||||
@override
|
||||
List<String> get extensionRPCs => <String>[];
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
@ -37,14 +35,14 @@ Future<void> silenceDriverLogger(AsyncCallback callback) async {
|
||||
|
||||
void main() {
|
||||
group('waitUntilNoTransientCallbacks', () {
|
||||
FlutterDriverExtension driverExtension;
|
||||
Map<String, dynamic> result;
|
||||
late FlutterDriverExtension driverExtension;
|
||||
Map<String, dynamic>? result;
|
||||
int messageId = 0;
|
||||
final List<String> log = <String>[];
|
||||
final List<String?> log = <String?>[];
|
||||
|
||||
setUp(() {
|
||||
result = null;
|
||||
driverExtension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false, true);
|
||||
driverExtension = FlutterDriverExtension((String? message) async { log.add(message); return (messageId += 1).toString(); }, false, true);
|
||||
});
|
||||
|
||||
testWidgets('returns immediately when transient callback queue is empty', (WidgetTester tester) async {
|
||||
@ -64,7 +62,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('waits until no transient callbacks', (WidgetTester tester) async {
|
||||
SchedulerBinding.instance.scheduleFrameCallback((_) {
|
||||
SchedulerBinding.instance!.scheduleFrameCallback((_) {
|
||||
// Intentionally blank. We only care about existence of a callback.
|
||||
});
|
||||
|
||||
@ -98,14 +96,14 @@ void main() {
|
||||
});
|
||||
|
||||
group('waitForCondition', () {
|
||||
FlutterDriverExtension driverExtension;
|
||||
Map<String, dynamic> result;
|
||||
late FlutterDriverExtension driverExtension;
|
||||
Map<String, dynamic>? result;
|
||||
int messageId = 0;
|
||||
final List<String> log = <String>[];
|
||||
final List<String?> log = <String?>[];
|
||||
|
||||
setUp(() {
|
||||
result = null;
|
||||
driverExtension = FlutterDriverExtension((String message) async { log.add(message); return (messageId += 1).toString(); }, false, true);
|
||||
driverExtension = FlutterDriverExtension((String? message) async { log.add(message); return (messageId += 1).toString(); }, false, true);
|
||||
});
|
||||
|
||||
testWidgets('waiting for NoTransientCallbacks returns immediately when transient callback queue is empty', (WidgetTester tester) async {
|
||||
@ -125,7 +123,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('waiting for NoTransientCallbacks returns until no transient callbacks', (WidgetTester tester) async {
|
||||
SchedulerBinding.instance.scheduleFrameCallback((_) {
|
||||
SchedulerBinding.instance!.scheduleFrameCallback((_) {
|
||||
// Intentionally blank. We only care about existence of a callback.
|
||||
});
|
||||
|
||||
@ -167,7 +165,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('waiting for NoPendingFrame returns until no pending scheduled frame', (WidgetTester tester) async {
|
||||
SchedulerBinding.instance.scheduleFrame();
|
||||
SchedulerBinding.instance!.scheduleFrame();
|
||||
|
||||
driverExtension.call(const WaitForCondition(NoPendingFrame()).serialize())
|
||||
.then<void>(expectAsync1((Map<String, dynamic> r) {
|
||||
@ -210,8 +208,8 @@ void main() {
|
||||
|
||||
testWidgets(
|
||||
'waiting for combined conditions returns until no transient callbacks', (WidgetTester tester) async {
|
||||
SchedulerBinding.instance.scheduleFrame();
|
||||
SchedulerBinding.instance.scheduleFrameCallback((_) {
|
||||
SchedulerBinding.instance!.scheduleFrame();
|
||||
SchedulerBinding.instance!.scheduleFrameCallback((_) {
|
||||
// Intentionally blank. We only care about existence of a callback.
|
||||
});
|
||||
|
||||
@ -239,8 +237,8 @@ void main() {
|
||||
|
||||
testWidgets(
|
||||
'waiting for combined conditions returns until no pending scheduled frame', (WidgetTester tester) async {
|
||||
SchedulerBinding.instance.scheduleFrame();
|
||||
SchedulerBinding.instance.scheduleFrameCallback((_) {
|
||||
SchedulerBinding.instance!.scheduleFrame();
|
||||
SchedulerBinding.instance!.scheduleFrameCallback((_) {
|
||||
// Intentionally blank. We only care about existence of a callback.
|
||||
});
|
||||
|
||||
@ -288,11 +286,11 @@ 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(
|
||||
'helloChannel', (ByteData message) {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 10),
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world']));
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world'])!);
|
||||
});
|
||||
channel.invokeMethod<String>('sayHello', 'hello');
|
||||
|
||||
@ -322,20 +320,20 @@ void main() {
|
||||
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
|
||||
// Configures channel 1
|
||||
const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
|
||||
ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel1', (ByteData message) {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel1', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 10),
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world']));
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world'])!);
|
||||
});
|
||||
|
||||
// Configures channel 2
|
||||
const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
|
||||
ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel2', (ByteData message) {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel2', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 20),
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world']));
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world'])!);
|
||||
});
|
||||
|
||||
channel1.invokeMethod<String>('sayHello', 'hello');
|
||||
@ -371,20 +369,20 @@ void main() {
|
||||
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
|
||||
// Configures channel 1
|
||||
const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
|
||||
ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel1', (ByteData message) {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel1', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 10),
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world']));
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world'])!);
|
||||
});
|
||||
|
||||
// Configures channel 2
|
||||
const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
|
||||
ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel2', (ByteData message) {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel2', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 20),
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world']));
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world'])!);
|
||||
});
|
||||
|
||||
channel1.invokeMethod<String>('sayHello', 'hello');
|
||||
@ -422,20 +420,20 @@ void main() {
|
||||
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
|
||||
// Configures channel 1
|
||||
const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
|
||||
ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel1', (ByteData message) {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel1', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 20),
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world']));
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world'])!);
|
||||
});
|
||||
|
||||
// Configures channel 2
|
||||
const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
|
||||
ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel2', (ByteData message) {
|
||||
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
|
||||
'helloChannel2', (ByteData? message) {
|
||||
return Future<ByteData>.delayed(
|
||||
const Duration(milliseconds: 10),
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world']));
|
||||
() => jsonMessage.encodeMessage(<dynamic>['hello world'])!);
|
||||
});
|
||||
|
||||
channel1.invokeMethod<String>('sayHello', 'hello');
|
||||
@ -469,13 +467,13 @@ void main() {
|
||||
});
|
||||
|
||||
group('getSemanticsId', () {
|
||||
FlutterDriverExtension driverExtension;
|
||||
late FlutterDriverExtension driverExtension;
|
||||
setUp(() {
|
||||
driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
});
|
||||
|
||||
testWidgets('works when semantics are enabled', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = RendererBinding.instance.pipelineOwner.ensureSemantics();
|
||||
final SemanticsHandle semantics = RendererBinding.instance!.pipelineOwner.ensureSemantics();
|
||||
await tester.pumpWidget(
|
||||
const Text('hello', textDirection: TextDirection.ltr));
|
||||
|
||||
@ -499,7 +497,7 @@ void main() {
|
||||
}, semanticsEnabled: false);
|
||||
|
||||
testWidgets('throws state error multiple matches are found', (WidgetTester tester) async {
|
||||
final SemanticsHandle semantics = RendererBinding.instance.pipelineOwner.ensureSemantics();
|
||||
final SemanticsHandle semantics = RendererBinding.instance!.pipelineOwner.ensureSemantics();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
@ -520,7 +518,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('getOffset', (WidgetTester tester) async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
|
||||
Future<Offset> getOffset(OffsetType offset) async {
|
||||
final Map<String, String> arguments = GetOffset(ByValueKey(1), offset).serialize();
|
||||
@ -552,9 +550,9 @@ void main() {
|
||||
|
||||
testWidgets('getText', (WidgetTester tester) async {
|
||||
await silenceDriverLogger(() async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
|
||||
Future<String> getTextInternal(SerializableFinder search) async {
|
||||
Future<String?> getTextInternal(SerializableFinder search) async {
|
||||
final Map<String, String> arguments = GetText(search, timeout: const Duration(seconds: 1)).serialize();
|
||||
final Map<String, dynamic> result = await driverExtension.call(arguments);
|
||||
if (result['isError'] as bool) {
|
||||
@ -622,9 +620,9 @@ void main() {
|
||||
|
||||
testWidgets('descendant finder', (WidgetTester tester) async {
|
||||
await silenceDriverLogger(() async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
|
||||
Future<String> getDescendantText({ String of, bool matchRoot = false}) async {
|
||||
Future<String?> getDescendantText({ String? of, bool matchRoot = false}) async {
|
||||
final Map<String, String> arguments = GetText(Descendant(
|
||||
of: ByValueKey(of),
|
||||
matching: ByValueKey('text2'),
|
||||
@ -655,7 +653,7 @@ void main() {
|
||||
expect(await getDescendantText(of: 'text2', matchRoot: true), 'Hello2');
|
||||
|
||||
// Find nothing
|
||||
Future<String> result = getDescendantText(of: 'text1', matchRoot: true);
|
||||
Future<String?> result = getDescendantText(of: 'text1', matchRoot: true);
|
||||
await tester.pump(const Duration(seconds: 2));
|
||||
expect(await result, null);
|
||||
|
||||
@ -667,9 +665,9 @@ void main() {
|
||||
|
||||
testWidgets('descendant finder firstMatchOnly', (WidgetTester tester) async {
|
||||
await silenceDriverLogger(() async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
|
||||
Future<String> getDescendantText() async {
|
||||
Future<String?> getDescendantText() async {
|
||||
final Map<String, String> arguments = GetText(Descendant(
|
||||
of: ByValueKey('column'),
|
||||
matching: const ByType('Text'),
|
||||
@ -701,9 +699,9 @@ void main() {
|
||||
|
||||
testWidgets('ancestor finder', (WidgetTester tester) async {
|
||||
await silenceDriverLogger(() async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
|
||||
Future<Offset> getAncestorTopLeft({ String of, String matching, bool matchRoot = false}) async {
|
||||
Future<Offset?> getAncestorTopLeft({ String? of, String? matching, bool matchRoot = false}) async {
|
||||
final Map<String, String> arguments = GetOffset(Ancestor(
|
||||
of: ByValueKey(of),
|
||||
matching: ByValueKey(matching),
|
||||
@ -759,7 +757,7 @@ void main() {
|
||||
);
|
||||
|
||||
// Find nothing
|
||||
Future<Offset> result = getAncestorTopLeft(of: 'leftchild', matching: 'leftchild');
|
||||
Future<Offset?> result = getAncestorTopLeft(of: 'leftchild', matching: 'leftchild');
|
||||
await tester.pump(const Duration(seconds: 2));
|
||||
expect(await result, null);
|
||||
|
||||
@ -771,9 +769,9 @@ void main() {
|
||||
|
||||
testWidgets('ancestor finder firstMatchOnly', (WidgetTester tester) async {
|
||||
await silenceDriverLogger(() async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
|
||||
Future<Offset> getAncestorTopLeft() async {
|
||||
Future<Offset?> getAncestorTopLeft() async {
|
||||
final Map<String, String> arguments = GetOffset(Ancestor(
|
||||
of: ByValueKey('leaf'),
|
||||
matching: const ByType('Container'),
|
||||
@ -819,9 +817,9 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('GetDiagnosticsTree', (WidgetTester tester) async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
|
||||
Future<Map<String, Object>> getDiagnosticsTree(DiagnosticsType type, SerializableFinder finder, { int depth = 0, bool properties = true }) async {
|
||||
Future<Map<String, dynamic>> getDiagnosticsTree(DiagnosticsType type, SerializableFinder finder, { int depth = 0, bool properties = true }) async {
|
||||
final Map<String, String> arguments = GetDiagnosticsTree(finder, type, subtreeDepth: depth, includeProperties: properties).serialize();
|
||||
final Map<String, dynamic> response = await driverExtension.call(arguments);
|
||||
final DiagnosticsTreeResult result = DiagnosticsTreeResult(response['response'] as Map<String, dynamic>);
|
||||
@ -838,12 +836,12 @@ void main() {
|
||||
);
|
||||
|
||||
// Widget
|
||||
Map<String, Object> result = await getDiagnosticsTree(DiagnosticsType.widget, ByValueKey('Text'), depth: 0);
|
||||
Map<String, dynamic> result = await getDiagnosticsTree(DiagnosticsType.widget, ByValueKey('Text'), depth: 0);
|
||||
expect(result['children'], isNull); // depth: 0
|
||||
expect(result['widgetRuntimeType'], 'Text');
|
||||
|
||||
List<Map<String, Object>> properties = (result['properties'] as List<dynamic>).cast<Map<String, Object>>();
|
||||
Map<String, Object> stringProperty = properties.singleWhere((Map<String, Object> property) => property['name'] == 'data');
|
||||
List<Map<String, dynamic>> properties = (result['properties']! as List<Object>).cast<Map<String, dynamic>>();
|
||||
Map<String, dynamic> stringProperty = properties.singleWhere((Map<String, dynamic> property) => property['name'] == 'data');
|
||||
expect(stringProperty['description'], '"Hello World"');
|
||||
expect(stringProperty['propertyType'], 'String');
|
||||
|
||||
@ -852,11 +850,11 @@ void main() {
|
||||
expect(result['properties'], isNull); // properties: false
|
||||
|
||||
result = await getDiagnosticsTree(DiagnosticsType.widget, ByValueKey('Text'), depth: 1);
|
||||
List<Map<String, Object>> children = (result['children'] as List<dynamic>).cast<Map<String, Object>>();
|
||||
List<Map<String, dynamic>> children = (result['children']! as List<Object>).cast<Map<String, dynamic>>();
|
||||
expect(children.single['children'], isNull);
|
||||
|
||||
result = await getDiagnosticsTree(DiagnosticsType.widget, ByValueKey('Text'), depth: 100);
|
||||
children = (result['children'] as List<dynamic>).cast<Map<String, Object>>();
|
||||
children = (result['children']! as List<Object>).cast<Map<String, dynamic>>();
|
||||
expect(children.single['children'], isEmpty);
|
||||
|
||||
// RenderObject
|
||||
@ -870,22 +868,22 @@ void main() {
|
||||
expect(result['description'], startsWith('RenderParagraph'));
|
||||
|
||||
result = await getDiagnosticsTree(DiagnosticsType.renderObject, ByValueKey('Text'), depth: 1);
|
||||
children = (result['children'] as List<dynamic>).cast<Map<String, Object>>();
|
||||
final Map<String, Object> textSpan = children.single;
|
||||
children = (result['children']! as List<Object>).cast<Map<String, dynamic>>();
|
||||
final Map<String, dynamic> textSpan = children.single;
|
||||
expect(textSpan['description'], 'TextSpan');
|
||||
properties = (textSpan['properties'] as List<dynamic>).cast<Map<String, Object>>();
|
||||
stringProperty = properties.singleWhere((Map<String, Object> property) => property['name'] == 'text');
|
||||
properties = (textSpan['properties']! as List<Object>).cast<Map<String, dynamic>>();
|
||||
stringProperty = properties.singleWhere((Map<String, dynamic> property) => property['name'] == 'text');
|
||||
expect(stringProperty['description'], '"Hello World"');
|
||||
expect(stringProperty['propertyType'], 'String');
|
||||
expect(children.single['children'], isNull);
|
||||
|
||||
result = await getDiagnosticsTree(DiagnosticsType.renderObject, ByValueKey('Text'), depth: 100);
|
||||
children = (result['children'] as List<dynamic>).cast<Map<String, Object>>();
|
||||
children = (result['children']! as List<Object>).cast<Map<String, dynamic>>();
|
||||
expect(children.single['children'], isEmpty);
|
||||
});
|
||||
|
||||
group('enableTextEntryEmulation', () {
|
||||
FlutterDriverExtension driverExtension;
|
||||
late FlutterDriverExtension driverExtension;
|
||||
|
||||
Future<Map<String, dynamic>> enterText() async {
|
||||
final Map<String, String> arguments = const EnterText('foo').serialize();
|
||||
@ -905,7 +903,7 @@ void main() {
|
||||
);
|
||||
|
||||
testWidgets('enableTextEntryEmulation false', (WidgetTester tester) async {
|
||||
driverExtension = FlutterDriverExtension((String arg) async => '', true, false);
|
||||
driverExtension = FlutterDriverExtension((String? arg) async => '', true, false);
|
||||
|
||||
await tester.pumpWidget(testWidget);
|
||||
|
||||
@ -914,7 +912,7 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('enableTextEntryEmulation true', (WidgetTester tester) async {
|
||||
driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
|
||||
await tester.pumpWidget(testWidget);
|
||||
|
||||
@ -944,7 +942,7 @@ void main() {
|
||||
|
||||
testWidgets('unknown extension finder', (WidgetTester tester) async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
|
||||
(String arg) async => '',
|
||||
(String? arg) async => '',
|
||||
true,
|
||||
true,
|
||||
finders: <FinderExtension>[],
|
||||
@ -960,12 +958,12 @@ void main() {
|
||||
final Map<String, dynamic> result = await getText(StubFinder('Text1'));
|
||||
expect(result['isError'], true);
|
||||
expect(result['response'] is String, true);
|
||||
expect(result['response'] as String, contains('Unsupported search specification type Stub'));
|
||||
expect(result['response'] as String?, contains('Unsupported search specification type Stub'));
|
||||
});
|
||||
|
||||
testWidgets('simple extension finder', (WidgetTester tester) async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
|
||||
(String arg) async => '',
|
||||
(String? arg) async => '',
|
||||
true,
|
||||
true,
|
||||
finders: <FinderExtension>[
|
||||
@ -987,7 +985,7 @@ void main() {
|
||||
|
||||
testWidgets('complex extension finder', (WidgetTester tester) async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
|
||||
(String arg) async => '',
|
||||
(String? arg) async => '',
|
||||
true,
|
||||
true,
|
||||
finders: <FinderExtension>[
|
||||
@ -1009,7 +1007,7 @@ void main() {
|
||||
|
||||
testWidgets('extension finder with command', (WidgetTester tester) async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
|
||||
(String arg) async => '',
|
||||
(String? arg) async => '',
|
||||
true,
|
||||
true,
|
||||
finders: <FinderExtension>[
|
||||
@ -1054,7 +1052,7 @@ void main() {
|
||||
|
||||
testWidgets('unknown extension command', (WidgetTester tester) async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
|
||||
(String arg) async => '',
|
||||
(String? arg) async => '',
|
||||
true,
|
||||
true,
|
||||
commands: <CommandExtension>[],
|
||||
@ -1070,12 +1068,12 @@ void main() {
|
||||
final Map<String, dynamic> result = await invokeCommand(ByValueKey('Button'), 10);
|
||||
expect(result['isError'], true);
|
||||
expect(result['response'] is String, true);
|
||||
expect(result['response'] as String, contains('Unsupported command kind StubNestedCommand'));
|
||||
expect(result['response'] as String?, contains('Unsupported command kind StubNestedCommand'));
|
||||
});
|
||||
|
||||
testWidgets('nested command', (WidgetTester tester) async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
|
||||
(String arg) async => '',
|
||||
(String? arg) async => '',
|
||||
true,
|
||||
true,
|
||||
commands: <CommandExtension>[
|
||||
@ -1101,7 +1099,7 @@ void main() {
|
||||
|
||||
testWidgets('prober command', (WidgetTester tester) async {
|
||||
final FlutterDriverExtension driverExtension = FlutterDriverExtension(
|
||||
(String arg) async => '',
|
||||
(String? arg) async => '',
|
||||
true,
|
||||
true,
|
||||
commands: <CommandExtension>[
|
||||
@ -1127,11 +1125,11 @@ void main() {
|
||||
});
|
||||
|
||||
group('waitUntilFrameSync', () {
|
||||
FlutterDriverExtension driverExtension;
|
||||
Map<String, dynamic> result;
|
||||
late FlutterDriverExtension driverExtension;
|
||||
Map<String, dynamic>? result;
|
||||
|
||||
setUp(() {
|
||||
driverExtension = FlutterDriverExtension((String arg) async => '', true, true);
|
||||
driverExtension = FlutterDriverExtension((String? arg) async => '', true, true);
|
||||
result = null;
|
||||
});
|
||||
|
||||
@ -1154,7 +1152,7 @@ void main() {
|
||||
|
||||
testWidgets(
|
||||
'waits until no transient callbacks', (WidgetTester tester) async {
|
||||
SchedulerBinding.instance.scheduleFrameCallback((_) {
|
||||
SchedulerBinding.instance!.scheduleFrameCallback((_) {
|
||||
// Intentionally blank. We only care about existence of a callback.
|
||||
});
|
||||
|
||||
@ -1180,7 +1178,7 @@ void main() {
|
||||
|
||||
testWidgets(
|
||||
'waits until no pending scheduled frame', (WidgetTester tester) async {
|
||||
SchedulerBinding.instance.scheduleFrame();
|
||||
SchedulerBinding.instance!.scheduleFrame();
|
||||
|
||||
driverExtension.call(const WaitForCondition(NoPendingFrame()).serialize())
|
||||
.then<void>(expectAsync1((Map<String, dynamic> r) {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
import 'package:flutter_driver/flutter_driver.dart';
|
||||
import 'package:flutter_driver/src/common/find.dart';
|
||||
|
@ -2,15 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter_driver/src/extension/_extension_io.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
|
||||
void main() {
|
||||
group('test io_extension',() {
|
||||
Future<Map<String, dynamic>> Function(Map<String, String>) call;
|
||||
late Future<Map<String, dynamic>> Function(Map<String, String>) call;
|
||||
|
||||
setUp(() {
|
||||
call = (Map<String, String> args) async {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter_driver/flutter_driver.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:convert' show json;
|
||||
|
||||
import 'package:file/file.dart';
|
||||
@ -409,7 +407,7 @@ void main() {
|
||||
|
||||
group('writeTimelineToFile', () {
|
||||
|
||||
Directory tempDir;
|
||||
late Directory tempDir;
|
||||
|
||||
setUp(() {
|
||||
useMemoryFileSystemForTesting();
|
||||
@ -480,7 +478,7 @@ void main() {
|
||||
final Timeline timeline = Timeline.fromJson(<String, dynamic>{
|
||||
'traceEvents': traceEvents,
|
||||
});
|
||||
return SceneDisplayLagSummarizer(timeline.events);
|
||||
return SceneDisplayLagSummarizer(timeline.events!);
|
||||
}
|
||||
|
||||
test('average_vsyncs_missed', () async {
|
||||
@ -531,7 +529,7 @@ void main() {
|
||||
final Timeline timeline = Timeline.fromJson(<String, dynamic>{
|
||||
'traceEvents': traceEvents,
|
||||
});
|
||||
return ProfilingSummarizer.fromEvents(timeline.events);
|
||||
return ProfilingSummarizer.fromEvents(timeline.events!);
|
||||
}
|
||||
|
||||
test('has_both_cpu_and_memory_usage', () async {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter_driver/src/driver/timeline.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
@ -34,7 +32,7 @@ void main() {
|
||||
|
||||
expect(timeline.events, hasLength(2));
|
||||
|
||||
final TimelineEvent e1 = timeline.events[1];
|
||||
final TimelineEvent e1 = timeline.events![1];
|
||||
expect(e1.name, 'test event');
|
||||
expect(e1.category, 'test category');
|
||||
expect(e1.phase, 'B');
|
||||
@ -46,7 +44,7 @@ void main() {
|
||||
expect(e1.threadTimestampMicros, 567);
|
||||
expect(e1.arguments, <String, dynamic>{'arg1': true});
|
||||
|
||||
final TimelineEvent e2 = timeline.events[0];
|
||||
final TimelineEvent e2 = timeline.events![0];
|
||||
expect(e2.name, isNull);
|
||||
expect(e2.category, isNull);
|
||||
expect(e2.phase, isNull);
|
||||
@ -74,10 +72,10 @@ void main() {
|
||||
});
|
||||
|
||||
expect(timeline.events, hasLength(2));
|
||||
expect(timeline.events[0].timestampMicros, equals(456));
|
||||
expect(timeline.events[1].timestampMicros, equals(457));
|
||||
expect(timeline.events[0].name, equals('test event 2'));
|
||||
expect(timeline.events[1].name, equals('test event 1'));
|
||||
expect(timeline.events![0].timestampMicros, equals(456));
|
||||
expect(timeline.events![1].timestampMicros, equals(457));
|
||||
expect(timeline.events![0].name, equals('test event 2'));
|
||||
expect(timeline.events![1].name, equals('test event 1'));
|
||||
});
|
||||
|
||||
test('sorts JSON nulls first', () {
|
||||
@ -103,14 +101,14 @@ void main() {
|
||||
});
|
||||
|
||||
expect(timeline.events, hasLength(4));
|
||||
expect(timeline.events[0].timestampMicros, isNull);
|
||||
expect(timeline.events[1].timestampMicros, isNull);
|
||||
expect(timeline.events[2].timestampMicros, equals(456));
|
||||
expect(timeline.events[3].timestampMicros, equals(457));
|
||||
expect(timeline.events[0].name, equals('test event 0'));
|
||||
expect(timeline.events[1].name, equals('test event 3'));
|
||||
expect(timeline.events[2].name, equals('test event 2'));
|
||||
expect(timeline.events[3].name, equals('test event 1'));
|
||||
expect(timeline.events![0].timestampMicros, isNull);
|
||||
expect(timeline.events![1].timestampMicros, isNull);
|
||||
expect(timeline.events![2].timestampMicros, equals(456));
|
||||
expect(timeline.events![3].timestampMicros, equals(457));
|
||||
expect(timeline.events![0].name, equals('test event 0'));
|
||||
expect(timeline.events![1].name, equals('test event 3'));
|
||||
expect(timeline.events![2].name, equals('test event 2'));
|
||||
expect(timeline.events![3].name, equals('test event 1'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter_driver/src/common/wait.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import '../test/common.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import '../test/common.dart';
|
||||
|
||||
void main() {
|
||||
|
Loading…
Reference in New Issue
Block a user