Skip to content

Commit 461d9fe

Browse files
committed
feat: support custom colors for test.name
1 parent b194263 commit 461d9fe

File tree

24 files changed

+124
-45
lines changed

24 files changed

+124
-45
lines changed

packages/ui/client/components/explorer/ExplorerItem.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,13 @@ const projectNameTextColor = computed(() => {
158158
case 'blue':
159159
case 'green':
160160
case 'magenta':
161+
case 'black':
162+
case 'red':
161163
return 'white'
164+
165+
case 'yellow':
166+
case 'cyan':
167+
case 'white':
162168
default:
163169
return 'black'
164170
}

packages/ui/client/composables/client/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ watch(
161161
client.rpc.getFiles(),
162162
client.rpc.getConfig(),
163163
client.rpc.getUnhandledErrors(),
164-
client.rpc.getResolvedProjectNames(),
164+
client.rpc.getResolvedProjectLabels(),
165165
])
166166
if (_config.standalone) {
167167
const filenames = await client.rpc.getTestFiles()

packages/ui/client/composables/client/static.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ export function createStaticClient(): VitestClient {
5151
getResolvedProjectNames: () => {
5252
return metadata.projects
5353
},
54+
getResolvedProjectLabels: () => {
55+
return []
56+
},
5457
getModuleGraph: async (projectName, id) => {
5558
return metadata.moduleGraph[projectName]?.[id]
5659
},

packages/ui/client/composables/explorer/tree.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export class ExplorerTree {
1919
private resumeEndRunId: ReturnType<typeof setTimeout> | undefined
2020
constructor(
2121
public projects: string[] = [],
22+
public colors = new Map<string, string | undefined>(),
2223
private onTaskUpdateCalled: boolean = false,
2324
private resumeEndTimeout = 500,
2425
public root = <RootTreeNode>{
@@ -54,8 +55,10 @@ export class ExplorerTree {
5455
this.rafCollector = useRafFn(this.runCollect.bind(this), { fpsLimit: 10, immediate: false })
5556
}
5657

57-
loadFiles(remoteFiles: File[], projects: string[]) {
58-
this.projects.splice(0, this.projects.length, ...projects)
58+
loadFiles(remoteFiles: File[], projects: { name: string; color?: string }[]) {
59+
this.projects.splice(0, this.projects.length, ...projects.map(p => p.name))
60+
this.colors = new Map(projects.map(p => [p.name, p.color]))
61+
5962
runLoadFiles(
6063
remoteFiles,
6164
true,

packages/ui/client/composables/explorer/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export function createOrUpdateFileNode(
7171
duration: file.result?.duration != null ? Math.round(file.result?.duration) : undefined,
7272
filepath: file.filepath,
7373
projectName: file.projectName || '',
74-
projectNameColor: getProjectNameColor(file.projectName),
74+
projectNameColor: explorerTree.colors.get(file.projectName || '') || getProjectNameColor(file.projectName),
7575
collectDuration: file.collectDuration,
7676
setupDuration: file.setupDuration,
7777
environmentLoad: file.environmentLoad,

packages/vitest/src/api/setup.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { WebSocket } from 'ws'
66
import type { Vitest } from '../node/core'
77
import type { Reporter } from '../node/types/reporter'
88
import type { SerializedTestSpecification } from '../runtime/types/utils'
9-
import type { Awaitable, ModuleGraphData, UserConsoleLog } from '../types/general'
9+
import type { Awaitable, LabelColor, ModuleGraphData, UserConsoleLog } from '../types/general'
1010
import type {
1111
TransformResultWithSource,
1212
WebSocketEvents,
@@ -90,6 +90,9 @@ export function setup(ctx: Vitest, _server?: ViteDevServer): void {
9090
getResolvedProjectNames(): string[] {
9191
return ctx.projects.map(p => p.name)
9292
},
93+
getResolvedProjectLabels(): { name: string; color?: LabelColor }[] {
94+
return ctx.projects.map(p => ({ name: p.name, color: p.color }))
95+
},
9396
async getTransformResult(projectName: string, id, browser = false) {
9497
const project = ctx.getProjectByName(projectName)
9598
const result: TransformResultWithSource | null | undefined = browser

packages/vitest/src/api/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { File, TaskEventPack, TaskResultPack } from '@vitest/runner'
22
import type { BirpcReturn } from 'birpc'
33
import type { SerializedConfig } from '../runtime/config'
44
import type { SerializedTestSpecification } from '../runtime/types/utils'
5-
import type { Awaitable, ModuleGraphData, UserConsoleLog } from '../types/general'
5+
import type { Awaitable, LabelColor, ModuleGraphData, UserConsoleLog } from '../types/general'
66

77
interface SourceMap {
88
file: string
@@ -32,7 +32,10 @@ export interface WebSocketHandlers {
3232
getTestFiles: () => Promise<SerializedTestSpecification[]>
3333
getPaths: () => string[]
3434
getConfig: () => SerializedConfig
35+
// TODO: Remove in v4
36+
/** @deprecated -- Use `getResolvedProjectLabels` instead */
3537
getResolvedProjectNames: () => string[]
38+
getResolvedProjectLabels: () => { name: string; color?: LabelColor }[]
3639
getModuleGraph: (
3740
projectName: string,
3841
id: string,

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

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

148+
resolved.name = typeof options.name === 'string'
149+
? options.name
150+
: (options.name?.label || '')
151+
152+
resolved.color = typeof options.name !== 'string' ? options.name?.color : undefined
153+
148154
const inspector = resolved.inspect || resolved.inspectBrk
149155

150156
resolved.inspector = {

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: 8 additions & 0 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,
@@ -195,6 +196,13 @@ export class TestProject {
195196
return this.config.name || ''
196197
}
197198

199+
/**
200+
* The color used when reporting tasks of this project.
201+
*/
202+
public get color(): ProjectName['color'] {
203+
return this.config.color
204+
}
205+
198206
/**
199207
* Serialized project configuration. This is the config that tests receive.
200208
*/

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/types/browser.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ type UnsupportedProperties =
7171
| 'environmentOptions'
7272
| 'server'
7373
| 'benchmark'
74+
| 'name'
7475

7576
export interface BrowserInstanceOption extends BrowserProviderOptions,
7677
Omit<ProjectConfig, UnsupportedProperties>,
@@ -87,6 +88,8 @@ export interface BrowserInstanceOption extends BrowserProviderOptions,
8788
* Name of the browser
8889
*/
8990
browser: string
91+
92+
name?: string
9093
}
9194

9295
export interface BrowserConfigOptions {

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { ViteNodeServerOptions } from 'vite-node'
88
import type { ChaiConfig } from '../../integrations/chai/config'
99
import type { SerializedConfig } from '../../runtime/config'
1010
import type { EnvironmentOptions } from '../../types/environment'
11-
import type { Arrayable, ErrorWithDiff, ParsedStack, ProvidedContext } from '../../types/general'
11+
import type { Arrayable, ErrorWithDiff, LabelColor, ParsedStack, ProvidedContext } from '../../types/general'
1212
import type { HappyDOMOptions } from '../../types/happy-dom-options'
1313
import type { JSDOMOptions } from '../../types/jsdom-options'
1414
import type {
@@ -50,6 +50,11 @@ export type { EnvironmentOptions, HappyDOMOptions, JSDOMOptions }
5050

5151
export type VitestRunMode = 'test' | 'benchmark'
5252

53+
export interface ProjectName {
54+
label: string
55+
color?: LabelColor
56+
}
57+
5358
interface SequenceOptions {
5459
/**
5560
* Class that handles sorting and sharding algorithm.
@@ -238,7 +243,7 @@ export interface InlineConfig {
238243
/**
239244
* Name of the project. Will be used to display in the reporter.
240245
*/
241-
name?: string
246+
name?: string | ProjectName
242247

243248
/**
244249
* Benchmark options.
@@ -990,9 +995,12 @@ export interface ResolvedConfig
990995
| 'setupFiles'
991996
| 'snapshotEnvironment'
992997
| 'bail'
998+
| 'name'
993999
> {
9941000
mode: VitestRunMode
9951001

1002+
name: ProjectName['label']
1003+
color?: ProjectName['color']
9961004
base?: string
9971005
diff?: string | SerializedDiffOptions
9981006
bail?: number

packages/vitest/src/public/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export type WorkerRPC = WorkerRPC_
182182
export type {
183183
AfterSuiteRunMeta,
184184
ErrorWithDiff,
185+
LabelColor,
185186
ModuleCache,
186187
ModuleGraphData,
187188
ParsedStack,

0 commit comments

Comments
 (0)