Hive
Tuist cache + selecting testing erroneously skips all tests
GitHub issue · Open
What happened?
I have a PR that originally failed unit tests due to runner time outs (a known issue per the github-runners repository). This means that our unit tests didn’t all successfully run. Indeed, in our project dashboard the unit test showed up as “failed”.
I pushed a commit that had no source code changes just to get the tests running again, and it skipped all the tests through selective testing. I assume this is because it’s looking at the changes from this commit and didn’t see any source code changes. But that means it erroneously reported the tests as “passed” ultimately.
How do we reproduce it?
- Have a repository with some unit tests
- Create a PR and have those unit tests time out (could set time out of the unit tests to be something like…3 minutes to guarantee failure).
- Push a new commit with non source code changes
- Observe that tuist cache reports that all the tests passed due to selective testing, even though previous tests failed.
Error log
There’s no error, but the tests that didn’t run due to the hang don’t get re-run.
macOS version
Github runner macos 26
Tuist version
4.90.0
Xcode version
26.0.1
Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.
Start a Flight and preserve its objective, outcome, and session here.
Tuist’s selective testing skips tests if no source code changes are detected since the last successful run, regardless of whether the previous test run failed or timed out. This is expected behavior: selective testing only considers file changes, not the outcome of previous test runs, so pushing a non-source code change will not trigger a rerun of failed tests and may incorrectly report them as passed if the cache is still valid. This limitation is confirmed by maintainers and documented in this issue.
Currently, there is no configuration or workaround in Tuist to force rerunning tests after a failed or incomplete run when using selective testing. The cache invalidation logic does not track test outcomes—only content hashes—so transient failures like timeouts are not accounted for in subsequent runs. To ensure tests are rerun after failures, you may need to disable selective testing (--no-selective-testing) or manually invalidate the cache.
Let me know if you want details on disabling selective testing or forcing a full test run.
To reply, just mention @dosu.
Docs are dead. Just use Dosu.
@dosu maybe this is worth a discussion or some added documentation because this feels kind of dangerous from a CI standpoint if we are relying on the tuist cache to tell us if tests pass. Particularly in a scenario like:
- I push a PR that doesn’t compile because i wrote Sting instead if String in one module, but I’ve made changes in 3 modules. Tests fail because they don’t compile.
- I push a fix for that one module, but only that module’s tests get run because that’s the only change seen, but there could be errors in the other 2 caught by unit tests.
You’re right—this is a real risk with Tuist’s selective testing and caching in CI. Selective testing currently skips tests for modules that haven’t changed since the last successful run, regardless of whether previous runs failed or didn’t compile, which can lead to missed errors in other modules if only a subset of changes are detected. This limitation is acknowledged by maintainers and is being actively discussed for improvement and documentation [source].
Recent work has started to address this by caching successful test results even if other tests fail, but the granularity is still at the module/target level, not at the file or test case level [source]. There are also proposals to add CLI flags (like --no-upload) and configuration options to control when selective test results are uploaded to remote cache, which could help mitigate CI risks [source].
For now, best practices to avoid false positives in CI include disabling selective testing (--no-selective-testing) for critical runs, manually invalidating the cache after failed builds, or configuring cache profiles to force full test runs when needed. This area is definitely worth further documentation and discussion, and the community is aware of the need for clearer guidance and safer defaults [source].
To reply, just mention @dosu.
Docs are dead. Just use Dosu.