mirror of
https://github.com/flutter/packages.git
synced 2026-03-13 10:40:37 +08:00
Makes the analysis options changes described in
https://github.com/flutter/flutter/issues/178827:
- Adding
[omit_obvious_local_variable_types](https://dart.dev/tools/linter-rules/omit_obvious_local_variable_types)
- Adding
[specify_nonobvious_local_variable_types](https://dart.dev/tools/linter-rules/specify_nonobvious_local_variable_types)
- Adding
[specify_nonobvious_property_types](https://dart.dev/tools/linter-rules/specify_nonobvious_property_types)
- Adding
[type_annotate_public_apis](https://dart.dev/tools/linter-rules/type_annotate_public_apis)
- Removing
[always_specify_types](https://dart.dev/tools/linter-rules/always_specify_types)
After those changes, makes the following repo-wide changes:
- `dart fix --apply` in all packages and in script/tool/
- `dart format` in all packages and in script/tool/
- `update-excerpts` repo tooling command to update excerpts based on the
changes to their sources
Also updates the min Flutter/Dart SDK version to 3.35/3.9 for the
following packages, to avoid `analyze` failures in the `N-2` legacy
analysis run due to what appears to be a 3.9 change in what the Dart
analyzer continues to be an obvious local type in loop iterations:
- go_router
- google_fonts
- google_identity_services_web
- google_maps_flutter_web
- local_auth_platform_interface
- metrics_center
- multicast_dns
- pigeon
- rfw
- shared_preferences
- two_dimensional_scrollables
- vector_graphics_compiler
- mustache_template
- path_parsing
Because this is causing a significant amount of format churn already, I
took this opportunity to update the repository tooling to a min Dart SDK
of 3.8 (the N-2 stable version, so the earliest version we need the
tooling to support) to pick up the new format style, so the amount of
automated formatter change is higher in script/tool/ than in the
packages.
This does contain two manual changes (other than the repo tooling min
version):
-
d700b45c7d
changes `dynamic` to `Object?` in a few places where `dynamic` caused
analyzer warnings under the new rule set.
- Updates the repo tooling to ignore `.dart_tool/` when looking for
unexpected local `analysis_options.yaml` files, to fix issues running
the repo tool's `analyze` command locally based on recent changes in
`dart` behavior.
This does not include any CHANGELOG or version updates; even though we
normally version any changes to production code, mass automated changes
like this aren't worth the churn of releasing. This includes changes to
lib/example/main.dart and to README.md excerpts; while the style changes
will be user-visible on pub.dev, it's fine for those changes to wait for
the next release of each package.
Part of https://github.com/flutter/flutter/issues/178827
1850 lines
55 KiB
Dart
1850 lines
55 KiB
Dart
// Copyright 2013 The Flutter Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io' as io;
|
|
|
|
import 'package:args/command_runner.dart';
|
|
import 'package:fake_async/fake_async.dart';
|
|
import 'package:file/file.dart';
|
|
import 'package:flutter_plugin_tools/src/common/core.dart';
|
|
import 'package:flutter_plugin_tools/src/common/plugin_utils.dart';
|
|
import 'package:flutter_plugin_tools/src/drive_examples_command.dart';
|
|
import 'package:git/git.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:platform/platform.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import 'mocks.dart';
|
|
import 'util.dart';
|
|
|
|
const String _fakeIOSDevice = '67d5c3d1-8bdf-46ad-8f6b-b00e2a972dda';
|
|
const String _fakeAndroidDevice = 'emulator-1234';
|
|
|
|
void main() {
|
|
group('test drive_example_command', () {
|
|
late Platform mockPlatform;
|
|
late Directory packagesDir;
|
|
late CommandRunner<void> runner;
|
|
late RecordingProcessRunner processRunner;
|
|
late RecordingProcessRunner gitProcessRunner;
|
|
|
|
setUp(() {
|
|
mockPlatform = MockPlatform();
|
|
final GitDir gitDir;
|
|
(:packagesDir, :processRunner, :gitProcessRunner, :gitDir) =
|
|
configureBaseCommandMocks(platform: mockPlatform);
|
|
final command = DriveExamplesCommand(
|
|
packagesDir,
|
|
processRunner: processRunner,
|
|
platform: mockPlatform,
|
|
gitDir: gitDir,
|
|
);
|
|
|
|
runner = CommandRunner<void>(
|
|
'drive_examples_command',
|
|
'Test for drive_example_command',
|
|
);
|
|
runner.addCommand(command);
|
|
|
|
// TODO(dit): Clean this up, https://github.com/flutter/flutter/issues/151869
|
|
mockPlatform.environment['CHANNEL'] = 'master';
|
|
mockPlatform.environment['FLUTTER_LOGS_DIR'] = '/path/to/logs';
|
|
});
|
|
|
|
void setMockFlutterDevicesOutput({
|
|
bool hasIOSDevice = true,
|
|
bool hasAndroidDevice = true,
|
|
bool includeBanner = false,
|
|
}) {
|
|
const updateBanner = '''
|
|
╔════════════════════════════════════════════════════════════════════════════╗
|
|
║ A new version of Flutter is available! ║
|
|
║ ║
|
|
║ To update to the latest version, run "flutter upgrade". ║
|
|
╚════════════════════════════════════════════════════════════════════════════╝
|
|
''';
|
|
final devices = <String>[
|
|
if (hasIOSDevice) '{"id": "$_fakeIOSDevice", "targetPlatform": "ios"}',
|
|
if (hasAndroidDevice)
|
|
'{"id": "$_fakeAndroidDevice", "targetPlatform": "android-x64"}',
|
|
];
|
|
final output =
|
|
'''${includeBanner ? updateBanner : ''}[${devices.join(',')}]''';
|
|
|
|
final mockDevicesProcess = MockProcess(
|
|
stdout: output,
|
|
stdoutEncoding: utf8,
|
|
);
|
|
processRunner.mockProcessesForExecutable[getFlutterCommand(
|
|
mockPlatform,
|
|
)] = <FakeProcessInfo>[
|
|
FakeProcessInfo(mockDevicesProcess, <String>['devices']),
|
|
];
|
|
}
|
|
|
|
test('fails if no platforms are provided', () async {
|
|
setMockFlutterDevicesOutput();
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(output, containsAllInOrder(<Matcher>[contains('Exactly one of')]));
|
|
});
|
|
|
|
test('fails if wasm flag is present but not web platform', () async {
|
|
setMockFlutterDevicesOutput();
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--android', '--wasm'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('--wasm is only supported on the web platform'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('fails if multiple platforms are provided', () async {
|
|
setMockFlutterDevicesOutput();
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--ios', '--macos'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(output, containsAllInOrder(<Matcher>[contains('Exactly one of')]));
|
|
});
|
|
|
|
test('fails for iOS if no iOS devices are present', () async {
|
|
setMockFlutterDevicesOutput(hasIOSDevice: false);
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--ios'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(output, containsAllInOrder(<Matcher>[contains('No iOS devices')]));
|
|
});
|
|
|
|
test('handles flutter tool banners when checking devices', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/test_driver/integration_test.dart',
|
|
'example/integration_test/foo_test.dart',
|
|
'example/ios/ios.m',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformIOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
setMockFlutterDevicesOutput(includeBanner: true);
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--ios',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('fails for iOS if getting devices fails', () async {
|
|
// Simulate failure from `flutter devices`.
|
|
processRunner.mockProcessesForExecutable[getFlutterCommand(
|
|
mockPlatform,
|
|
)] = <FakeProcessInfo>[
|
|
FakeProcessInfo(MockProcess(exitCode: 1), <String>['devices']),
|
|
];
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--ios'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(output, containsAllInOrder(<Matcher>[contains('No iOS devices')]));
|
|
});
|
|
|
|
test('fails for Android if no Android devices are present', () async {
|
|
setMockFlutterDevicesOutput(hasAndroidDevice: false);
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--android'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[contains('No Android devices')]),
|
|
);
|
|
});
|
|
|
|
test(
|
|
'a plugin without any integration test files is reported as an error',
|
|
() async {
|
|
setMockFlutterDevicesOutput();
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/lib/main.dart',
|
|
'example/android/android.java',
|
|
'example/ios/ios.m',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
|
platformIOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--android'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No driver tests were run (1 example(s) found).'),
|
|
contains('No tests ran'),
|
|
]),
|
|
);
|
|
},
|
|
);
|
|
|
|
test('integration tests using test(...) fail validation', () async {
|
|
setMockFlutterDevicesOutput();
|
|
final RepositoryPackage package = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/test_driver/integration_test.dart',
|
|
'example/integration_test/foo_test.dart',
|
|
'example/android/android.java',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
|
platformIOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
package.directory
|
|
.childDirectory('example')
|
|
.childDirectory('integration_test')
|
|
.childFile('foo_test.dart')
|
|
.writeAsStringSync('''
|
|
test('this is the wrong kind of test!'), () {
|
|
...
|
|
}
|
|
''');
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--android'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('foo_test.dart failed validation'),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('tests an iOS plugin', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/bar_test.dart',
|
|
'example/integration_test/foo_test.dart',
|
|
'example/integration_test/ignore_me.dart',
|
|
'example/android/android.java',
|
|
'example/ios/ios.m',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
|
platformIOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
setMockFlutterDevicesOutput();
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--ios',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'devices',
|
|
'--machine',
|
|
], null),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
_fakeIOSDevice,
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('handles missing CI debug logs directory', () async {
|
|
mockPlatform.environment.remove('FLUTTER_LOGS_DIR');
|
|
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/bar_test.dart',
|
|
'example/integration_test/foo_test.dart',
|
|
'example/integration_test/ignore_me.dart',
|
|
'example/android/android.java',
|
|
'example/ios/ios.m',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
|
platformIOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
setMockFlutterDevicesOutput();
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--ios',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'devices',
|
|
'--machine',
|
|
], null),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
_fakeIOSDevice,
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('saves a screenshot if test is taking too long', () async {
|
|
setMockFlutterDevicesOutput();
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/bar_test.dart',
|
|
'example/ios/ios.m',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
|
platformIOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final fakeAsync = FakeAsync();
|
|
processRunner.mockProcessesForExecutable['flutter']!.addAll(
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(
|
|
_FakeDelayingProcess(
|
|
delayDuration: const Duration(minutes: 11),
|
|
fakeAsync: fakeAsync,
|
|
),
|
|
<String>['test'],
|
|
),
|
|
FakeProcessInfo(MockProcess(), <String>['screenshot']),
|
|
],
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
var output = <String>[];
|
|
fakeAsync.run((_) {
|
|
() async {
|
|
output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--ios',
|
|
]);
|
|
}();
|
|
});
|
|
fakeAsync.flushTimers();
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains(
|
|
'Test is taking a long time, taking screenshot test-timeout-screenshot_integration_test.png...',
|
|
),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'devices',
|
|
'--machine',
|
|
], null),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
_fakeIOSDevice,
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'screenshot',
|
|
'-d',
|
|
_fakeIOSDevice,
|
|
'--out=/path/to/logs/test-timeout-screenshot_integration_test.png',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('driving when plugin does not support Linux is a no-op', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>['example/integration_test/plugin_test.dart'],
|
|
);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--linux',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('Skipping unsupported platform linux...'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
// Output should be empty since running drive-examples --linux on a non-Linux
|
|
// plugin is a no-op.
|
|
expect(processRunner.recordedCalls, <ProcessCall>[]);
|
|
});
|
|
|
|
test('tests a Linux plugin', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/linux/linux.cc',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformLinux: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--linux',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
'linux',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('driving when plugin does not suppport macOS is a no-op', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>['example/integration_test/plugin_test.dart'],
|
|
);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--macos',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('Skipping unsupported platform macos...'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
// Output should be empty since running drive-examples --macos with no macos
|
|
// implementation is a no-op.
|
|
expect(processRunner.recordedCalls, <ProcessCall>[]);
|
|
});
|
|
|
|
test('tests a macOS plugin', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/macos/macos.swift',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformMacOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--macos',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
'macos',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
// This tests the workaround for https://github.com/flutter/flutter/issues/135673
|
|
// and the behavior it tests should be removed once that is fixed.
|
|
group('runs tests separately on desktop', () {
|
|
test('macOS', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/first_test.dart',
|
|
'example/integration_test/second_test.dart',
|
|
'example/macos/macos.swift',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformMacOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--macos',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
'macos',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test/first_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
'macos',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test/second_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
// This tests the workaround for https://github.com/flutter/flutter/issues/135673
|
|
// and the behavior it tests should be removed once that is fixed.
|
|
test('Linux', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/first_test.dart',
|
|
'example/integration_test/second_test.dart',
|
|
'example/linux/foo.cc',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformLinux: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--linux',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
'linux',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test/first_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
'linux',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test/second_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
// This tests the workaround for https://github.com/flutter/flutter/issues/135673
|
|
// and the behavior it tests should be removed once that is fixed.
|
|
test('Windows', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/first_test.dart',
|
|
'example/integration_test/second_test.dart',
|
|
'example/windows/foo.cpp',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWindows: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--windows',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
'windows',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test/first_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
'windows',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test/second_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
});
|
|
|
|
test('driving when plugin does not suppport web is a no-op', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>['example/integration_test/plugin_test.dart'],
|
|
);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
// Output should be empty since running drive-examples --web on a non-web
|
|
// plugin is a no-op.
|
|
expect(processRunner.recordedCalls, <ProcessCall>[]);
|
|
});
|
|
|
|
test('drives a web plugin', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/test_driver/integration_test.dart',
|
|
'example/web/index.html',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'drive',
|
|
'-d',
|
|
'web-server',
|
|
'--web-port=7357',
|
|
'--browser-name=chrome',
|
|
'--screenshot=/path/to/logs/plugin_example-drive',
|
|
'--driver',
|
|
'test_driver/integration_test.dart',
|
|
'--target',
|
|
'integration_test/plugin_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('drives a web plugin compiled to WASM', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/test_driver/integration_test.dart',
|
|
'example/web/index.html',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
'--wasm',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'drive',
|
|
'-d',
|
|
'web-server',
|
|
'--web-port=7357',
|
|
'--browser-name=chrome',
|
|
'--wasm',
|
|
'--screenshot=/path/to/logs/plugin_example-drive',
|
|
'--driver',
|
|
'test_driver/integration_test.dart',
|
|
'--target',
|
|
'integration_test/plugin_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('runs chromedriver when requested', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/test_driver/integration_test.dart',
|
|
'example/web/index.html',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
'--run-chromedriver',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
const ProcessCall('chromedriver', <String>['--port=4444'], null),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'drive',
|
|
'-d',
|
|
'web-server',
|
|
'--web-port=7357',
|
|
'--browser-name=chrome',
|
|
'--screenshot=/path/to/logs/plugin_example-drive',
|
|
'--driver',
|
|
'test_driver/integration_test.dart',
|
|
'--target',
|
|
'integration_test/plugin_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('drives a web plugin with CHROME_EXECUTABLE', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/test_driver/integration_test.dart',
|
|
'example/web/index.html',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
mockPlatform.environment['CHROME_EXECUTABLE'] = '/path/to/chrome';
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'drive',
|
|
'-d',
|
|
'web-server',
|
|
'--web-port=7357',
|
|
'--browser-name=chrome',
|
|
'--chrome-binary=/path/to/chrome',
|
|
'--screenshot=/path/to/logs/plugin_example-drive',
|
|
'--driver',
|
|
'test_driver/integration_test.dart',
|
|
'--target',
|
|
'integration_test/plugin_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('driving when plugin does not suppport Windows is a no-op', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>['example/integration_test/plugin_test.dart'],
|
|
);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--windows',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('Skipping unsupported platform windows...'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
// Output should be empty since running drive-examples --windows on a
|
|
// non-Windows plugin is a no-op.
|
|
expect(processRunner.recordedCalls, <ProcessCall>[]);
|
|
});
|
|
|
|
test('tests a Windows plugin', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/windows/windows.cpp',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWindows: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--windows',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
'windows',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('tests an Android plugin', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/android/android.java',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
setMockFlutterDevicesOutput();
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--android',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'devices',
|
|
'--machine',
|
|
], null),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
_fakeAndroidDevice,
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('tests an Android plugin with "apk" alias', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/android/android.java',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
setMockFlutterDevicesOutput();
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--apk',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'devices',
|
|
'--machine',
|
|
], null),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
_fakeAndroidDevice,
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('driving when plugin does not support Android is no-op', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>['example/integration_test/plugin_test.dart'],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformMacOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
setMockFlutterDevicesOutput();
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--android',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('Skipping unsupported platform android...'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
// Output should be empty other than the device query.
|
|
expect(processRunner.recordedCalls, <ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'devices',
|
|
'--machine',
|
|
], null),
|
|
]);
|
|
});
|
|
|
|
test('driving when plugin does not support iOS is no-op', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>['example/integration_test/plugin_test.dart'],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformMacOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
setMockFlutterDevicesOutput();
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--ios',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('Skipping unsupported platform ios...'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
// Output should be empty other than the device query.
|
|
expect(processRunner.recordedCalls, <ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'devices',
|
|
'--machine',
|
|
], null),
|
|
]);
|
|
});
|
|
|
|
test('platform interface plugins are silently skipped', () async {
|
|
createFakePlugin(
|
|
'aplugin_platform_interface',
|
|
packagesDir,
|
|
examples: <String>[],
|
|
);
|
|
|
|
setMockFlutterDevicesOutput();
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--macos',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for aplugin_platform_interface'),
|
|
contains(
|
|
'SKIPPING: Platform interfaces are not expected to have integration tests.',
|
|
),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
// Output should be empty since it's skipped.
|
|
expect(processRunner.recordedCalls, <ProcessCall>[]);
|
|
});
|
|
|
|
test('enable-experiment flag', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/plugin_test.dart',
|
|
'example/android/android.java',
|
|
'example/ios/ios.m',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformAndroid: const PlatformDetails(PlatformSupport.inline),
|
|
platformIOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
|
|
setMockFlutterDevicesOutput();
|
|
await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--ios',
|
|
'--enable-experiment=exp1',
|
|
]);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'devices',
|
|
'--machine',
|
|
], null),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
_fakeIOSDevice,
|
|
'--enable-experiment=exp1',
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('fails when no example is present', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
examples: <String>[],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--web'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No driver tests were run (0 example(s) found).'),
|
|
contains('The following packages had errors:'),
|
|
contains(
|
|
' plugin:\n'
|
|
' No tests ran (use --exclude if this is intentional)',
|
|
),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('web fails when no driver is present', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/bar_test.dart',
|
|
'example/integration_test/foo_test.dart',
|
|
'example/web/index.html',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--web'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No driver found for plugin/example'),
|
|
contains('No driver tests were run (1 example(s) found).'),
|
|
contains('The following packages had errors:'),
|
|
contains(
|
|
' plugin:\n'
|
|
' No tests ran (use --exclude if this is intentional)',
|
|
),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('web fails when no integration tests are present', () async {
|
|
createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/test_driver/integration_test.dart',
|
|
'example/web/index.html',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--web'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('No driver tests were run (1 example(s) found).'),
|
|
contains('The following packages had errors:'),
|
|
contains(
|
|
' plugin:\n'
|
|
' No tests ran (use --exclude if this is intentional)',
|
|
),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('"flutter drive" reports test failures', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/test_driver/integration_test.dart',
|
|
'example/integration_test/bar_test.dart',
|
|
'example/integration_test/foo_test.dart',
|
|
'example/web/index.html',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformWeb: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
// Simulate failure from `flutter drive`.
|
|
processRunner.mockProcessesForExecutable[getFlutterCommand(
|
|
mockPlatform,
|
|
)] = <FakeProcessInfo>[
|
|
// Fail both bar_test.dart and foo_test.dart.
|
|
FakeProcessInfo(MockProcess(exitCode: 1), <String>['drive']),
|
|
FakeProcessInfo(MockProcess(exitCode: 1), <String>['drive']),
|
|
];
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--web'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('The following packages had errors:'),
|
|
contains(
|
|
' plugin:\n'
|
|
' example/integration_test/bar_test.dart\n'
|
|
' example/integration_test/foo_test.dart',
|
|
),
|
|
]),
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'drive',
|
|
'-d',
|
|
'web-server',
|
|
'--web-port=7357',
|
|
'--browser-name=chrome',
|
|
'--screenshot=/path/to/logs/plugin_example-drive',
|
|
'--driver',
|
|
'test_driver/integration_test.dart',
|
|
'--target',
|
|
'integration_test/bar_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'drive',
|
|
'-d',
|
|
'web-server',
|
|
'--web-port=7357',
|
|
'--browser-name=chrome',
|
|
'--screenshot=/path/to/logs/plugin_example-drive',
|
|
'--driver',
|
|
'test_driver/integration_test.dart',
|
|
'--target',
|
|
'integration_test/foo_test.dart',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('"flutter test" reports test failures', () async {
|
|
final RepositoryPackage plugin = createFakePlugin(
|
|
'plugin',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/bar_test.dart',
|
|
'example/integration_test/foo_test.dart',
|
|
'example/ios/ios.swift',
|
|
],
|
|
platformSupport: <String, PlatformDetails>{
|
|
platformIOS: const PlatformDetails(PlatformSupport.inline),
|
|
},
|
|
);
|
|
|
|
setMockFlutterDevicesOutput();
|
|
// Simulate failure from `flutter test`.
|
|
processRunner.mockProcessesForExecutable[getFlutterCommand(mockPlatform)]!
|
|
.add(FakeProcessInfo(MockProcess(exitCode: 1), <String>['test']));
|
|
|
|
Error? commandError;
|
|
final List<String> output = await runCapturingPrint(
|
|
runner,
|
|
<String>['drive-examples', '--ios'],
|
|
errorHandler: (Error e) {
|
|
commandError = e;
|
|
},
|
|
);
|
|
|
|
expect(commandError, isA<ToolExit>());
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for plugin'),
|
|
contains('The following packages had errors:'),
|
|
contains(
|
|
' plugin:\n'
|
|
' Integration tests failed.',
|
|
),
|
|
]),
|
|
);
|
|
|
|
final Directory pluginExampleDirectory = getExampleDir(plugin);
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'devices',
|
|
'--machine',
|
|
], null),
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'test',
|
|
'-d',
|
|
_fakeIOSDevice,
|
|
'--debug-logs-dir=/path/to/logs',
|
|
'integration_test',
|
|
], pluginExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
group('packages', () {
|
|
test('can be driven', () async {
|
|
final RepositoryPackage package = createFakePackage(
|
|
'a_package',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/foo_test.dart',
|
|
'example/test_driver/integration_test.dart',
|
|
'example/web/index.html',
|
|
],
|
|
);
|
|
final Directory exampleDirectory = getExampleDir(package);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for a_package'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'drive',
|
|
'-d',
|
|
'web-server',
|
|
'--web-port=7357',
|
|
'--browser-name=chrome',
|
|
'--screenshot=/path/to/logs/a_package_example-drive',
|
|
'--driver',
|
|
'test_driver/integration_test.dart',
|
|
'--target',
|
|
'integration_test/foo_test.dart',
|
|
], exampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('drive handles missing CI screenshot directory', () async {
|
|
mockPlatform.environment.remove('FLUTTER_LOGS_DIR');
|
|
|
|
final RepositoryPackage package = createFakePackage(
|
|
'a_package',
|
|
packagesDir,
|
|
extraFiles: <String>[
|
|
'example/integration_test/foo_test.dart',
|
|
'example/test_driver/integration_test.dart',
|
|
'example/web/index.html',
|
|
],
|
|
);
|
|
final Directory exampleDirectory = getExampleDir(package);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for a_package'),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'drive',
|
|
'-d',
|
|
'web-server',
|
|
'--web-port=7357',
|
|
'--browser-name=chrome',
|
|
'--driver',
|
|
'test_driver/integration_test.dart',
|
|
'--target',
|
|
'integration_test/foo_test.dart',
|
|
], exampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('are skipped when example does not support platform', () async {
|
|
createFakePackage(
|
|
'a_package',
|
|
packagesDir,
|
|
isFlutter: true,
|
|
extraFiles: <String>[
|
|
'example/integration_test/foo_test.dart',
|
|
'example/test_driver/integration_test.dart',
|
|
],
|
|
);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for a_package'),
|
|
contains(
|
|
'Skipping a_package/example; does not support any '
|
|
'requested platforms',
|
|
),
|
|
contains('SKIPPING: No example supports requested platform(s).'),
|
|
]),
|
|
);
|
|
|
|
expect(processRunner.recordedCalls.isEmpty, true);
|
|
});
|
|
|
|
test('drive only supported examples if there is more than one', () async {
|
|
final RepositoryPackage package = createFakePackage(
|
|
'a_package',
|
|
packagesDir,
|
|
isFlutter: true,
|
|
examples: <String>['with_web', 'without_web'],
|
|
extraFiles: <String>[
|
|
'example/with_web/integration_test/foo_test.dart',
|
|
'example/with_web/test_driver/integration_test.dart',
|
|
'example/with_web/web/index.html',
|
|
'example/without_web/integration_test/foo_test.dart',
|
|
'example/without_web/test_driver/integration_test.dart',
|
|
],
|
|
);
|
|
final Directory supportedExampleDirectory = getExampleDir(
|
|
package,
|
|
).childDirectory('with_web');
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for a_package'),
|
|
contains(
|
|
'Skipping a_package/example/without_web; does not support any requested platforms.',
|
|
),
|
|
contains('No issues found!'),
|
|
]),
|
|
);
|
|
|
|
expect(
|
|
processRunner.recordedCalls,
|
|
orderedEquals(<ProcessCall>[
|
|
ProcessCall(getFlutterCommand(mockPlatform), const <String>[
|
|
'drive',
|
|
'-d',
|
|
'web-server',
|
|
'--web-port=7357',
|
|
'--browser-name=chrome',
|
|
'--screenshot=/path/to/logs/a_package_example_with_web-drive',
|
|
'--driver',
|
|
'test_driver/integration_test.dart',
|
|
'--target',
|
|
'integration_test/foo_test.dart',
|
|
], supportedExampleDirectory.path),
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('are skipped when there is no integration testing', () async {
|
|
createFakePackage(
|
|
'a_package',
|
|
packagesDir,
|
|
isFlutter: true,
|
|
extraFiles: <String>['example/web/index.html'],
|
|
);
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[
|
|
contains('Running for a_package'),
|
|
contains(
|
|
'SKIPPING: No example is configured for integration tests.',
|
|
),
|
|
]),
|
|
);
|
|
|
|
expect(processRunner.recordedCalls.isEmpty, true);
|
|
});
|
|
});
|
|
|
|
group('file filtering', () {
|
|
const files = <String>[
|
|
'pubspec.yaml',
|
|
'foo.dart',
|
|
'foo.java',
|
|
'foo.kt',
|
|
'foo.m',
|
|
'foo.swift',
|
|
'foo.cc',
|
|
'foo.cpp',
|
|
'foo.h',
|
|
];
|
|
for (final file in files) {
|
|
test('runs command for changes to $file', () async {
|
|
createFakePackage('package_a', packagesDir);
|
|
|
|
gitProcessRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(
|
|
MockProcess(
|
|
stdout:
|
|
'''
|
|
packages/package_a/$file
|
|
''',
|
|
),
|
|
),
|
|
];
|
|
|
|
// The target platform is irrelevant here; because this repo's
|
|
// packages are fully federated, there's no need to distinguish
|
|
// the ignore list by target (e.g., skipping iOS tests if only Java or
|
|
// Kotlin files change), because package-level filering will already
|
|
// accomplish the same goal.
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
'--web',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[contains('Running for package_a')]),
|
|
);
|
|
});
|
|
}
|
|
|
|
test('skips commands if all files should be ignored', () async {
|
|
createFakePackage('package_a', packagesDir);
|
|
|
|
gitProcessRunner.mockProcessesForExecutable['git-diff'] =
|
|
<FakeProcessInfo>[
|
|
FakeProcessInfo(
|
|
MockProcess(
|
|
stdout: '''
|
|
README.md
|
|
CODEOWNERS
|
|
.gitignore
|
|
packages/package_a/CHANGELOG.md
|
|
''',
|
|
),
|
|
),
|
|
];
|
|
|
|
final List<String> output = await runCapturingPrint(runner, <String>[
|
|
'drive-examples',
|
|
]);
|
|
|
|
expect(
|
|
output,
|
|
isNot(
|
|
containsAllInOrder(<Matcher>[contains('Running for package_a')]),
|
|
),
|
|
);
|
|
expect(
|
|
output,
|
|
containsAllInOrder(<Matcher>[contains('SKIPPING ALL PACKAGES')]),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
class _FakeDelayingProcess extends Fake implements io.Process {
|
|
/// Creates a mock process that takes [delayDuration] time to exit successfully.
|
|
_FakeDelayingProcess({
|
|
required Duration delayDuration,
|
|
required FakeAsync fakeAsync,
|
|
}) : _delayDuration = delayDuration,
|
|
_fakeAsync = fakeAsync;
|
|
|
|
final Duration _delayDuration;
|
|
final FakeAsync _fakeAsync;
|
|
|
|
@override
|
|
Future<int> get exitCode async {
|
|
_fakeAsync.elapse(_delayDuration);
|
|
return 0;
|
|
}
|
|
}
|