Flutter_driver nnbd (#74856)

This commit is contained in:
Dan Field 2021-01-27 23:55:26 -08:00 committed by GitHub
parent 650b240634
commit 3ece9c63d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 291 additions and 380 deletions

View file

@ -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);

View file

@ -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.
///

View file

@ -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() {

View file

@ -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);
}

View file

@ -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';

View file

@ -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);

View file

@ -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) {

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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!);
},
);

View file

@ -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);

View file

@ -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',

View file

@ -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

View file

@ -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';

View file

@ -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>[];

View file

@ -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) {

View file

@ -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';

View file

@ -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 {

View file

@ -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';

View file

@ -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 {

View file

@ -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'));
});
});
}

View file

@ -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';

View file

@ -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() {

View file

@ -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() {

View file

@ -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() {

View file

@ -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() {