You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Vitest extension doesn't run test files with tags #799
I debugged this by replicating the extension's worker code path (packages/worker/src/index.ts → createVitest + packages/worker/src/runner.ts → rerunTestSpecifications) in a standalone Node script and found the root cause.
TL;DR: The extension's config discovery treats my shared base config as a runnable config and spawns a second Vitest instance for it and that instance has no tags.
My shared base file vitest.config.base.tsmatches this pattern.
resolveVitestConfigs() in packages/extension/src/spawn/pkg.ts spawns one Vitest instance per matched file (intentionally, to support vitest.e2e.config.ts etc.).
The base-config instance is rooted at the repo root with the default include, so it claims the same test files as my package-level configs — but the base config defines no tags.
When that instance collects a tagged test, @vitest/runner's validateTags throws exactly the reported error.
The CLI never fails because nothing ever runs vitest --config vitest.config.base.ts.
Minimal reproduction
Three files (this is the structure of my real project, trading-signals):
Creating a Vitest instance for vitest.config.base.ts (as the extension does) and running the test file reproduces it verbatim on Vitest 4.1.10:
FAIL packages/foo/test/tags.test.ts
Error: The Vitest config does't define any "tags", cannot apply "tulipindicators" tag for this test.
Running the same file through the leaf config instance passes. I verified both paths with the exact createVitest options the extension worker uses.
Note: the sample added in #800 can't reproduce the issue as it defines the tags in the same config file that the extension discovers, which works fine. The repro sample needs the base-config structure above.
Workaround
Rename vitest.config.base.ts to vitest.shared.ts (the naming convention from the Vitest docs here) or set vitest.configSearchPatternExclude in VS Code settings.
Possible fixes on the extension side
When multiple discovered instances claim the same test file, prefer the config that is closest to the file (dedupe by ownership).
When multiple discovered instances claim the same test file, prefer the config that is closest to the file (dedupe by ownership).
This is not how the relationship works. It's not that test files define what config they are in, it's the config that defines what test files are in. It is perfectly valid to reuse the same test file in different configs, in my opinion. You can also see what configs provide test files in your UI:
You can disable them too with "Toggle Configs" command:
Fair point on the model. But can you help me understand this:
Why does the extension fail to run my tests when the shared config is named vitest.config.base.ts, but succeed when the exact same file is named vitest.shared.ts?
Why does the extension fail to run my tests when the shared config is named vitest.config.base.ts, but succeed when the exact same file is named vitest.shared.ts?
Configs define test profiles. You can see the profiles on the first picture I sent in my previous comment. Profile defines how tests run, not what tests exist. For some reason, in your case the default profile for that test file is vitest.config.base.ts and not the other one, but the extension does creates multiple profiles in your case correctly. You can change the default profile by clicking on the chevron button next to the "run" button.
vitest.config.base.ts matches the config pattern and vitest.shared.ts does not match the pattern, so Vitest doesn't create a separate profile for it.
@sheremet-va thanks for pointing me to the Vitest profiles. I still believe there's an issue with which profile gets selected when rerunning tests from the extension. Since it's tricky to describe in writing, I recorded a short video demonstrating it: https://youtu.be/7ZJjfOY6kb8
@sheremet-va thanks for pointing me to the Vitest profiles. I still believe there's an issue with which profile gets selected when rerunning tests from the extension. Since it's tricky to describe in writing, I recorded a short video demonstrating it: https://youtu.be/7ZJjfOY6kb8
I already explained everything that you show in your video though. If you don't want your shared config to run the tests, disable the profile or make it non default. I actually don't know why it decides the shared be the default in the gutter icon, probably because of the order (the shared profile is first in the list)
I actually don't know why it decides the shared be the default in the gutter icon
That's exactly my point. When I hit "Run" on a test in /packages/module/my.test.ts from the grid, I expect it to use /packages/module/vitest.config.ts (most specific) instead of resolving to /vitest.config.base.ts.
TypeScript works the same way: open /packages/module/code.ts and you get errors based on /packages/module/tsconfig.json, even if it extends /tsconfig.base.json.
Where I see room for improvement is the resolution order. Going by specificity would feel more predictable here. Don't you think so?
Where I see room for improvement is the resolution order. Going by specificity would feel more predictable here. Don't you think so?
I do not think so because it is not general enough. Say, you have multiple configs in the folder. What do you choose now? We just provide the default. If you have a custom setup, configure it.
The extension doesn't pick a favorite, vscode API controls which provider runs. Profile doesn't even know which config it belongs to, you can have multiple profiles for the same config (coverage+debug+run). What we could do is maybe register them in a different order, so vscode picks up the earliest automatically? In that case we would have to delay it until all configs are resolved which would slow down the initialisation for nested configs.
What we could do is maybe register them in a different order, so vscode picks up the earliest automatically?
I like that idea, because it helps the user without asking them to understand the extension's internals first.
To see it from the end user's point of view, this is what happened to me:
I added tags to my test file
I listed the tags properly in my Vitest config
I hit "Run Test" in the grid and got: The Vitest config does't define any "tags"
This made me totally confused. There was no indicator that I had to switch my Vitest config profile (such a warning or note could also help). Without opening this thread and talking to you, I would have just thought there is a defect with the extension.
Activity
bennycode commentedon Aug 3, 2026
I debugged this by replicating the extension's worker code path (
packages/worker/src/index.ts→createVitest+packages/worker/src/runner.ts→rerunTestSpecifications) in a standalone Node script and found the root cause.TL;DR: The extension's config discovery treats my shared base config as a runnable config and spawns a second Vitest instance for it and that instance has no
tags.Root cause
vitest.config.base.tsmatches this pattern.resolveVitestConfigs()inpackages/extension/src/spawn/pkg.tsspawns one Vitest instance per matched file (intentionally, to supportvitest.e2e.config.tsetc.).include, so it claims the same test files as my package-level configs — but the base config defines notags.@vitest/runner'svalidateTagsthrows exactly the reported error.The CLI never fails because nothing ever runs
vitest --config vitest.config.base.ts.Minimal reproduction
Three files (this is the structure of my real project, trading-signals):
Creating a Vitest instance for
vitest.config.base.ts(as the extension does) and running the test file reproduces it verbatim on Vitest 4.1.10:Running the same file through the leaf config instance passes. I verified both paths with the exact
createVitestoptions the extension worker uses.Note: the sample added in #800 can't reproduce the issue as it defines the tags in the same config file that the extension discovers, which works fine. The repro sample needs the base-config structure above.
Workaround
Rename
vitest.config.base.tstovitest.shared.ts(the naming convention from the Vitest docs here) or setvitest.configSearchPatternExcludein VS Code settings.Possible fixes on the extension side
When multiple discovered instances claim the same test file, prefer the config that is closest to the file (dedupe by ownership).
sheremet-va commentedon Aug 3, 2026
This is not how the relationship works. It's not that test files define what config they are in, it's the config that defines what test files are in. It is perfectly valid to reuse the same test file in different configs, in my opinion. You can also see what configs provide test files in your UI:
You can disable them too with "Toggle Configs" command:
I am open to improving the error message though.
bennycode commentedon Aug 4, 2026
Fair point on the model. But can you help me understand this:
Why does the extension fail to run my tests when the shared config is named
vitest.config.base.ts, but succeed when the exact same file is namedvitest.shared.ts?I could fix the extension error by just renaming my config: bennycode/trading-signals#1276
sheremet-va commentedon Aug 4, 2026
Configs define test profiles. You can see the profiles on the first picture I sent in my previous comment. Profile defines how tests run, not what tests exist. For some reason, in your case the default profile for that test file is
vitest.config.base.tsand not the other one, but the extension does creates multiple profiles in your case correctly. You can change the default profile by clicking on the chevron button next to the "run" button.vitest.config.base.tsmatches the config pattern andvitest.shared.tsdoes not match the pattern, so Vitest doesn't create a separate profile for it.bennycode commentedon Aug 4, 2026
@sheremet-va thanks for pointing me to the Vitest profiles. I still believe there's an issue with which profile gets selected when rerunning tests from the extension. Since it's tricky to describe in writing, I recorded a short video demonstrating it: https://youtu.be/7ZJjfOY6kb8
sheremet-va commentedon Aug 5, 2026
I already explained everything that you show in your video though. If you don't want your shared config to run the tests, disable the profile or make it non default. I actually don't know why it decides the shared be the default in the gutter icon, probably because of the order (the shared profile is first in the list)
bennycode commentedon Aug 5, 2026
That's exactly my point. When I hit "Run" on a test in
/packages/module/my.test.tsfrom the grid, I expect it to use/packages/module/vitest.config.ts(most specific) instead of resolving to/vitest.config.base.ts.TypeScript works the same way: open
/packages/module/code.tsand you get errors based on/packages/module/tsconfig.json, even if it extends/tsconfig.base.json.Where I see room for improvement is the resolution order. Going by specificity would feel more predictable here. Don't you think so?
sheremet-va commentedon Aug 5, 2026
This is how profiles are defined:
vscode/packages/extension/src/extension.ts
Line 143 in 1a759e8
vscode/packages/extension/src/api.ts
Line 75 in e5cc3f2
fix: pick the closest config's run profile when several configs claim…
bennycode commentedon Aug 6, 2026
I like that idea, because it helps the user without asking them to understand the extension's internals first.
To see it from the end user's point of view, this is what happened to me:
This made me totally confused. There was no indicator that I had to switch my Vitest config profile (such a warning or note could also help). Without opening this thread and talking to you, I would have just thought there is a defect with the extension.
fix: run gutter tests with the most specific config when several conf…