run method

  1. @override
Future<ExitCode> run([
  1. List<String>? args
])
override

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 isDartOnly =
      argResults.wasParsed('dart-only') && argResults['dart-only'] as bool;
  final isFlutterOnly = argResults.wasParsed('flutter-only') &&
      argResults['flutter-only'] as bool;
  final isBoth = isDartOnly == isFlutterOnly;
  final optimize = argResults['optimize'] as bool;
  final isRecursive = argResults['recursive'] as bool? ?? false;
  final cleanOptimizedFiles = argResults['clean'] as bool;

  final providedTests = [...argResults.rest];

  List<String>? testsToRun;
  if (providedTests.isNotEmpty) {
    testsToRun = getTestsFromProvided(providedTests);

    if (testsToRun.isEmpty) {
      logger.err('No valid files or directories found');
      return ExitCode.usage;
    }
  }

  if (isRecursive && testsToRun != null) {
    logger.err(
      'Cannot run tests recursively with specific files or directories',
    );
    return ExitCode.usage;
  }

  warnDartOrFlutterTests(
    isFlutterOnly: isFlutterOnly,
    isDartOnly: isDartOnly,
  );

  if (isRecursive) {
    logger.detail('Running tests recursively');
  }

  final pubspecs = await pubspecYaml.all(recursive: isRecursive);

  if (pubspecs.isEmpty) {
    logger.err('No pubspec.yaml files found');
    return ExitCode.unavailable;
  }

  final (:both, :dart, :flutter) = getArgs(this);

  final flutterArgs = [...flutter, ...both];
  final dartArgs = [...dart, ...both];

  final commandsToRun = <CommandToRun>[];

  void Function()? cleanUp;

  if (testsToRun != null) {
    final pubspec = pubspecYaml.nearest();

    if (pubspec == null) {
      logger.err('No pubspec.yaml file found');
      return ExitCode.unavailable;
    }

    final tool = DetermineFlutterOrDart(
      pubspecYaml: pubspec,
      pubspecLock: pubspecLock,
      findFile: findFile,
    );

    if (optimize) {
      final entities = testsToRun.map((e) => fs.file(e)).toList();

      final testFiles =
          separateTestFiles(entities, isFlutter: tool.isFlutter);

      logger.detail('Optimizing provided test files, $testFiles');

      final tests = writeOptimizedFiles(
        testFiles,
        testDir: path.join(tool.directory(), 'test'),
        tool: tool,
      );

      logger.detail('Got tests, $tests');

      commandsToRun.addAll(
        getCommandsToRun(
          tests,
          flutterArgs: flutterArgs,
          dartArgs: dartArgs,
        ),
      );

      cleanUp = () => cleanUpOptimizedFiles(tests.keys);
    } else {
      final command = createTestCommand(
        projectRoot: tool.directory(),
        relativeProjectRoot: path.relative(tool.directory()),
        tool: tool,
        flutterArgs: flutterArgs,
        dartArgs: dartArgs,
        tests: testsToRun,
      );

      commandsToRun.add(command);
    }
  } else {
    final testDirsResult = getTestDirs(
      pubspecs,
      isFlutterOnly: isFlutterOnly,
      isDartOnly: isDartOnly,
    );

    // exit code is not null
    if (testDirsResult.$2 case final ExitCode exitCode) {
      return exitCode;
    }

    final (testDirs, dirTools) = testDirsResult.$1!;

    final result = getTestsFromDirs(
      testDirs,
      dirTools,
      optimize: optimize,
    );

    // exit code is not null
    if (result.$2 case final ExitCode exitCode) {
      return exitCode;
    }

    final possibleTests = result.$1;

    if (possibleTests == null) {
      logger.err('No tests found');
      return ExitCode.unavailable;
    }

    final tests = possibleTests;

    commandsToRun.addAll(
      getCommandsToRun(
        tests,
        flutterArgs: flutterArgs,
        dartArgs: dartArgs,
      ),
    );

    cleanUp = () => cleanUpOptimizedFiles(tests.keys);
  }

  logger.info('ARGS:');

  if (isBoth || isDartOnly) {
    var message = darkGray.wrap('  Dart:    ')!;
    if (dartArgs.isEmpty) {
      message += cyan.wrap('NONE')!;
    } else {
      message += cyan.wrap(dartArgs.join(', '))!;
    }
    logger.info(message);
  }

  if (isBoth || isFlutterOnly) {
    var message = darkGray.wrap('  Flutter: ')!;
    if (flutterArgs.isEmpty) {
      message += cyan.wrap('NONE')!;
    } else {
      message += cyan.wrap(flutterArgs.join(', '))!;
    }
    logger.info(message);
  }

  logger.write('\n');

  final exitCode = await runCommands(
    commandsToRun,
    runConcurrently: argResults['concurrent'] as bool,
    bail: argResults['bail'] as bool,
  );

  logger.write('\n');

  if (optimize && cleanOptimizedFiles) {
    final done = logger.progress('Cleaning up optimized test files');

    cleanUp?.call();

    done.complete('Optimized test files cleaned!');
  }

  if (exitCode != ExitCode.success) {
    logger.err('${red.wrap('✗')} Some tests failed');
  } else {
    logger.write('${green.wrap('✔')} Tests passed');
  }

  logger.write('\n');

  return exitCode;
}