Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/integration_test/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# CHANGELOG

## 0.10.0-nullsafety

* (Prelease) Migration for sound null safety in Dart.

## 0.9.2+1

* Update android compileSdkVersion to 29.
Expand Down
4 changes: 4 additions & 0 deletions packages/integration_test/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include: ../../analysis_options.yaml
analyzer:
enable-experiment:
- non-nullable
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ void main() {
find.byWidgetPredicate(
(Widget widget) =>
widget is Text &&
widget.data.startsWith('Platform: ${Platform.operatingSystem}'),
widget.data != null &&
widget.data!.startsWith('Platform: ${Platform.operatingSystem}'),
),
findsOneWidget,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ void main() {
find.byWidgetPredicate(
(Widget widget) =>
widget is Text &&
widget.data
widget.data != null &&
widget.data!
.startsWith('Platform: ${html.window.navigator.platform}\n'),
),
findsOneWidget,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ void main() {
find.byWidgetPredicate(
(Widget widget) =>
widget is Text &&
widget.data.startsWith('Platform: ${Platform.operatingSystem}'),
widget.data != null &&
widget.data!.startsWith('Platform: ${Platform.operatingSystem}'),
),
findsOneWidget,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import 'package:integration_test_example/main.dart' as app;

void main() {
final IntegrationTestWidgetsFlutterBinding binding =
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
IntegrationTestWidgetsFlutterBinding.ensureInitialized()
as IntegrationTestWidgetsFlutterBinding;

testWidgets('verify text', (WidgetTester tester) async {
// Build our app and trigger a frame.
Expand All @@ -31,7 +32,8 @@ void main() {
find.byWidgetPredicate(
(Widget widget) =>
widget is Text &&
widget.data
widget.data != null &&
widget.data!
.startsWith('Platform: ${html.window.navigator.platform}\n'),
),
findsOneWidget,
Expand Down
2 changes: 1 addition & 1 deletion packages/integration_test/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Demonstrates how to use the integration_test plugin.
publish_to: 'none'

environment:
sdk: ">=2.1.0 <3.0.0"
sdk: '>=2.10.0-56.0.dev <3.0.0'
flutter: ">=1.6.7 <2.0.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also update flutter version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the Dart constraint will take care of that, but we could.


dependencies:
Expand Down
4 changes: 3 additions & 1 deletion packages/integration_test/example/test_driver/failure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ void main() {
await expectLater(
find.byWidgetPredicate(
(Widget widget) =>
widget is Text && widget.data.startsWith('This should fail'),
widget is Text &&
widget.data != null &&
widget.data!.startsWith('This should fail'),
),
findsOneWidget,
);
Expand Down
2 changes: 1 addition & 1 deletion packages/integration_test/lib/_callback_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class IOCallbackManager implements CallbackManager {
@override
Future<Map<String, dynamic>> callback(
Map<String, String> params, IntegrationTestResults testRunner) async {
final String command = params['command'];
final String command = params['command'] as String;
Map<String, String> response;
switch (command) {
case 'request_data':
Expand Down
5 changes: 2 additions & 3 deletions packages/integration_test/lib/_callback_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,13 @@ class WebCallbackManager implements CallbackManager {
@override
Future<Map<String, dynamic>> callback(
Map<String, String> params, IntegrationTestResults testRunner) async {
final String command = params['command'];
final String command = params['command'] as String;
Map<String, String> response;
switch (command) {
case 'request_data':
return params['message'] == null
? _requestData(testRunner)
: _requestDataWithMessage(params['message'], testRunner);
break;
: _requestDataWithMessage(params['message'] as String, testRunner);
case 'get_health':
response = <String, String>{'status': 'ok'};
break;
Expand Down
38 changes: 19 additions & 19 deletions packages/integration_test/lib/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,26 @@ class Response {
final bool _allTestsPassed;

/// The extra information to be added along side the test result.
Map<String, dynamic> data;
Map<String, dynamic>? data;

/// Constructor to use for positive response.
Response.allTestsPassed({this.data})
: this._allTestsPassed = true,
this._failureDetails = null;
: _allTestsPassed = true,
_failureDetails = <Failure>[];

/// Constructor for failure response.
Response.someTestsFailed(this._failureDetails, {this.data})
: this._allTestsPassed = false;
: _allTestsPassed = false;

/// Constructor for failure response.
Response.toolException({String ex})
: this._allTestsPassed = false,
this._failureDetails = [Failure('ToolException', ex)];
Response.toolException({String? ex})
: _allTestsPassed = false,
_failureDetails = <Failure>[Failure('ToolException', ex)];

/// Constructor for web driver commands response.
Response.webDriverCommand({this.data})
: this._allTestsPassed = false,
this._failureDetails = null;
: _allTestsPassed = false,
_failureDetails = <Failure>[];

/// Whether the test ran successfully or not.
bool get allTestsPassed => _allTestsPassed;
Expand Down Expand Up @@ -86,8 +86,8 @@ class Response {

/// Create a list of Strings from [_failureDetails].
List<String> _failureDetailsAsString() {
final List<String> list = List<String>();
if (_failureDetails == null || _failureDetails.isEmpty) {
final List<String> list = <String>[];
if (_failureDetails.isEmpty) {
return list;
}

Expand All @@ -100,7 +100,7 @@ class Response {

/// Creates a [Failure] list using a json response.
static List<Failure> _failureDetailsFromJson(List<dynamic> list) {
final List<Failure> failureList = List<Failure>();
final List<Failure> failureList = <Failure>[];
list.forEach((s) {
final String failure = s as String;
failureList.add(Failure.fromJsonString(failure));
Expand All @@ -115,14 +115,14 @@ class Failure {
final String methodName;

/// The details of the failure such as stack trace.
final String details;
final String? details;

/// Constructor requiring all fields during initialization.
Failure(this.methodName, this.details);

/// Serializes the object to JSON.
String toJson() {
return json.encode(<String, String>{
return json.encode(<String, String?>{
'methodName': methodName,
'details': details,
});
Expand Down Expand Up @@ -244,13 +244,13 @@ class WebDriverCommand {

/// Constructor for [WebDriverCommandType.noop] command.
WebDriverCommand.noop()
: this.type = WebDriverCommandType.noop,
this.values = Map();
: type = WebDriverCommandType.noop,
values = Map();

/// Constructor for [WebDriverCommandType.noop] screenshot.
WebDriverCommand.screenshot(String screenshot_name)
: this.type = WebDriverCommandType.screenshot,
this.values = {'screenshot_name': screenshot_name};
: type = WebDriverCommandType.screenshot,
values = {'screenshot_name': screenshot_name};

/// Util method for converting [WebDriverCommandType] to a map entry.
///
Expand Down Expand Up @@ -294,7 +294,7 @@ abstract class IntegrationTestResults {
List<Failure> get failureMethodsDetails;

/// The extra data for the reported result.
Map<String, dynamic> get reportData;
Map<String, dynamic>? get reportData;

/// Whether all the test methods completed succesfully.
Completer<bool> get allTestsPassed;
Expand Down
66 changes: 36 additions & 30 deletions packages/integration_test/lib/integration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
@override
bool get registerTestTextInput => false;

Size _surfaceSize;
Size? _surfaceSize;

// This flag is used to print warning messages when tracking performance
// under debug mode.
Expand All @@ -91,7 +91,7 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
///
/// Set to null to use the default surface size.
@override
Future<void> setSurfaceSize(Size size) {
Future<void> setSurfaceSize(Size? size) {
return TestAsyncUtils.guard<void>(() async {
assert(inTest);
if (_surfaceSize == size) {
Expand Down Expand Up @@ -123,12 +123,17 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
///
/// Returns an instance of the [IntegrationTestWidgetsFlutterBinding], creating and
/// initializing it if necessary.
static WidgetsBinding ensureInitialized() {
static WidgetsBinding ensureInitialized(
{@visibleForTesting vm.VmService? vmService}) {
if (WidgetsBinding.instance == null) {
IntegrationTestWidgetsFlutterBinding();
}
assert(WidgetsBinding.instance is IntegrationTestWidgetsFlutterBinding);
return WidgetsBinding.instance;
if (vmService != null) {
(WidgetsBinding.instance as IntegrationTestWidgetsFlutterBinding)
._cachedVmService = vmService;
}
return WidgetsBinding.instance!;
}

static const MethodChannel _channel =
Expand All @@ -150,9 +155,9 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
///
/// The default value is `null`.
@override
Map<String, dynamic> get reportData => _reportData;
Map<String, dynamic> _reportData;
set reportData(Map<String, dynamic> data) => this._reportData = data;
Map<String, dynamic>? get reportData => _reportData;
Map<String, dynamic>? _reportData;
set reportData(Map<String, dynamic>? data) => this._reportData = data;

/// Manages callbacks received from driver side and commands send to driver
/// side.
Expand Down Expand Up @@ -189,7 +194,7 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
Future<void> testBody(),
VoidCallback invariantTester, {
String description = '',
Duration timeout,
Duration? timeout,
}) async {
await super.runTest(
testBody,
Expand All @@ -200,28 +205,28 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
results[description] ??= _success;
}

vm.VmService _vmService;
vm.VmService? _cachedVmService;
Future<vm.VmService> get _vmService async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change related to nnbd?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be split out into a separate patch. It came up because with nnbd I had to think more carefully about whether this property was nullable or not, and when it'd be set, and came to realize it was getting set by a method when another method might want to use it too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, let's keep it here. I think it's enough as long as we add it to the change log/pr description (if something goes wrong it will be easier to see 😅 )

if (_cachedVmService == null) {
final developer.ServiceProtocolInfo info =
await developer.Service.getInfo();
assert(info.serverUri != null);
_cachedVmService = await vm_io.vmServiceConnectUri(
'ws://localhost:${info.serverUri!.port}${info.serverUri!.path}ws',
);
}
return _cachedVmService!;
}

/// Initialize the [vm.VmService] settings for the timeline.
@visibleForTesting
Future<void> enableTimeline({
List<String> streams = const <String>['all'],
@visibleForTesting vm.VmService vmService,
}) async {
assert(streams != null);
assert(streams != null); // ignore: unnecessary_null_comparison
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line seems no longer necessary when we have null-safety.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still useful when not in sound null safety e.g. importing a non nnbd package

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: does it make sense to merge to asserts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nturgut I'm not sure I'm understanding what merge asserts would be in this context...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's very nit :)

assert(streams !=null && streams. isNotEmpty, 'Non empty stream is required')

assert(streams.isNotEmpty);
if (vmService != null) {
_vmService = vmService;
}
if (_vmService == null) {
final developer.ServiceProtocolInfo info =
await developer.Service.getInfo();
assert(info.serverUri != null);
_vmService = await vm_io.vmServiceConnectUri(
'ws://localhost:${info.serverUri.port}${info.serverUri.path}ws',
);
}
await _vmService.setVMTimelineFlags(streams);
final vm.VmService vmService = await _vmService;
await vmService.setVMTimelineFlags(streams);
}

/// Runs [action] and returns a [vm.Timeline] trace for it.
Expand All @@ -243,16 +248,17 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
bool retainPriorEvents = false,
}) async {
await enableTimeline(streams: streams);
final vm.VmService vmService = await _vmService;
if (retainPriorEvents) {
await action();
return await _vmService.getVMTimeline();
return await vmService.getVMTimeline();
}

await _vmService.clearVMTimeline();
final vm.Timestamp startTime = await _vmService.getVMTimelineMicros();
await vmService.clearVMTimeline();
final vm.Timestamp startTime = await vmService.getVMTimelineMicros();
await action();
final vm.Timestamp endTime = await _vmService.getVMTimelineMicros();
return await _vmService.getVMTimeline(
final vm.Timestamp endTime = await vmService.getVMTimelineMicros();
return await vmService.getVMTimeline(
timeOriginMicros: startTime.timestamp,
timeExtentMicros: endTime.timestamp,
);
Expand Down Expand Up @@ -285,7 +291,7 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
retainPriorEvents: retainPriorEvents,
);
reportData ??= <String, dynamic>{};
reportData[reportKey] = timeline.toJson();
reportData![reportKey] = timeline.toJson();
}

/// Watches the [FrameTiming] during `action` and report it to the binding
Expand Down Expand Up @@ -324,6 +330,6 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
final FrameTimingSummarizer frameTimes =
FrameTimingSummarizer(frameTimings);
reportData ??= <String, dynamic>{};
reportData[reportKey] = frameTimes.summary;
reportData![reportKey] = frameTimes.summary;
}
}
8 changes: 4 additions & 4 deletions packages/integration_test/lib/integration_test_driver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ typedef ResponseDataCallback = FutureOr<void> Function(Map<String, dynamic>);
Future<void> writeResponseData(
Map<String, dynamic> data, {
String testOutputFilename = 'integration_response_data',
String destinationDirectory,
String? destinationDirectory,
}) async {
assert(testOutputFilename != null);
assert(testOutputFilename != null); // ignore: unnecessary_null_comparison
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line seems no longer necessary when we have null-safety.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above - these are still helpful when working in mixed/unsound mode.

destinationDirectory ??= testOutputsDirectory;
await fs.directory(destinationDirectory).create(recursive: true);
final File file = fs.file(path.join(
Expand Down Expand Up @@ -65,7 +65,7 @@ Future<void> writeResponseData(
/// ```
Future<void> integrationDriver({
Duration timeout = const Duration(minutes: 1),
ResponseDataCallback responseDataCallback = writeResponseData,
ResponseDataCallback? responseDataCallback = writeResponseData,
}) async {
final FlutterDriver driver = await FlutterDriver.connect();
final String jsonResult = await driver.requestData(null, timeout: timeout);
Expand All @@ -75,7 +75,7 @@ Future<void> integrationDriver({
if (response.allTestsPassed) {
print('All tests passed.');
if (responseDataCallback != null) {
await responseDataCallback(response.data);
await responseDataCallback(response.data!);
}
exit(0);
} else {
Expand Down
Loading