Troubleshooting
Each entry starts from what you see. For any of them, -v writes every decision and its reason to stderr; that log answers most questions, and it is what to send us.
td affected --base origin/main -v
The whole test project ran
Look for the project in the output: the reason is printed next to it. The usual causes are a build-wide file, a non-C# file in the project, a global using, or a type found through reflection. What runs everything lists them all. In the -v log, a line such as affects whole project: True names the file.
No coverage map was used
Without a map, selection traces names, which is wider. The log says why there was none:
No coverage maps within 50 commits before the merge base: nothing was recorded recently on the default branch. Record a map on every push there; the action'srecordmode does it.Ignoring the coverage map of … which is not an ancestor of the base: the map comes from another branch, or from before a force push or a long-running branch. Record again on the default branch, or raise--max-map-age.--maps-dir … does not exist: the folder with the maps was not restored before the run.- On GitHub Actions, the job needs
actions: readpermission to list the cache entries that hold the maps.
The base commit cannot be found
TestDetta compares your branch with the merge base, so it needs the history of both. The action stops with:
TestDetta compares with a base commit and needs the full history. Use actions/checkout with fetch-depth: 0.
Check out with fetch-depth: 0. On other CI systems, turn off shallow clones and fetch the target branch with an explicit refspec, as shown for each system in other CI systems.
Fewer tests were skipped than expected
- The map is older than the merge base and a build or configuration file changed in between: the affected projects run completely.
--drift-fallback namenarrows them by name instead. - A test class is selected without touching the change. Name tracing is cautious: a class that names the changed type is selected even if coverage would have ruled it out. A log line such as
is not in the coverage map of … Record the map againmeans the map is out of date for that project. - A central helper changed. Code that most tests run, such as a shared base class or a serializer, selects most tests. That is correct.
The filter matched no test
When a project's filter selects no test, TestDetta runs the project again without the filter and logs The filter for … matched no test; running it unfiltered. Nothing is missed, but this is a bug on our side: please send the -v log.
Squash merges, rebases and force pushes
Maps are recorded for commits on the default branch, and a pull request finds the newest one at or before its merge base. A squash merge or rebase creates new commits on the default branch; the next push records a map for them, and until then pull requests use the previous map through the drift bridge. A force push to a pull request branch changes nothing: the merge base is computed again.
Pull requests from forks
CI systems do not pass secrets to pull requests from forks. Public repositories need no license, so nothing changes for them. For a private repository, a run without a license runs every test, as it would without TestDetta.
Questions
Is the code coverage of a selected run complete?
No. A run that skips tests produces partial coverage. Publish coverage from the full runs on the default branch; recording runs every test there.
Can tests be retried?
Yes, with your framework's own retry option: everything after -- goes to dotnet test unchanged.
Can the selected tests be split across parallel jobs?
td affected --format commands prints one dotnet test command per test project, with its filter. Hand the lines out to your jobs.