Skip to content

Commit bd34500

Browse files
Alcedo Nathaniel De Guzman JrSimenB
authored andcommitted
Add color to displayName in project configuration. (#8025)
1 parent 9705b3d commit bd34500

File tree

15 files changed

+289
-11
lines changed

15 files changed

+289
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- `[jest-runner]` Support default exports for test environments ([#8163](https://github.com/facebook/jest/pull/8163))
1010
- `[pretty-format]` Support React.Suspense ([#8180](https://github.com/facebook/jest/pull/8180))
1111
- `[jest-snapshot]` Indent inline snapshots ([#8198](https://github.com/facebook/jest/pull/8198))
12+
- `[jest-config]` Support colors in `displayName` configuration ([#8025](https://github.com/facebook/jest/pull/8025))
1213

1314
### Fixes
1415

docs/Configuration.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,31 @@ The `extract` function should return an iterable (`Array`, `Set`, etc.) with the
288288

289289
That module can also contain a `getCacheKey` function to generate a cache key to determine if the logic has changed and any cached artifacts relying on it should be discarded.
290290

291+
### `displayName` [string, object]
292+
293+
default: `undefined`
294+
295+
Allows for a label to be printed along side a test while it is running. This becomes more useful in multiproject repositories where there can be many jest configuration files. This visually tells which project a test belongs to. Here are sample valid values.
296+
297+
```js
298+
module.exports = {
299+
displayName: 'CLIENT',
300+
};
301+
```
302+
303+
or
304+
305+
```js
306+
module.exports = {
307+
displayName: {
308+
name: 'CLIENT',
309+
color: 'blue',
310+
},
311+
};
312+
```
313+
314+
As a secondary option, an object with the properties `name` and `color` can be passed. This allows for a custom configuration of the background color of the displayName. `displayName` defaults to white when its value is a string. Jest uses [chalk](https://github.com/chalk/chalk) to provide the color. As such, all of the valid options for colors supported by chalk are also supported by jest.
315+
291316
### `errorOnDeprecated` [boolean]
292317

293318
Default: `false`

packages/jest-config/src/ValidConfig.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ const initialOptions: Config.InitialOptions = {
3939
},
4040
},
4141
dependencyExtractor: '<rootDir>/dependencyExtractor.js',
42-
displayName: 'project-name',
42+
// @ts-ignore TODO: type this properly
43+
displayName: multipleValidOptions('test-config', {
44+
color: 'blue',
45+
name: 'test-config',
46+
}),
4347
errorOnDeprecated: false,
4448
expand: false,
4549
extraGlobals: [],

packages/jest-config/src/__tests__/__snapshots__/normalize.test.js.snap

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,70 @@ exports[`Upgrade help logs a warning when \`scriptPreprocessor\` and/or \`prepro
1717
<yellow></>"
1818
`;
1919
20+
exports[`displayName should throw an error when displayName is is an empty object 1`] = `
21+
"<red><bold><bold>● <bold>Validation Error</>:</>
22+
<red></>
23+
<red> Option \\"<bold>displayName</>\\" must be of type:</>
24+
<red></>
25+
<red> {</>
26+
<red> name: string;</>
27+
<red> color: string;</>
28+
<red> }</>
29+
<red></>
30+
<red></>
31+
<red> <bold>Configuration Documentation:</></>
32+
<red> https://jestjs.io/docs/configuration.html</>
33+
<red></>"
34+
`;
35+
36+
exports[`displayName should throw an error when displayName is missing color 1`] = `
37+
"<red><bold><bold>● <bold>Validation Error</>:</>
38+
<red></>
39+
<red> Option \\"<bold>displayName</>\\" must be of type:</>
40+
<red></>
41+
<red> {</>
42+
<red> name: string;</>
43+
<red> color: string;</>
44+
<red> }</>
45+
<red></>
46+
<red></>
47+
<red> <bold>Configuration Documentation:</></>
48+
<red> https://jestjs.io/docs/configuration.html</>
49+
<red></>"
50+
`;
51+
52+
exports[`displayName should throw an error when displayName is missing name 1`] = `
53+
"<red><bold><bold>● <bold>Validation Error</>:</>
54+
<red></>
55+
<red> Option \\"<bold>displayName</>\\" must be of type:</>
56+
<red></>
57+
<red> {</>
58+
<red> name: string;</>
59+
<red> color: string;</>
60+
<red> }</>
61+
<red></>
62+
<red></>
63+
<red> <bold>Configuration Documentation:</></>
64+
<red> https://jestjs.io/docs/configuration.html</>
65+
<red></>"
66+
`;
67+
68+
exports[`displayName should throw an error when displayName is using invalid values 1`] = `
69+
"<red><bold><bold>● <bold>Validation Error</>:</>
70+
<red></>
71+
<red> Option \\"<bold>displayName</>\\" must be of type:</>
72+
<red></>
73+
<red> {</>
74+
<red> name: string;</>
75+
<red> color: string;</>
76+
<red> }</>
77+
<red></>
78+
<red></>
79+
<red> <bold>Configuration Documentation:</></>
80+
<red> https://jestjs.io/docs/configuration.html</>
81+
<red></>"
82+
`;
83+
2084
exports[`preset throws when module was found but no "jest-preset.js" or "jest-preset.json" files 1`] = `
2185
"<red><bold><bold>● <bold>Validation Error</>:</>
2286
<red></>

packages/jest-config/src/__tests__/normalize.test.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,3 +1539,26 @@ describe('Defaults', () => {
15391539
expect(console.warn).not.toHaveBeenCalled();
15401540
});
15411541
});
1542+
1543+
describe('displayName', () => {
1544+
test.each`
1545+
displayName | description
1546+
${{}} | ${'is an empty object'}
1547+
${{name: 'hello'}} | ${'missing color'}
1548+
${{color: 'green'}} | ${'missing name'}
1549+
${{color: 2, name: []}} | ${'using invalid values'}
1550+
`(
1551+
'should throw an error when displayName is $description',
1552+
({displayName}) => {
1553+
expect(() => {
1554+
normalize(
1555+
{
1556+
rootDir: '/root/',
1557+
displayName,
1558+
},
1559+
{},
1560+
);
1561+
}).toThrowErrorMatchingSnapshot();
1562+
},
1563+
);
1564+
});

packages/jest-config/src/normalize.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import micromatch from 'micromatch';
1616
import {sync as realpath} from 'realpath-native';
1717
import Resolver from 'jest-resolve';
1818
import {replacePathSepForRegex} from 'jest-regex-util';
19+
import getType from 'jest-get-type';
1920
import validatePattern from './validatePattern';
2021
import getMaxWorkers from './getMaxWorkers';
2122
import {
@@ -738,6 +739,50 @@ export default function normalize(
738739
}
739740
break;
740741
}
742+
case 'displayName': {
743+
const displayName = oldOptions[key] as Config.DisplayName;
744+
if (typeof displayName === 'string') {
745+
value = displayName;
746+
break;
747+
}
748+
/**
749+
* Ensuring that displayName shape is correct here so that the
750+
* reporters can trust the shape of the data
751+
* TODO: Normalize "displayName" such that given a config option
752+
* {
753+
* "displayName": "Test"
754+
* }
755+
* becomes
756+
* {
757+
* displayName: {
758+
* name: "Test",
759+
* color: "white"
760+
* }
761+
* }
762+
*
763+
* This can't be done now since this will be a breaking change
764+
* for custom reporters
765+
*/
766+
if (getType(displayName) === 'object') {
767+
const errorMessage =
768+
` Option "${chalk.bold('displayName')}" must be of type:\n\n` +
769+
' {\n' +
770+
' name: string;\n' +
771+
' color: string;\n' +
772+
' }\n';
773+
const {name, color} = displayName;
774+
if (
775+
!name ||
776+
!color ||
777+
typeof name !== 'string' ||
778+
typeof color !== 'string'
779+
) {
780+
throw createConfigError(errorMessage);
781+
}
782+
}
783+
value = oldOptions[key];
784+
break;
785+
}
741786
case 'automock':
742787
case 'browser':
743788
case 'cache':
@@ -749,7 +794,6 @@ export default function normalize(
749794
case 'coverageThreshold':
750795
case 'detectLeaks':
751796
case 'detectOpenHandles':
752-
case 'displayName':
753797
case 'errorOnDeprecated':
754798
case 'expand':
755799
case 'extraGlobals':

packages/jest-reporters/src/__tests__/__snapshots__/utils.test.js.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`printDisplayName should correctly print the displayName when color and name are valid values 1`] = `"</><inverse><green> hello </></></>"`;
4+
5+
exports[`printDisplayName should default displayName color to white when color is not a valid value 1`] = `"</><inverse><white> hello </></></>"`;
6+
7+
exports[`printDisplayName should default displayName color to white when displayName is a string 1`] = `"</><inverse><white> hello </></></>"`;
8+
39
exports[`trimAndFormatPath() does not trim anything 1`] = `"<dim>1234567890/1234567890/</><bold>1234.js</>"`;
410
511
exports[`trimAndFormatPath() split at the path.sep index 1`] = `"<dim>.../</><bold>1234.js</>"`;

packages/jest-reporters/src/__tests__/utils.test.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import path from 'path';
99
import chalk from 'chalk';
1010
import stripAnsi from 'strip-ansi';
11-
import {trimAndFormatPath, wrapAnsiString} from '../utils';
11+
import {trimAndFormatPath, wrapAnsiString, printDisplayName} from '../utils';
1212

1313
describe('wrapAnsiString()', () => {
1414
it('wraps a long string containing ansi chars', () => {
@@ -111,3 +111,35 @@ describe('trimAndFormatPath()', () => {
111111
expect(stripAnsi(result).length).toBe(columns - pad);
112112
});
113113
});
114+
115+
describe('printDisplayName', () => {
116+
it('should default displayName color to white when displayName is a string', () => {
117+
const config = {
118+
displayName: 'hello',
119+
};
120+
121+
expect(printDisplayName(config)).toMatchSnapshot();
122+
});
123+
124+
it('should default displayName color to white when color is not a valid value', () => {
125+
const config = {
126+
displayName: {
127+
color: 'rubbish',
128+
name: 'hello',
129+
},
130+
};
131+
132+
expect(printDisplayName(config)).toMatchSnapshot();
133+
});
134+
135+
it('should correctly print the displayName when color and name are valid values', () => {
136+
const config = {
137+
displayName: {
138+
color: 'green',
139+
name: 'hello',
140+
},
141+
};
142+
143+
expect(printDisplayName(config)).toMatchSnapshot();
144+
});
145+
});

packages/jest-reporters/src/utils.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,20 @@ const PROGRESS_BAR_WIDTH = 40;
1717

1818
export const printDisplayName = (config: Config.ProjectConfig) => {
1919
const {displayName} = config;
20+
const white = chalk.reset.inverse.white;
21+
if (!displayName) {
22+
return '';
23+
}
2024

21-
if (displayName) {
22-
return chalk.supportsColor
23-
? chalk.reset.inverse.white(` ${displayName} `)
24-
: displayName;
25+
if (typeof displayName === 'string') {
26+
return chalk.supportsColor ? white(` ${displayName} `) : displayName;
2527
}
2628

27-
return '';
29+
const {name, color} = displayName;
30+
const chosenColor = chalk.reset.inverse[color]
31+
? chalk.reset.inverse[color]
32+
: white;
33+
return chalk.supportsColor ? chosenColor(` ${name} `) : name;
2834
};
2935

3036
export const trimAndFormatPath = (

packages/jest-test-result/src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// eslint-disable-next-line import/no-extraneous-dependencies
99
import {CoverageMap, CoverageMapData} from 'istanbul-lib-coverage';
1010
import {ConsoleBuffer} from '@jest/console';
11+
import {Config} from '@jest/types';
1112

1213
export type SerializableError = {
1314
code?: unknown;
@@ -102,7 +103,7 @@ export type Suite = {
102103
export type TestResult = {
103104
console?: ConsoleBuffer | null;
104105
coverage?: CoverageMapData;
105-
displayName?: string | null;
106+
displayName?: Config.DisplayName;
106107
failureMessage?: string | null;
107108
leaks: boolean;
108109
memoryUsage?: Bytes;

0 commit comments

Comments
 (0)