Description
Positional test targets are forwarded verbatim into every per-package run when --recursive is set, so a relative path can only resolve in one package and fails to load in all the others.
_runCommand in lib/src/cli/flutter_cli.dart fans out one run per discovered pubspec.yaml, each with that package as its working directory:
final processes = _Cmd.runWhere<T>(
run: (entity) => cmd(entity.parent.path),
where: (entity) => !ignore.excludes(entity) && _isPubspec(entity),
cwd: cwd,
);
TestCLIRunner.test then passes the same arguments (which carry argResults.rest) into each of those runs unchanged.
Steps To Reproduce
- Create a monorepo with two packages, each with its own test:
my_monorepo/
packages/
a/pubspec.yaml test/a_test.dart
b/pubspec.yaml test/b_test.dart
- From
my_monorepo, run:
very_good dart test -r test/a_test.dart
packages/a passes. packages/b tries to load packages/b/test/a_test.dart, which does not exist, fails to load, and the command exits 69.
Expected Behavior
Either of the following would be reasonable:
-
Reject the combination. --recursive and positional test targets describe mutually exclusive models of the working directory: a target is only meaningful relative to a single package root, and --recursive means there is not one. Failing fast with a message pointing at the right invocation is more useful than N-1 load errors around one incidental success.
-
Resolve targets against the invocation directory. Interpret each target relative to the original cwd, then pass each package only the targets that fall inside it, skipping packages with no matches. This would make very_good test -r packages/a/test/x_test.dart packages/b/test/y_test.dart do the obvious thing, but it needs decisions about targets that match no package or sit outside all of them.
Option 1 is the smaller change. TestCLIRunner.test already receives both recursive and the arguments, and TestCLIRunner.isTargettingTestFiles already exists as the predicate, so the check has a natural home at the point both very_good test and very_good dart test route through.
Additional Context
This came out of review on #1676, which adds a paths argument to the MCP test tool and so exposes both knobs side by side in a single call. That PR currently guards the combination in the MCP handler, but the invariant belongs to the test command rather than the transport — a guard here would cover both entry points and shell users.
Happy to open a PR once there is agreement on which direction you prefer.
Description
Positional test targets are forwarded verbatim into every per-package run when
--recursiveis set, so a relative path can only resolve in one package and fails to load in all the others._runCommandinlib/src/cli/flutter_cli.dartfans out one run per discoveredpubspec.yaml, each with that package as its working directory:TestCLIRunner.testthen passes the samearguments(which carryargResults.rest) into each of those runs unchanged.Steps To Reproduce
my_monorepo, run:very_good dart test -r test/a_test.dartpackages/apasses.packages/btries to loadpackages/b/test/a_test.dart, which does not exist, fails to load, and the command exits 69.Expected Behavior
Either of the following would be reasonable:
Reject the combination.
--recursiveand positional test targets describe mutually exclusive models of the working directory: a target is only meaningful relative to a single package root, and--recursivemeans there is not one. Failing fast with a message pointing at the right invocation is more useful than N-1 load errors around one incidental success.Resolve targets against the invocation directory. Interpret each target relative to the original cwd, then pass each package only the targets that fall inside it, skipping packages with no matches. This would make
very_good test -r packages/a/test/x_test.dart packages/b/test/y_test.dartdo the obvious thing, but it needs decisions about targets that match no package or sit outside all of them.Option 1 is the smaller change.
TestCLIRunner.testalready receives bothrecursiveand the arguments, andTestCLIRunner.isTargettingTestFilesalready exists as the predicate, so the check has a natural home at the point bothvery_good testandvery_good dart testroute through.Additional Context
This came out of review on #1676, which adds a
pathsargument to the MCPtesttool and so exposes both knobs side by side in a single call. That PR currently guards the combination in the MCP handler, but the invariant belongs to the test command rather than the transport — a guard here would cover both entry points and shell users.Happy to open a PR once there is agreement on which direction you prefer.