Skip to content

Commit eec53d9

Browse files
authored
feat(experimental): expose matchesTagsFilter to test if the current filter matches tags (#9913)
1 parent d4f924e commit eec53d9

File tree

7 files changed

+415
-8
lines changed

7 files changed

+415
-8
lines changed

docs/guide/test-tags.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,20 @@ You can also pass multiple `--tags-filter` flags. They are combined with AND log
300300
# Run tests that match (unit OR e2e) AND are NOT slow
301301
vitest --tags-filter="unit || e2e" --tags-filter="!slow"
302302
```
303+
304+
### Checking Tags Filter at Runtime
305+
306+
You can use `TestRunner.matchesTagsFilter` (since Vitest 4.1.1) to check whether the current tags filter matches a set of tags. This is useful for conditionally running expensive setup logic only when relevant tests are included:
307+
308+
```ts
309+
import { beforeAll, TestRunner } from 'vitest'
310+
311+
beforeAll(async () => {
312+
// Seed database when "vitest --tags-filter db" is used
313+
if (TestRunner.matchesTagsFilter(['db'])) {
314+
await seedDatabase()
315+
}
316+
})
317+
```
318+
319+
The method accepts an array of tags and returns `true` if the current `--tags-filter` would include a test with those tags. If no tags filter is active, it always returns `true`.

packages/runner/src/collect.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export async function collectTests(
3636
'collect_spec',
3737
{ 'code.file.path': filepath },
3838
async () => {
39+
runner._currentSpecification = typeof spec === 'string' ? { filepath: spec } : spec
40+
3941
const testLocations = typeof spec === 'string' ? undefined : spec.testLocations
4042
const testNamePattern = typeof spec === 'string' ? undefined : spec.testNamePattern
4143
const testIds = typeof spec === 'string' ? undefined : spec.testIds

packages/runner/src/types/runner.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ export interface FileSpecification {
5555
// file can be marked via a jsdoc comment to have tags,
5656
// these are _not_ tags to filter tests by
5757
fileTags?: string[]
58-
testLocations: number[] | undefined
59-
testNamePattern: RegExp | undefined
60-
testTagsFilter: string[] | undefined
61-
testIds: string[] | undefined
58+
testLocations?: number[] | undefined
59+
testNamePattern?: RegExp | undefined
60+
testTagsFilter?: string[] | undefined
61+
testIds?: string[] | undefined
6262
}
6363

6464
export interface TestTagDefinition extends Omit<TestOptions, 'tags' | 'shuffle'> {
@@ -231,8 +231,10 @@ export interface VitestRunner {
231231
// eslint-disable-next-line ts/method-signature-style
232232
trace?<T>(name: string, attributes: Record<string, any>, cb: () => T): T
233233

234-
/** @private */
234+
/** @internal */
235+
_currentSpecification?: FileSpecification | undefined
236+
/** @internal */
235237
_currentTaskStartTime?: number
236-
/** @private */
238+
/** @internal */
237239
_currentTaskTimeout?: number
238240
}

packages/runner/src/utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export {
1010
} from './collect'
1111
export { limitConcurrency } from './limit-concurrency'
1212
export { partitionSuiteChildren } from './suite'
13-
export { createTagsFilter, validateTags } from './tags'
13+
export { createTagsFilter, matchesTagsFilter, validateTags } from './tags'
1414
export {
1515
createTaskName,
1616
getFullName,

packages/runner/src/utils/tags.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,24 @@
11
import type { TestTagDefinition, VitestRunnerConfig } from '../types/runner'
2+
import { getRunner } from '../suite'
3+
4+
const filterMap = new WeakMap<string[], (testTags: string[]) => boolean>()
5+
6+
/**
7+
* @experimental
8+
*/
9+
export function matchesTagsFilter(testTags: string[]): boolean {
10+
const runner = getRunner()
11+
const tagsFilter = runner._currentSpecification?.testTagsFilter ?? runner.config.tagsFilter
12+
if (!tagsFilter) {
13+
return true
14+
}
15+
let tagsFilterPredicate = filterMap.get(tagsFilter)
16+
if (!tagsFilterPredicate) {
17+
tagsFilterPredicate = createTagsFilter(tagsFilter, runner.config.tags)
18+
filterMap.set(tagsFilter, tagsFilterPredicate)
19+
}
20+
return tagsFilterPredicate(testTags)
21+
}
222

323
export function validateTags(config: VitestRunnerConfig, tags: string[]): void {
424
if (!config.strictTags) {

packages/vitest/src/runtime/runners/test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
getFn,
2323
getHooks,
2424
} from '@vitest/runner'
25-
import { createChainable, getNames, getTestName, getTests } from '@vitest/runner/utils'
25+
import { createChainable, getNames, getTestName, getTests, matchesTagsFilter } from '@vitest/runner/utils'
2626
import { processError } from '@vitest/utils/error'
2727
import { normalize } from 'pathe'
2828
import { createExpect } from '../../integrations/chai/index'
@@ -278,6 +278,7 @@ export class TestRunner implements VitestTestRunner {
278278
static getTestFn: typeof getFn = getFn
279279
static setSuiteHooks: typeof getHooks = getHooks
280280
static setTestFn: typeof getFn = getFn
281+
static matchesTagsFilter: typeof matchesTagsFilter = matchesTagsFilter
281282

282283
/**
283284
* @deprecated

0 commit comments

Comments
 (0)