Skip to content

Commit b905f45

Browse files
committed
feat: support custom colors for test.name
1 parent 29084f1 commit b905f45

File tree

24 files changed

+123
-59
lines changed

24 files changed

+123
-59
lines changed

packages/browser/src/node/plugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ export default (parentServer: ParentBrowserProject, base = '/'): Plugin[] => {
383383
{
384384
name: 'vitest:browser:in-source-tests',
385385
transform(code, id) {
386-
const project = parentServer.vitest.getProjectByName(parentServer.config.name)
386+
const project = parentServer.vitest.getProjectByName(parentServer.config.name.label)
387387
if (!project._isCachedTestFile(id) || !code.includes('import.meta.vitest')) {
388388
return
389389
}

packages/ui/client/components/FileDetails.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ debouncedWatch(
137137
)
138138
139139
const projectNameColor = computed(() => {
140-
return getProjectNameColor(current.value?.file.projectName)
140+
return getProjectNameColor(current.value?.file.projectName, undefined)
141141
})
142142
143143
const projectNameTextColor = computed(() => {

packages/ui/client/utils/task.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import type { Suite, Task } from 'vitest'
1+
import type { LabelColor, Suite, Task } from 'vitest'
2+
3+
const labelDefaultColors: LabelColor[] = ['yellow', 'cyan', 'green', 'magenta']
24

35
export function isSuite(task: Task): task is Suite {
46
return Object.hasOwnProperty.call(task, 'tasks')
@@ -18,13 +20,19 @@ export function caseInsensitiveMatch(target: string, str2: string) {
1820
return target.toLowerCase().includes(str2.toLowerCase())
1921
}
2022

21-
export function getProjectNameColor(name: string | undefined) {
23+
export function getProjectNameColor(name: string | undefined, color?: LabelColor) {
2224
if (!name) {
2325
return ''
2426
}
25-
const index = name
26-
.split('')
27-
.reduce((acc, v, idx) => acc + v.charCodeAt(0) + idx, 0)
28-
const colors = ['yellow', 'cyan', 'green', 'magenta']
29-
return colors[index % colors.length]
27+
let background = color?.toLowerCase() as Lowercase<LabelColor> | undefined
28+
29+
if (!background) {
30+
const index = name
31+
.split('')
32+
.reduce((acc, v, idx) => acc + v.charCodeAt(0) + idx, 0)
33+
34+
background = labelDefaultColors[index % labelDefaultColors.length]
35+
}
36+
37+
return background
3038
}

packages/vitest/src/api/setup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export function setup(ctx: Vitest, _server?: ViteDevServer): void {
121121
const spec = await ctx.globTestSpecifications()
122122
return spec.map(spec => [
123123
{
124-
name: spec.project.config.name,
124+
name: spec.project.config.name.label,
125125
root: spec.project.config.root,
126126
},
127127
spec.moduleId,

packages/vitest/src/node/config/resolveConfig.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ export function resolveConfig(
145145
resolved.project = toArray(resolved.project)
146146
resolved.provide ??= {}
147147

148+
resolved.name = typeof options.name === 'string'
149+
? { label: options.name }
150+
: { label: '', ...options.name }
151+
148152
const inspector = resolved.inspect || resolved.inspectBrk
149153

150154
resolved.inspector = {
@@ -732,7 +736,7 @@ export function resolveConfig(
732736
let cacheDir = VitestCache.resolveCacheDir(
733737
'',
734738
viteConfig.cacheDir,
735-
resolved.name,
739+
resolved.name.label,
736740
)
737741

738742
if (resolved.cache && resolved.cache.dir) {
@@ -747,7 +751,7 @@ export function resolveConfig(
747751
cacheDir = VitestCache.resolveCacheDir(
748752
resolved.root,
749753
resolved.cache.dir,
750-
resolved.name,
754+
resolved.name.label,
751755
)
752756
}
753757

@@ -918,7 +922,7 @@ function isPlaywrightChromiumOnly(vitest: Vitest, config: ResolvedConfig) {
918922
return false
919923
}
920924
for (const instance of browser.instances) {
921-
const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser)
925+
const name = instance.name || (config.name ? `${config.name.label} (${instance.browser})` : instance.browser)
922926
// browser config is filtered out
923927
if (!vitest.matchesProjectFilter(name)) {
924928
continue

packages/vitest/src/node/config/serializeConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export function serializeConfig(
4242
retry: config.retry,
4343
disableConsoleIntercept: config.disableConsoleIntercept,
4444
root: config.root,
45-
name: config.name,
45+
name: config.name.label,
4646
globals: config.globals,
4747
snapshotEnvironment: config.snapshotEnvironment,
4848
passWithNoTests: config.passWithNoTests,

packages/vitest/src/node/logger.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export class Logger {
164164
const config = project.config
165165
const printConfig = !project.isRootProject() && project.name
166166
if (printConfig) {
167-
this.console.error(`\n${formatProjectName(project.name)}\n`)
167+
this.console.error(`\n${formatProjectName(project)}\n`)
168168
}
169169
if (config.include) {
170170
this.console.error(
@@ -243,7 +243,7 @@ export class Logger {
243243

244244
const output = project.isRootProject()
245245
? ''
246-
: formatProjectName(project.name)
246+
: formatProjectName(project)
247247
const provider = project.browser.provider.name
248248
const providerString = provider === 'preview' ? '' : ` by ${c.reset(c.bold(provider))}`
249249
this.log(

packages/vitest/src/node/plugins/utils.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ export function resolveOptimizerConfig(
5959
(n: string) => !exclude.includes(n),
6060
)
6161

62-
newConfig.cacheDir = (testConfig.cache !== false && testConfig.cache?.dir) || VitestCache.resolveCacheDir(root, viteCacheDir, testConfig.name)
62+
const projectName = typeof testConfig.name === 'string' ? testConfig.name : testConfig.name?.label
63+
64+
newConfig.cacheDir = (testConfig.cache !== false && testConfig.cache?.dir) || VitestCache.resolveCacheDir(root, viteCacheDir, projectName)
6365
newConfig.optimizeDeps = {
6466
...viteOptions,
6567
...testOptions,

packages/vitest/src/node/plugins/workspace.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ export function WorkspaceVitestPlugin(
4343
const testConfig = viteConfig.test || {}
4444

4545
const root = testConfig.root || viteConfig.root || options.root
46-
let name = testConfig.name
46+
47+
let { label: name, color } = typeof testConfig.name === 'string'
48+
? { label: testConfig.name }
49+
: { label: '', ...testConfig.name }
50+
4751
if (!name) {
4852
if (typeof options.workspacePath === 'string') {
4953
// if there is a package.json, read the name from it
@@ -136,7 +140,7 @@ export function WorkspaceVitestPlugin(
136140
},
137141
},
138142
test: {
139-
name,
143+
name: { label: name, color },
140144
},
141145
};
142146

packages/vitest/src/node/project.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type { WorkspaceSpec as DeprecatedWorkspaceSpec } from './pool'
1414
import type { Reporter } from './reporters'
1515
import type { ParentProjectBrowser, ProjectBrowser } from './types/browser'
1616
import type {
17+
ProjectName,
1718
ResolvedConfig,
1819
SerializedConfig,
1920
TestProjectInlineConfiguration,
@@ -191,8 +192,15 @@ export class TestProject {
191192
/**
192193
* The name of the project or an empty string if not set.
193194
*/
194-
public get name(): string {
195-
return this.config.name || ''
195+
public get name(): ProjectName['label'] {
196+
return this.config.name.label || ''
197+
}
198+
199+
/**
200+
* The color used when reporting tasks of this project.
201+
*/
202+
public get color(): ProjectName['color'] {
203+
return this.config.name.color
196204
}
197205

198206
/**
@@ -585,7 +593,7 @@ export class TestProject {
585593

586594
/** @deprecated use `name` instead */
587595
public getName(): string {
588-
return this.config.name || ''
596+
return this.config.name.label || ''
589597
}
590598

591599
/** @deprecated internal */
@@ -684,7 +692,7 @@ export class TestProject {
684692
/** @internal */
685693
static _createBasicProject(vitest: Vitest): TestProject {
686694
const project = new TestProject(
687-
vitest.config.name || vitest.config.root,
695+
vitest.config.name.label || vitest.config.root,
688696
vitest,
689697
)
690698
project.vitenode = vitest.vitenode

packages/vitest/src/node/reporters/base.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export abstract class BaseReporter implements Reporter {
235235
}
236236

237237
if (testModule.project.name) {
238-
title += ` ${formatProjectName(testModule.project.name, '')}`
238+
title += ` ${formatProjectName(testModule.project, '')}`
239239
}
240240

241241
return ` ${title} ${testModule.task.name} ${suffix}`
@@ -552,7 +552,9 @@ export abstract class BaseReporter implements Reporter {
552552
}
553553

554554
const groupName = getFullName(group, c.dim(' > '))
555-
this.log(` ${formatProjectName(bench.file.projectName)}${bench.name}${c.dim(` - ${groupName}`)}`)
555+
const project = this.ctx.projects.find(p => p.name === bench.file.projectName)
556+
557+
this.log(` ${formatProjectName(project)}${bench.name}${c.dim(` - ${groupName}`)}`)
556558

557559
const siblings = group.tasks
558560
.filter(i => i.meta.benchmark && i.result?.benchmark && i !== bench)
@@ -601,6 +603,7 @@ export abstract class BaseReporter implements Reporter {
601603
for (const task of tasks) {
602604
const filepath = (task as File)?.filepath || ''
603605
const projectName = (task as File)?.projectName || task.file?.projectName || ''
606+
const project = this.ctx.projects.find(p => p.name === projectName)
604607

605608
let name = getFullName(task, c.dim(' > '))
606609

@@ -609,7 +612,7 @@ export abstract class BaseReporter implements Reporter {
609612
}
610613

611614
this.ctx.logger.error(
612-
`${c.bgRed(c.bold(' FAIL '))} ${formatProjectName(projectName)}${name}`,
615+
`${c.bgRed(c.bold(' FAIL '))} ${formatProjectName(project)}${name}`,
613616
)
614617
}
615618

packages/vitest/src/node/reporters/benchmark/reporter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class BenchmarkReporter extends DefaultReporter {
6565
const duration = testTask.task.result?.duration || 0
6666

6767
if (benches.length > 0 && benches.every(t => t.result?.state !== 'run' && t.result?.state !== 'queued')) {
68-
let title = `\n ${getStateSymbol(testTask.task)} ${formatProjectName(testTask.project.name)}${getFullName(testTask.task, c.dim(' > '))}`
68+
let title = `\n ${getStateSymbol(testTask.task)} ${formatProjectName(testTask.project)}${getFullName(testTask.task, c.dim(' > '))}`
6969

7070
if (duration != null && duration > this.ctx.config.slowTestThreshold) {
7171
title += c.yellow(` ${Math.round(duration)}${c.dim('ms')}`)

packages/vitest/src/node/reporters/renderers/utils.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Task } from '@vitest/runner'
22
import type { SnapshotSummary } from '@vitest/snapshot'
33
import type { Formatter } from 'tinyrainbow'
4+
import type { TestProject } from '../../project'
45
import { stripVTControlCharacters } from 'node:util'
56
import { slash } from '@vitest/utils'
67
import { basename, dirname, isAbsolute, relative } from 'pathe'
@@ -23,6 +24,8 @@ export const taskFail: string = c.red(F_CROSS)
2324
export const suiteFail: string = c.red(F_POINTER)
2425
export const pending: string = c.gray('·')
2526

27+
const labelDefaultColors = [c.bgYellow, c.bgCyan, c.bgGreen, c.bgMagenta] as const
28+
2629
function getCols(delta = 0) {
2730
let length = process.stdout?.columns
2831
if (!length || Number.isNaN(length)) {
@@ -223,20 +226,25 @@ export function formatTime(time: number): string {
223226
return `${Math.round(time)}ms`
224227
}
225228

226-
export function formatProjectName(name: string | undefined, suffix = ' '): string {
227-
if (!name) {
229+
export function formatProjectName(project?: Pick<TestProject, 'name' | 'color'>, suffix = ' '): string {
230+
if (!project?.name) {
228231
return ''
229232
}
230233
if (!c.isColorSupported) {
231-
return `|${name}|${suffix}`
234+
return `|${project.name}|${suffix}`
232235
}
233-
const index = name
234-
.split('')
235-
.reduce((acc, v, idx) => acc + v.charCodeAt(0) + idx, 0)
236236

237-
const colors = [c.bgYellow, c.bgCyan, c.bgGreen, c.bgMagenta]
237+
let background = project.color && c[`bg${capitalize(project.color)}`]
238+
239+
if (!background) {
240+
const index = project.name
241+
.split('')
242+
.reduce((acc, v, idx) => acc + v.charCodeAt(0) + idx, 0)
243+
244+
background = labelDefaultColors[index % labelDefaultColors.length]
245+
}
238246

239-
return c.black(colors[index % colors.length](` ${name} `)) + suffix
247+
return c.black(background(` ${project.name} `)) + suffix
240248
}
241249

242250
export function withLabel(color: 'red' | 'green' | 'blue' | 'cyan' | 'yellow', label: string, message?: string) {
@@ -257,3 +265,7 @@ export function truncateString(text: string, maxLength: number): string {
257265

258266
return `${plainText.slice(0, maxLength - 1)}…`
259267
}
268+
269+
function capitalize<T extends string>(text: T) {
270+
return `${text[0].toUpperCase()}${text.slice(1)}` as Capitalize<T>
271+
}

packages/vitest/src/node/reporters/summary.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ interface SlowTask {
3434
interface RunningModule extends Pick<Counter, 'total' | 'completed'> {
3535
filename: TestModule['task']['name']
3636
projectName: TestModule['project']['name']
37+
projectColor: TestModule['project']['color']
3738
hook?: Omit<SlowTask, 'hook'>
3839
tests: Map<TestCase['id'], SlowTask>
3940
typecheck: boolean
@@ -278,7 +279,7 @@ export class SummaryReporter implements Reporter {
278279
const typecheck = testFile.typecheck ? `${c.bgBlue(c.bold(' TS '))} ` : ''
279280
summary.push(
280281
c.bold(c.yellow(` ${F_POINTER} `))
281-
+ formatProjectName(testFile.projectName)
282+
+ formatProjectName({ name: testFile.projectName, color: testFile.projectColor })
282283
+ typecheck
283284
+ testFile.filename
284285
+ c.dim(!testFile.completed && !testFile.total
@@ -382,6 +383,7 @@ function initializeStats(module: TestModule): RunningModule {
382383
completed: 0,
383384
filename: module.task.name,
384385
projectName: module.project.name,
386+
projectColor: module.project.color,
385387
tests: new Map(),
386388
typecheck: !!module.task.meta.typecheck,
387389
}

packages/vitest/src/node/reporters/verbose.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class VerboseReporter extends DefaultReporter {
3838
let title = ` ${getStateSymbol(test.task)} `
3939

4040
if (test.project.name) {
41-
title += formatProjectName(test.project.name)
41+
title += formatProjectName(test.project)
4242
}
4343

4444
title += getFullName(test.task, c.dim(' > '))

packages/vitest/src/node/spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export class TestSpecification {
5050
this[0] = project
5151
this[1] = moduleId
5252
this[2] = { pool }
53-
const name = project.config.name
53+
const name = project.config.name?.label
5454
const hashName = pool !== 'typescript'
5555
? name
5656
: name
@@ -81,7 +81,7 @@ export class TestSpecification {
8181
toJSON(): SerializedTestSpecification {
8282
return [
8383
{
84-
name: this.project.config.name,
84+
name: this.project.config.name.label,
8585
root: this.project.config.root,
8686
},
8787
this.moduleId,

packages/vitest/src/node/state.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export class StateManager {
139139
const fileTask = createFileTask(
140140
path,
141141
project.config.root,
142-
project.config.name,
142+
project.config.name.label,
143143
)
144144
fileTask.local = true
145145
TestModule.register(fileTask, project)
@@ -149,7 +149,7 @@ export class StateManager {
149149
return
150150
}
151151
const filtered = files.filter(
152-
file => file.projectName !== project.config.name,
152+
file => file.projectName !== project.config.name.label,
153153
)
154154
// always keep a File task, so we can associate logs with it
155155
if (!filtered.length) {
@@ -222,7 +222,7 @@ export class StateManager {
222222
this.collectFiles(
223223
project,
224224
files.map(filepath =>
225-
createFileTask(filepath, project.config.root, project.config.name),
225+
createFileTask(filepath, project.config.root, project.config.name.label),
226226
),
227227
)
228228
}

0 commit comments

Comments
 (0)