Unverified Commit ed977dd6 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Revert "[integration_test] Add a `run` method for proper reporting of test...

Revert "[integration_test] Add a `run` method for proper reporting of test results (#70075)" (#70466)

This reverts commit af5eb3b9.
parent af5eb3b9
...@@ -18,9 +18,9 @@ assertions. ...@@ -18,9 +18,9 @@ assertions.
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
void main() => run(_testMain); void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
void _testMain() {
testWidgets("failing test example", (WidgetTester tester) async { testWidgets("failing test example", (WidgetTester tester) async {
expect(2 + 2, equals(5)); expect(2 + 2, equals(5));
}); });
......
...@@ -12,10 +12,12 @@ ...@@ -12,10 +12,12 @@
import 'dart:html' as html; import 'dart:html' as html;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:integration_test_example/main.dart' as app; import 'package:integration_test_example/main.dart' as app;
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('verify text', (WidgetTester tester) async { testWidgets('verify text', (WidgetTester tester) async {
// Build our app and trigger a frame. // Build our app and trigger a frame.
app.main(); app.main();
......
...@@ -12,10 +12,13 @@ ...@@ -12,10 +12,13 @@
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:integration_test_example/main.dart' as app; import 'package:integration_test_example/main.dart' as app;
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('verify text', (WidgetTester tester) async { testWidgets('verify text', (WidgetTester tester) async {
// Build our app and trigger a frame. // Build our app and trigger a frame.
app.main(); app.main();
......
...@@ -14,4 +14,7 @@ import 'package:integration_test/integration_test.dart'; ...@@ -14,4 +14,7 @@ import 'package:integration_test/integration_test.dart';
import '_example_test_io.dart' if (dart.library.html) '_example_test_web.dart' import '_example_test_io.dart' if (dart.library.html) '_example_test_web.dart'
as tests; as tests;
void main() => run(tests.main); void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
tests.main();
}
...@@ -17,4 +17,7 @@ import 'package:integration_test/integration_test.dart'; ...@@ -17,4 +17,7 @@ import 'package:integration_test/integration_test.dart';
import '_extended_test_io.dart' if (dart.library.html) '_extended_test_web.dart' import '_extended_test_io.dart' if (dart.library.html) '_extended_test_web.dart'
as tests; as tests;
void main() => run(tests.main); void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
tests.main();
}
...@@ -106,48 +106,21 @@ class Response { ...@@ -106,48 +106,21 @@ class Response {
} }
} }
/// Represents the result of running a test. /// Representing a failure includes the method name and the failure details.
class TestResult { class Failure {
TestResult._(this.methodName); /// Constructor requiring all fields during initialization.
Failure(this.methodName, this.details);
/// The name of the test method which failed. /// The name of the test method which failed.
final String methodName; final String methodName;
}
/// Represents successful execution of a test.
class Success extends TestResult {
/// Constructor requiring all fields during initialization.
Success(String methodName) : super._(methodName);
}
/// Represents a test failure.
class Failure extends TestResult {
/// Constructor requiring all fields during initialization.
///
/// If [error] is passed, [errors] will be ignored.
Failure(String methodName, String details, {
Object error,
List<AsyncError> errors,
}) :
errors = error != null
? <AsyncError>[AsyncError(error, StackTrace.fromString(details))]
: errors ?? <AsyncError>[],
super._(methodName);
/// Errors that were thrown during the test.
final List<AsyncError> errors;
/// The first error that was thrown during the test.
Object get error => errors.isEmpty ? null : errors.first.error;
/// The details of the first failure such as stack trace. /// The details of the failure such as stack trace.
String get details => errors.isEmpty ? null : errors.first.stackTrace.toString(); final String details;
/// Serializes the object to JSON. /// Serializes the object to JSON.
String toJson() { String toJson() {
return json.encode(<String, String>{ return json.encode(<String, String>{
'methodName': methodName, 'methodName': methodName,
'error': error.toString(),
'details': details, 'details': details,
}); });
} }
......
...@@ -6,157 +6,70 @@ import 'dart:async'; ...@@ -6,157 +6,70 @@ import 'dart:async';
import 'dart:developer' as developer; import 'dart:developer' as developer;
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
// ignore: implementation_imports
import 'package:test_core/src/direct_run.dart';
// ignore: implementation_imports
import 'package:test_core/src/runner/engine.dart';
import 'package:vm_service/vm_service.dart' as vm; import 'package:vm_service/vm_service.dart' as vm;
import 'package:vm_service/vm_service_io.dart' as vm_io; import 'package:vm_service/vm_service_io.dart' as vm_io;
import '_callback_io.dart' if (dart.library.html) '_callback_web.dart' import '_callback_io.dart' if (dart.library.html) '_callback_web.dart' as driver_actions;
as driver_actions;
import '_extension_io.dart' if (dart.library.html) '_extension_web.dart'; import '_extension_io.dart' if (dart.library.html) '_extension_web.dart';
import 'common.dart'; import 'common.dart';
import 'src/constants.dart';
import 'src/reporter.dart';
/// Toggles the legacy reporting mechansim where results are only collected
/// for [testWidgets].
///
/// If [run] is called, this will be disabled.
bool _isUsingLegacyReporting = true;
/// Executes a block that contains tests.
///
/// Example Usage:
/// ```
/// import 'package:flutter_test/flutter_test.dart';
/// import 'package:integration_test/integration_test.dart';
///
/// void main() => run(_testMain);
///
/// void _testMain() {
/// test('A test', () {
/// expect(true, true);
/// });
/// }
/// ```
///
/// If not explicitly passed, the default [reporter] will send results over the
/// platform channel to native.
Future<void> run(
FutureOr<void> Function() testMain, {
Reporter reporter = const _ReporterImpl(),
}) async {
_isUsingLegacyReporting = false;
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
// Pipe detailed exceptions within [testWidgets] to `package:test`.
reportTestException = (FlutterErrorDetails details, String testDescription) {
registerException('Test $testDescription failed: $details');
};
final Completer<List<TestResult>> resultsCompleter = Completer<List<TestResult>>();
await directRunTests(
testMain,
reporterFactory: (Engine engine) => ResultReporter(engine, resultsCompleter),
);
final List<TestResult> results = await resultsCompleter.future;
binding._updateTestResultState(<String, TestResult>{
for (final TestResult result in results)
result.methodName: result,
});
await reporter.report(results);
}
/// Abstract interface for a result reporter.
abstract class Reporter {
/// Reports test results.
///
/// This method will be called at the end of [run] with the [results] of
/// running the test suite.
Future<void> report(List<TestResult> results);
}
/// Default implementation of the reporter that sends results over to the
/// platform side.
class _ReporterImpl implements Reporter {
const _ReporterImpl();
@override
Future<void> report(
List<TestResult> results,
) async {
try {
await IntegrationTestWidgetsFlutterBinding._channel.invokeMethod<void>(
'allTestsFinished',
<String, dynamic>{
'results': <String, String>{
for (final TestResult result in results)
result.methodName: result is Failure
? _formatFailureForPlatform(result)
: success
}
},
);
} on MissingPluginException {
print('Warning: integration_test test plugin was not detected.');
}
}
}
String _formatFailureForPlatform(Failure failure) => '${failure.error} ${failure.details}'; const String _success = 'success';
/// A subclass of [LiveTestWidgetsFlutterBinding] that reports tests results /// A subclass of [LiveTestWidgetsFlutterBinding] that reports tests results
/// on a channel to adapt them to native instrumentation test format. /// on a channel to adapt them to native instrumentation test format.
class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding implements IntegrationTestResults {
implements IntegrationTestResults { /// Sets up a listener to report that the tests are finished when everything is
/// If [run] is not used, sets up a listener to report that the tests are /// torn down.
/// finished when everything is torn down.
///
/// This functionality is deprecated – clients are expected to use [run] to
/// execute their tests instead.
IntegrationTestWidgetsFlutterBinding() { IntegrationTestWidgetsFlutterBinding() {
if (!_isUsingLegacyReporting) { // TODO(jackson): Report test results as they arrive
// TODO(jiahaog): Point users to use the CLI https://github.com/flutter/flutter/issues/66264.
print('Using the legacy test result reporter, which will not catch all '
'errors thrown in declared tests. Consider wrapping tests with '
'https://api.flutter.dev/flutter/integration_test/run.html instead.');
return;
}
tearDownAll(() async { tearDownAll(() async {
_updateTestResultState(results); try {
await const _ReporterImpl().report(results.values.toList()); // For web integration tests we are not using the
// `plugins.flutter.io/integration_test`. Mark the tests as complete
// before invoking the channel.
if (kIsWeb) {
if (!_allTestsPassed.isCompleted) {
_allTestsPassed.complete(true);
}
}
callbackManager.cleanup();
await _channel.invokeMethod<void>(
'allTestsFinished',
<String, dynamic>{
'results': results.map((String name, Object result) {
if (result is Failure) {
return MapEntry<String, dynamic>(name, result.details);
}
return MapEntry<String, Object>(name, result);
})
},
);
} on MissingPluginException {
print('Warning: integration_test test plugin was not detected.');
}
if (!_allTestsPassed.isCompleted) {
_allTestsPassed.complete(true);
}
}); });
// TODO(jackson): Report the results individually instead of all at once
// See https://github.com/flutter/flutter/issues/38985
final TestExceptionReporter oldTestExceptionReporter = reportTestException; final TestExceptionReporter oldTestExceptionReporter = reportTestException;
reportTestException = (FlutterErrorDetails details, String testDescription) { reportTestException =
results[testDescription] = Failure( (FlutterErrorDetails details, String testDescription) {
testDescription, results[testDescription] = Failure(testDescription, details.toString());
details.toString(), if (!_allTestsPassed.isCompleted) {
error: details.exception, _allTestsPassed.complete(false);
); }
oldTestExceptionReporter(details, testDescription); oldTestExceptionReporter(details, testDescription);
}; };
} }
void _updateTestResultState(Map<String, TestResult> results) {
this.results = results;
print('Test execution completed: $results');
_allTestsPassed.complete(!results.values.any((TestResult result) => result is Failure));
callbackManager.cleanup();
}
@override @override
bool get overrideHttpClient => false; bool get overrideHttpClient => false;
...@@ -218,8 +131,11 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding ...@@ -218,8 +131,11 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
MethodChannel('plugins.flutter.io/integration_test'); MethodChannel('plugins.flutter.io/integration_test');
/// Test results that will be populated after the tests have completed. /// Test results that will be populated after the tests have completed.
///
/// Keys are the test descriptions, and values are either [_success] or
/// a [Failure].
@visibleForTesting @visibleForTesting
Map<String, TestResult> results = <String, TestResult>{}; Map<String, Object> results = <String, Object>{};
List<Failure> get _failures => results.values.whereType<Failure>().toList(); List<Failure> get _failures => results.values.whereType<Failure>().toList();
...@@ -275,7 +191,7 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding ...@@ -275,7 +191,7 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
description: description, description: description,
timeout: timeout, timeout: timeout,
); );
results[description] ??= Success(description); results[description] ??= _success;
} }
vm.VmService _vmService; vm.VmService _vmService;
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// Represents a successful test.
const String success = 'success';
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
// ignore: implementation_imports
import 'package:test_api/src/backend/live_test.dart';
// ignore: implementation_imports
import 'package:test_core/src/runner/engine.dart';
// ignore: implementation_imports
import 'package:test_core/src/runner/reporter.dart';
import '../common.dart';
import 'constants.dart';
/// A reporter that plugs into [directRunTests] from `package:test_core`.
class ResultReporter implements Reporter {
/// When the [_engine] has completed execution of tests, [_resultsCompleter]
/// will be completed with the test results.
ResultReporter(this._engine, this._resultsCompleter) {
_subscriptions.add(_engine.success.asStream().listen(_onDone));
}
final Engine _engine;
final Completer<List<TestResult>> _resultsCompleter;
final Set<StreamSubscription<Object>> _subscriptions = <StreamSubscription<Object>>{};
void _onDone(bool _) {
_cancel();
final List<TestResult> results = <TestResult>[
for (final LiveTest liveTest in _engine.liveTests)
liveTest.state.result.name == success
? Success(liveTest.test.name)
: Failure(
liveTest.test.name,
null,
errors: liveTest.errors,
)
];
_resultsCompleter.complete(results);
}
void _cancel() {
for (final StreamSubscription<Object> subscription in _subscriptions) {
subscription.cancel();
}
_subscriptions.clear();
}
@override
void pause() {}
@override
void resume() {}
}
...@@ -15,40 +15,22 @@ dependencies: ...@@ -15,40 +15,22 @@ dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
path: 1.8.0-nullsafety.3 path: 1.8.0-nullsafety.3
test_core: 0.3.12-nullsafety.9
vm_service: 5.2.0 vm_service: 5.2.0
_fe_analyzer_shared: 7.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
analyzer: 0.39.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 2.0.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 1.6.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" async: 2.5.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 2.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
characters: 1.1.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.1.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.2.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" charcode: 1.2.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
clock: 1.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" 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" collection: 1.15.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.14.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.2 # 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" fake_async: 1.2.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 6.0.0-nullsafety.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.0.0-nullsafety.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
html: 0.14.0+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
io: 0.3.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
js: 0.6.3-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
logging: 0.11.4 # 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" matcher: 0.12.10-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.3.0-nullsafety.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.3.0-nullsafety.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_interop: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_io: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
package_config: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pool: 1.5.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pub_semver: 1.4.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_map_stack_trace: 2.1.0-nullsafety.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_maps: 0.10.10-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.8.0-nullsafety.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.8.0-nullsafety.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.10.0-nullsafety.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0-nullsafety.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
...@@ -58,9 +40,7 @@ dependencies: ...@@ -58,9 +40,7 @@ dependencies:
test_api: 0.2.19-nullsafety.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.2.19-nullsafety.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.3.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vector_math: 2.1.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 2.1.2 # 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"
dev_dependencies: dev_dependencies:
pedantic: 1.10.0-nullsafety.3 pedantic: 1.10.0-nullsafety.3
...@@ -75,4 +55,4 @@ flutter: ...@@ -75,4 +55,4 @@ flutter:
ios: ios:
pluginClass: IntegrationTestPlugin pluginClass: IntegrationTestPlugin
# PUBSPEC CHECKSUM: a5dd # PUBSPEC CHECKSUM: f9bc
...@@ -7,37 +7,42 @@ import 'dart:convert'; ...@@ -7,37 +7,42 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/src/constants.dart'; import 'package:path/path.dart' as path;
import 'utils.dart'; final String bat = Platform.isWindows ? '.bat' : '';
final String _flutterBin = path.join(Directory.current.parent.parent.parent.path, 'bin', 'flutter$bat');
// Assumes that the flutter command is in `$PATH`. const String _integrationResultsPrefix =
const String _flutterBin = 'flutter'; 'IntegrationTestWidgetsFlutterBinding test results:';
const String _integrationResultsPrefix = 'IntegrationTestWidgetsFlutterBinding test results:'; const String _failureExcerpt = r'Expected: <false>\n Actual: <true>';
Future<void> main() async { Future<void> main() async {
test('When multiple tests pass', () async { group('Integration binding result', () {
final Map<String, dynamic> results = await _runTest('test/reporter/data/pass_test_script.dart'); test('when multiple tests pass', () async {
final Map<String, dynamic> results = await _runTest(path.join('test', 'data', 'pass_test_script.dart'));
expect(results, hasLength(2)); expect(
expect(results, containsPair('Passing test 1', _isSuccess)); results,
expect(results, containsPair('Passing test 2', _isSuccess)); equals(<String, dynamic>{
}); 'passing test 1': 'success',
'passing test 2': 'success',
}));
});
test('When multiple tests fail', () async { test('when multiple tests fail', () async {
final Map<String, dynamic> results = await _runTest('test/reporter/data/fail_test_script.dart'); final Map<String, dynamic> results = await _runTest(path.join('test', 'data', 'fail_test_script.dart'));
expect(results, hasLength(2)); expect(results, hasLength(2));
expect(results, containsPair('Failing test 1', _isSerializedFailure)); expect(results, containsPair('failing test 1', contains(_failureExcerpt)));
expect(results, containsPair('Failing test 2', _isSerializedFailure)); expect(results, containsPair('failing test 2', contains(_failureExcerpt)));
}); });
test('When one test passes, then another fails', () async { test('when one test passes, then another fails', () async {
final Map<String, dynamic> results = await _runTest('test/reporter/data/pass_then_fail_test_script.dart'); final Map<String, dynamic> results = await _runTest(path.join('test', 'data', 'pass_then_fail_test_script.dart'));
expect(results, hasLength(2)); expect(results, hasLength(2));
expect(results, containsPair('Passing test', _isSuccess)); expect(results, containsPair('passing test', equals('success')));
expect(results, containsPair('Failing test', _isSerializedFailure)); expect(results, containsPair('failing test', contains(_failureExcerpt)));
});
}); });
} }
...@@ -45,7 +50,8 @@ Future<void> main() async { ...@@ -45,7 +50,8 @@ Future<void> main() async {
/// ///
/// [scriptPath] is relative to the package root. /// [scriptPath] is relative to the package root.
Future<Map<String, dynamic>> _runTest(String scriptPath) async { Future<Map<String, dynamic>> _runTest(String scriptPath) async {
final Process process = await Process.start(_flutterBin, <String>['test', '--machine', scriptPath]); final Process process =
await Process.start(_flutterBin, <String>['test', '--machine', scriptPath]);
/// In the test [tearDownAll] block, the test results are encoded into JSON and /// In the test [tearDownAll] block, the test results are encoded into JSON and
/// are printed with the [_integrationResultsPrefix] prefix. /// are printed with the [_integrationResultsPrefix] prefix.
...@@ -55,23 +61,19 @@ Future<Map<String, dynamic>> _runTest(String scriptPath) async { ...@@ -55,23 +61,19 @@ Future<Map<String, dynamic>> _runTest(String scriptPath) async {
final String testResults = (await process.stdout final String testResults = (await process.stdout
.transform(utf8.decoder) .transform(utf8.decoder)
.expand((String text) => text.split('\n')) .expand((String text) => text.split('\n'))
.map<dynamic>((String line) { .map((String line) {
try { try {
return jsonDecode(line); return jsonDecode(line) as Map<String, dynamic>;
} on FormatException { } on FormatException {
// Only interested in test events which are JSON. // Only interested in test events which are JSON.
} }
}) })
.where((dynamic testEvent) => .where((Map<String, dynamic> testEvent) =>
testEvent != null && testEvent['type'] == 'print') testEvent != null && testEvent['type'] == 'print')
.map((dynamic printEvent) => printEvent['message'] as String) .map((Map<String, dynamic> printEvent) => printEvent['message'] as String)
.firstWhere((String message) => .firstWhere((String message) =>
message.startsWith(_integrationResultsPrefix))) message.startsWith(_integrationResultsPrefix)))
.replaceAll(_integrationResultsPrefix, ''); .replaceAll(_integrationResultsPrefix, '');
return jsonDecode(testResults) as Map<String, dynamic>; return jsonDecode(testResults) as Map<String, dynamic>;
} }
bool _isSuccess(Object object) => object == success;
bool _isSerializedFailure(dynamic object) => object.toString().contains(failureExcerpt);
...@@ -2,24 +2,23 @@ ...@@ -2,24 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:convert';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../utils.dart'; Future<void> main() async {
void main() {
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding; final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
testWidgets('Failing test 1', (WidgetTester tester) async { testWidgets('failing test 1', (WidgetTester tester) async {
expect(false, true); expect(true, false);
}); });
testWidgets('Failing test 2', (WidgetTester tester) async { testWidgets('failing test 2', (WidgetTester tester) async {
expect(false, true); expect(true, false);
}); });
tearDownAll(() { tearDownAll(() {
print( print('IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}');
'IntegrationTestWidgetsFlutterBinding test results: ${testResultsToJson(binding.results)}');
}); });
} }
...@@ -2,24 +2,24 @@ ...@@ -2,24 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:convert';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../utils.dart'; Future<void> main() async {
void main() {
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding; final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
testWidgets('Passing test 1', (WidgetTester tester) async { testWidgets('passing test 1', (WidgetTester tester) async {
expect(true, true); expect(true, true);
}); });
testWidgets('Passing test 2', (WidgetTester tester) async { testWidgets('passing test 2', (WidgetTester tester) async {
expect(true, true); expect(true, true);
}); });
tearDownAll(() { tearDownAll(() {
print( print(
'IntegrationTestWidgetsFlutterBinding test results: ${testResultsToJson(binding.results)}'); 'IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}');
}); });
} }
...@@ -2,24 +2,24 @@ ...@@ -2,24 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:convert';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../utils.dart'; Future<void> main() async {
void main() {
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding; final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
testWidgets('Passing test', (WidgetTester tester) async { testWidgets('passing test', (WidgetTester tester) async {
expect(true, true); expect(true, true);
}); });
testWidgets('Failing test', (WidgetTester tester) async { testWidgets('failing test', (WidgetTester tester) async {
expect(false, true); expect(true, false);
}); });
tearDownAll(() { tearDownAll(() {
print( print(
'IntegrationTestWidgetsFlutterBinding test results: ${testResultsToJson(binding.results)}'); 'IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}');
}); });
} }
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/common.dart';
import 'utils.dart';
void main() {
test('When multiple tests fail', () async {
final List<TestResult> results = await runAndCollectResults(_testMain);
expect(results, <dynamic>[
isFailure('Failing testWidgets()'),
isFailure('Failing test()')
]);
});
}
void _testMain() {
testWidgets('Failing testWidgets()', (WidgetTester tester) async {
expect(false, true);
});
test('Failing test()', () {
expect(false, true);
});
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/common.dart';
import 'utils.dart';
void main() {
test('When multiple tests pass', () async {
final List<TestResult> results = await runAndCollectResults(_testMain);
expect(results, <dynamic>[
isSuccess('Passing testWidgets()'),
isSuccess('Passing test()')
]);
});
}
void _testMain() {
testWidgets('Passing testWidgets()', (WidgetTester tester) async {
expect(true, true);
});
test('Passing test()', () {
expect(true, true);
});
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/common.dart';
import 'utils.dart';
void main() {
test('when one test passes, then another fails', () async {
final List<TestResult> results = await runAndCollectResults(_testMain);
expect(results, <dynamic>[
isSuccess('Passing test'),
isFailure('Failing test')
]);
});
}
void _testMain() {
testWidgets('Passing test', (WidgetTester tester) async {
expect(true, true);
});
testWidgets('Failing test', (WidgetTester tester) async {
expect(false, true);
});
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/common.dart';
import 'package:integration_test/integration_test.dart';
import 'package:integration_test/src/constants.dart';
const String failureExcerpt = 'Expected: <true>';
dynamic isSuccess(String methodName) => isA<Success>()
.having((Success s) => s.methodName, 'methodName', methodName);
dynamic isFailure(String methodName) => isA<Failure>()
.having((Failure e) => e.methodName, 'methodName', methodName)
.having((Failure e) => e.error.toString(), 'error', contains(failureExcerpt));
Future<List<TestResult>> runAndCollectResults(
FutureOr<void> Function() testMain,
) async {
final _TestReporter reporter = _TestReporter();
await run(testMain, reporter: reporter);
return reporter.results;
}
class _TestReporter implements Reporter {
final Completer<List<TestResult>> _resultsCompleter = Completer<List<TestResult>>();
Future<List<TestResult>> get results => _resultsCompleter.future;
@override
Future<void> report(List<TestResult> results) async => _resultsCompleter.complete(results);
}
String testResultsToJson(Map<String, TestResult> results) {
return jsonEncode(<String, Object>{
for (TestResult result in results.values)
result.methodName: result is Failure ? result : success
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment