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