run method
Runs this command.
The return value is wrapped in a Future
if necessary and returned by
CommandRunner.runCommand
.
Implementation
@override
Future<ExitCode> run([List<String>? args]) async {
final argResults = args != null ? argParser.parse(args) : super.argResults!;
final isRecursive = argResults['recursive'] as bool;
final isDartOnly =
argResults.wasParsed('dart-only') && argResults['dart-only'] as bool;
final isFlutterOnly = argResults.wasParsed('flutter-only') &&
argResults['flutter-only'] as bool;
final concurrent = argResults['concurrent'] as bool;
final clean = argResults['clean'] as bool;
final optimize = argResults['optimize'] as bool;
final runTestType =
TestScope.options[argResults['scope'] as String] ?? TestScope.active;
warnDartOrFlutterTests(
isFlutterOnly: isFlutterOnly,
isDartOnly: isDartOnly,
);
final pubspecs = await pubspecYaml.all(recursive: isRecursive);
final testDirsResult = getTestDirs(
pubspecs,
isFlutterOnly: isFlutterOnly,
isDartOnly: isDartOnly,
);
if (testDirsResult.$2 case final ExitCode exitCode) {
return exitCode;
}
final (testDirs, dirTools) = testDirsResult.$1!;
final testsResult = getPackagesToTest(
testDirs,
dirTools,
optimize: optimize,
);
// exit code is not null
if (testsResult.$2 case final ExitCode exitCode) {
return exitCode;
}
final tests = testsResult.$1!;
final libDirs = testDirs.map((e) => e.replaceAll(RegExp(r'test$'), 'lib'));
final (:both, :dart, :flutter) = getArgs(this);
final flutterArgs = [...flutter, ...both];
final dartArgs = [...dart, ...both];
var printMessage = true;
logger.detail(
'Watching directories: ${[
...testDirs,
...libDirs,
].map(path.relative).join(', ')}',
);
var runType = runTestType;
var runConcurrently = concurrent;
Iterable<PackageToTest>? lastTests;
// This setup up will not include any new packages created,
// only the ones that exist when the command is run
while (true) {
if (printMessage) {
writeWaitingMessage(
runType,
runConcurrently: runConcurrently,
);
}
printMessage = false;
final (type: event, :file) = await waitForChange(
testDirs: testDirs,
libDirs: libDirs,
printMessage: () => writeWaitingMessage(
runType,
runConcurrently: runConcurrently,
),
);
if (event.isExit) {
break;
}
if (event.isToggleModified) {
runType = TestScope.toggle(runType);
printMessage = true;
lastTests = null;
continue;
}
if (event.isToggleConcurrency) {
runConcurrently = !runConcurrently;
printMessage = true;
continue;
}
final testsToRun = <PackageToTest>{};
if (!event.isRun) {
if (file == null) {
logger.detail('No file changed, waiting for changes...');
continue;
}
if (file.endsWith(TesterMixin.optimizedTestBasename)) {
logger.detail('Optimized test file changed, waiting for changes...');
continue;
}
}
if (runType.isAll) {
logger.info('Running all tests');
testsToRun.addAll(tests);
} else if (file == null) {
logger.info('Checking for last tests run...');
await Future<void>.delayed(const Duration(milliseconds: 100));
if (lastTests == null) {
logger.info(
red.wrap('No previous tests found, modify a file to run tests'),
);
printMessage = true;
continue;
}
testsToRun.addAll(lastTests);
} else {
final packageToTest = await findTest(
tests,
file,
returnTestFile: runType.isModified,
);
if (packageToTest == null) {
logger.detail('No test found for $file, waiting for changes...');
continue;
}
logger.info('Running tests for ${path.relative(file)}');
testsToRun.add(packageToTest);
}
lastTests = testsToRun;
printMessage = true;
final commandsToRun = getCommandsToRun(
testsToRun,
flutterArgs: flutterArgs,
dartArgs: dartArgs,
);
final exitCode = await runCommands(
commandsToRun,
runConcurrently: runConcurrently,
bail: false,
);
if (exitCode != ExitCode.success) {
logger.err('${red.wrap('✗')} Some tests failed');
} else {
logger.write('${green.wrap('✔')} Tests passed');
}
}
if (optimize && clean) {
final done = logger.progress('Cleaning up optimized test files');
cleanUpOptimizedFiles(tests.map((e) => e.optimizedPath));
done.complete('Optimized test files cleaned!');
}
return ExitCode.success;
}