diff --git a/lib/src/commands/test/test.dart b/lib/src/commands/test/test.dart index 39321ec7a..e64138542 100644 --- a/lib/src/commands/test/test.dart +++ b/lib/src/commands/test/test.dart @@ -109,6 +109,18 @@ class TestCommand extends Command { 'Multiple defines can be passed by repeating ' '"--dart-define" multiple times.', valueHelp: 'foo=bar', + ) + ..addMultiOption( + 'dart-define-from-file', + help: 'The path of a .json or .env file containing key-value pairs ' + 'that will be available as environment variables. ' + 'These can be accessed using the String.fromEnvironment, ' + 'bool.fromEnvironment, and int.fromEnvironment constructors. ' + 'Multiple defines can be passed by repeating ' + '"--dart-define-from-file" multiple times. ' + 'Entries from "--dart-define" with identical keys take ' + 'precedence over entries from these files.', + valueHelp: 'use-define-config.json|.env', ); } @@ -161,6 +173,8 @@ This command should be run from the root of your Flutter project.''', final updateGoldens = _argResults['update-goldens'] as bool; final forceAnsi = _argResults['force-ansi'] as bool?; final dartDefine = _argResults['dart-define'] as List?; + final dartDefineFromFile = + _argResults['dart-define-from-file'] as List?; final rest = _argResults.rest; if (isFlutterInstalled) { @@ -184,6 +198,9 @@ This command should be run from the root of your Flutter project.''', if (updateGoldens) '--update-goldens', if (dartDefine != null) for (final value in dartDefine) '--dart-define=$value', + if (dartDefineFromFile != null) + for (final value in dartDefineFromFile) + '--dart-define-from-file=$value', ...['-j', concurrency], '--no-pub', ...rest, diff --git a/test/src/commands/test/test_test.dart b/test/src/commands/test/test_test.dart index 046c9567e..3cf5a4044 100644 --- a/test/src/commands/test/test_test.dart +++ b/test/src/commands/test/test_test.dart @@ -21,21 +21,22 @@ const expectedTestUsage = [ 'Run tests in a Dart or Flutter project.\n' '\n' 'Usage: very_good test [arguments]\n' - '-h, --help Print this usage information.\n' - ''' --coverage Whether to collect coverage information.\n''' - '''-r, --recursive Run tests recursively for all nested packages.\n''' - ''' --[no-]optimization Whether to apply optimizations for test performance.\n''' - ''' (defaults to on)\n''' - '''-j, --concurrency The number of concurrent test suites run.\n''' - ''' (defaults to "4")\n''' - '''-t, --tags Run only tests associated with the specified tags.\n''' - ''' --exclude-coverage A glob which will be used to exclude files that match from the coverage.\n''' - '''-x, --exclude-tags Run only tests that do not have the specified tags.\n''' - ''' --min-coverage Whether to enforce a minimum coverage percentage.\n''' - ''' --test-randomize-ordering-seed The seed to randomize the execution order of test cases within test files.\n''' - ''' --update-goldens Whether "matchesGoldenFile()" calls within your test methods should update the golden files.\n''' - ''' --force-ansi Whether to force ansi output. If not specified, it will maintain the default behavior based on stdout and stderr.\n''' - ''' --dart-define= Additional key-value pairs that will be available as constants from the String.fromEnvironment, bool.fromEnvironment, int.fromEnvironment, and double.fromEnvironment constructors. Multiple defines can be passed by repeating "--dart-define" multiple times.\n''' + '''-h, --help Print this usage information.\n''' + ''' --coverage Whether to collect coverage information.\n''' + '''-r, --recursive Run tests recursively for all nested packages.\n''' + ''' --[no-]optimization Whether to apply optimizations for test performance.\n''' + ''' (defaults to on)\n''' + '''-j, --concurrency The number of concurrent test suites run.\n''' + ''' (defaults to "4")\n''' + '''-t, --tags Run only tests associated with the specified tags.\n''' + ''' --exclude-coverage A glob which will be used to exclude files that match from the coverage.\n''' + '''-x, --exclude-tags Run only tests that do not have the specified tags.\n''' + ''' --min-coverage Whether to enforce a minimum coverage percentage.\n''' + ''' --test-randomize-ordering-seed The seed to randomize the execution order of test cases within test files.\n''' + ''' --update-goldens Whether "matchesGoldenFile()" calls within your test methods should update the golden files.\n''' + ''' --force-ansi Whether to force ansi output. If not specified, it will maintain the default behavior based on stdout and stderr.\n''' + ''' --dart-define= Additional key-value pairs that will be available as constants from the String.fromEnvironment, bool.fromEnvironment, int.fromEnvironment, and double.fromEnvironment constructors. Multiple defines can be passed by repeating "--dart-define" multiple times.\n''' + ''' --dart-define-from-file= The path of a .json or .env file containing key-value pairs that will be available as environment variables. These can be accessed using the String.fromEnvironment, bool.fromEnvironment, and int.fromEnvironment constructors. Multiple defines can be passed by repeating "--dart-define-from-file" multiple times. Entries from "--dart-define" with identical keys take precedence over entries from these files.\n''' '\n' 'Run "very_good help" to see global options.' ]; @@ -484,6 +485,27 @@ void main() { ).called(1); }); + test('completes normally --dart-define-from-file', () async { + when( + () => argResults['dart-define-from-file'], + ).thenReturn(['defines/foo.json', 'bar.env']); + final result = await testCommand.run(); + expect(result, equals(ExitCode.success.code)); + verify( + () => flutterTest( + optimizePerformance: true, + arguments: [ + '--dart-define-from-file=defines/foo.json', + '--dart-define-from-file=bar.env', + ...defaultArguments, + ], + logger: logger, + stdout: logger.write, + stderr: logger.err, + ), + ).called(1); + }); + test('completes normally --force-ansi', () async { when(() => argResults['force-ansi']).thenReturn(true); final result = await testCommand.run();