mirror of
https://github.com/flutter/packages.git
synced 2025-08-14 18:12:30 +08:00
[ci] Add a web version of Dart unit tests (#4352)
Adds new LUCI targets in bringup mode to run all possible Dart unit tests in Chrome. This is a new test (see linked issue), not a port of a Cirrus test, so it involves changes to tooling and packages: - The tooling now accepts an explicit platform. The default behavior if none is provided is the previous behavior of running in VM for everything but web plugin implementations (since that's convenient locally). - The tooling now has a basic understanding of `dart_test.yaml` `test_on` directives, to know when to skip. - Packages that don't support web have opt-out files. - Packages that do support web but have a few tests that fail on web have those tests opted out. - Packages that do support web but have a lot of failures on web have temporary opt-out files with TODOs + issue links. Most of https://github.com/flutter/flutter/issues/128979
This commit is contained in:
@ -27,8 +27,15 @@ class DartTestCommand extends PackageLoopingCommand {
|
||||
'See https://github.com/dart-lang/sdk/blob/main/docs/process/experimental-flags.md '
|
||||
'for details.',
|
||||
);
|
||||
argParser.addOption(
|
||||
_platformFlag,
|
||||
help: 'Runs tests on the given platform instead of the default platform '
|
||||
'("vm" in most cases, "chrome" for web plugin implementations).',
|
||||
);
|
||||
}
|
||||
|
||||
static const String _platformFlag = 'platform';
|
||||
|
||||
@override
|
||||
final String name = 'dart-test';
|
||||
|
||||
@ -52,17 +59,57 @@ class DartTestCommand extends PackageLoopingCommand {
|
||||
return PackageResult.skip('No test/ directory.');
|
||||
}
|
||||
|
||||
String? platform = getNullableStringArg(_platformFlag);
|
||||
|
||||
// Skip running plugin tests for non-web-supporting plugins (or non-web
|
||||
// federated plugin implementations) on web, since there's no reason to
|
||||
// expect them to work.
|
||||
final bool webPlatform = platform != null && platform != 'vm';
|
||||
final bool explicitVMPlatform = platform == 'vm';
|
||||
final bool isWebOnlyPluginImplementation = pluginSupportsPlatform(
|
||||
platformWeb, package,
|
||||
requiredMode: PlatformSupport.inline) &&
|
||||
package.directory.basename.endsWith('_web');
|
||||
if (webPlatform) {
|
||||
if (isFlutterPlugin(package) &&
|
||||
!pluginSupportsPlatform(platformWeb, package)) {
|
||||
return PackageResult.skip(
|
||||
"Non-web plugin tests don't need web testing.");
|
||||
}
|
||||
if (_requiresVM(package)) {
|
||||
// This explict skip is necessary because trying to run tests in a mode
|
||||
// that the package has opted out of returns a non-zero exit code.
|
||||
return PackageResult.skip('Package has opted out of non-vm testing.');
|
||||
}
|
||||
} else if (explicitVMPlatform) {
|
||||
if (isWebOnlyPluginImplementation) {
|
||||
return PackageResult.skip("Web plugin tests don't need vm testing.");
|
||||
}
|
||||
if (_requiresNonVM(package)) {
|
||||
// This explict skip is necessary because trying to run tests in a mode
|
||||
// that the package has opted out of returns a non-zero exit code.
|
||||
return PackageResult.skip('Package has opted out of vm testing.');
|
||||
}
|
||||
} else if (platform == null && isWebOnlyPluginImplementation) {
|
||||
// If no explicit mode is requested, run web plugin implementations in
|
||||
// Chrome since their tests are not expected to work in vm mode. This
|
||||
// allows easily running all unit tests locally, without having to run
|
||||
// both modes.
|
||||
platform = 'chrome';
|
||||
}
|
||||
|
||||
bool passed;
|
||||
if (package.requiresFlutter()) {
|
||||
passed = await _runFlutterTests(package);
|
||||
passed = await _runFlutterTests(package, platform: platform);
|
||||
} else {
|
||||
passed = await _runDartTests(package);
|
||||
passed = await _runDartTests(package, platform: platform);
|
||||
}
|
||||
return passed ? PackageResult.success() : PackageResult.fail();
|
||||
}
|
||||
|
||||
/// Runs the Dart tests for a Flutter package, returning true on success.
|
||||
Future<bool> _runFlutterTests(RepositoryPackage package) async {
|
||||
Future<bool> _runFlutterTests(RepositoryPackage package,
|
||||
{String? platform}) async {
|
||||
final String experiment = getStringArg(kEnableExperiment);
|
||||
|
||||
final int exitCode = await processRunner.runAndStream(
|
||||
@ -71,10 +118,7 @@ class DartTestCommand extends PackageLoopingCommand {
|
||||
'test',
|
||||
'--color',
|
||||
if (experiment.isNotEmpty) '--enable-experiment=$experiment',
|
||||
// TODO(ditman): Remove this once all plugins are migrated to 'drive'.
|
||||
if (pluginSupportsPlatform(platformWeb, package,
|
||||
requiredMode: PlatformSupport.inline))
|
||||
'--platform=chrome',
|
||||
if (platform != null) '--platform=$platform',
|
||||
],
|
||||
workingDir: package.directory,
|
||||
);
|
||||
@ -82,7 +126,8 @@ class DartTestCommand extends PackageLoopingCommand {
|
||||
}
|
||||
|
||||
/// Runs the Dart tests for a non-Flutter package, returning true on success.
|
||||
Future<bool> _runDartTests(RepositoryPackage package) async {
|
||||
Future<bool> _runDartTests(RepositoryPackage package,
|
||||
{String? platform}) async {
|
||||
// Unlike `flutter test`, `pub run test` does not automatically get
|
||||
// packages
|
||||
int exitCode = await processRunner.runAndStream(
|
||||
@ -103,10 +148,42 @@ class DartTestCommand extends PackageLoopingCommand {
|
||||
'run',
|
||||
if (experiment.isNotEmpty) '--enable-experiment=$experiment',
|
||||
'test',
|
||||
if (platform != null) '--platform=$platform',
|
||||
],
|
||||
workingDir: package.directory,
|
||||
);
|
||||
|
||||
return exitCode == 0;
|
||||
}
|
||||
|
||||
bool _requiresVM(RepositoryPackage package) {
|
||||
final File testConfig = package.directory.childFile('dart_test.yaml');
|
||||
if (!testConfig.existsSync()) {
|
||||
return false;
|
||||
}
|
||||
// test_on lines can be very complex, but in pratice the packages in this
|
||||
// repo currently only need the ability to require vm or not, so that
|
||||
// simple directive is all that is currently supported.
|
||||
final RegExp vmRequrimentRegex = RegExp(r'^test_on:\s*vm$');
|
||||
return testConfig
|
||||
.readAsLinesSync()
|
||||
.any((String line) => vmRequrimentRegex.hasMatch(line));
|
||||
}
|
||||
|
||||
bool _requiresNonVM(RepositoryPackage package) {
|
||||
final File testConfig = package.directory.childFile('dart_test.yaml');
|
||||
if (!testConfig.existsSync()) {
|
||||
return false;
|
||||
}
|
||||
// test_on lines can be very complex, but in pratice the packages in this
|
||||
// repo currently only need the ability to require vm or not, so a simple
|
||||
// one-target directive is all that's supported currently. Making it
|
||||
// deliberately strict avoids the possibility of accidentally skipping vm
|
||||
// coverage due to a complex expression that's not handled correctly.
|
||||
final RegExp testOnRegex = RegExp(r'^test_on:\s*([a-z])*\s*$');
|
||||
return testConfig.readAsLinesSync().any((String line) {
|
||||
final RegExpMatch? match = testOnRegex.firstMatch(line);
|
||||
return match != null && match.group(1) != 'vm';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user