Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add color to displayName in project configuration. #8025

Merged
merged 32 commits into from Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e3bf4a3
WIP
natealcedo Feb 24, 2019
eefc4ff
Update jest-types to have displayNameColor
natealcedo Feb 28, 2019
e0f09e2
Update default value to white
natealcedo Feb 28, 2019
ec8b7c9
Add displayNameColor to Initial Options
natealcedo Feb 28, 2019
7bb02fc
Merge remote-tracking branch 'origin/master' into feature/support-dis…
natealcedo Mar 23, 2019
a810c31
Delete Config.js
natealcedo Mar 23, 2019
789cb8b
Remove displayNameColor
natealcedo Mar 23, 2019
0903cd5
Eslint fix
natealcedo Mar 23, 2019
e369ca5
Update implementation of displayName
natealcedo Mar 23, 2019
01d8d97
Update DisplayName type
natealcedo Mar 23, 2019
94caad6
NormalizedisplayName
natealcedo Mar 23, 2019
dc7b046
Add validation for when displayName is an object
natealcedo Mar 23, 2019
f75bb90
Add test cases for normalizing of displayName when the value is an ob…
natealcedo Mar 23, 2019
2a56599
Remove validation logic from utils
natealcedo Mar 23, 2019
d42b2a3
Add all colors
natealcedo Mar 24, 2019
81fc522
Use jest-get-type
natealcedo Mar 24, 2019
65aa738
Add tests to displayName
natealcedo Mar 25, 2019
041a81d
Update ProjectConfig
natealcedo Mar 25, 2019
01fd4aa
Run lint fix
natealcedo Mar 25, 2019
44429c8
Revert typing error
natealcedo Mar 25, 2019
ec0d0d0
Merge branch 'master' into feature/support-displayNameColor
natealcedo Mar 26, 2019
68a6ae4
Remove test scenario which will never happen
natealcedo Mar 26, 2019
d1fe278
Merge remote-tracking branch 'origin/master' into feature/support-dis…
natealcedo Mar 26, 2019
87dc8cf
Update docs with new displayName behavior
natealcedo Mar 26, 2019
f1dbd72
Update versioned docs
natealcedo Mar 26, 2019
aada1fb
Update changelog
natealcedo Mar 26, 2019
bea007a
Update snapshot
natealcedo Mar 26, 2019
8928a2e
Lint fix
natealcedo Mar 26, 2019
c1e5a38
Lint md fix
natealcedo Mar 26, 2019
4462019
Respond to feedback
natealcedo Mar 26, 2019
21b99bb
Add new line
natealcedo Mar 26, 2019
3665d38
Update snapshot
natealcedo Mar 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -9,6 +9,7 @@
- `[jest-runner]` Support default exports for test environments ([#8163](https://github.com/facebook/jest/pull/8163))
- `[pretty-format]` Support React.Suspense ([#8180](https://github.com/facebook/jest/pull/8180))
- `[jest-snapshot]` Indent inline snapshots ([#8198](https://github.com/facebook/jest/pull/8198))
- `[jest-config]` Support colors in `displayName` configuration ([#8025](https://github.com/facebook/jest/pull/8025))

### Fixes

Expand Down
25 changes: 25 additions & 0 deletions docs/Configuration.md
Expand Up @@ -288,6 +288,31 @@ The `extract` function should return an iterable (`Array`, `Set`, etc.) with the

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.

### `displayName` [string, object]

default: `undefined`

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.

```js
module.exports = {
displayName: 'CLIENT',
};
```

or

```js
module.exports = {
displayName: {
name: 'CLIENT',
color: 'blue',
},
};
```

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.

### `errorOnDeprecated` [boolean]

Default: `false`
Expand Down
6 changes: 5 additions & 1 deletion packages/jest-config/src/ValidConfig.ts
Expand Up @@ -39,7 +39,11 @@ const initialOptions: Config.InitialOptions = {
},
},
dependencyExtractor: '<rootDir>/dependencyExtractor.js',
displayName: 'project-name',
// @ts-ignore TODO: type this properly
displayName: multipleValidOptions('test-config', {
color: 'blue',
name: 'test-config',
}),
errorOnDeprecated: false,
expand: false,
extraGlobals: [],
Expand Down
Expand Up @@ -17,6 +17,66 @@ exports[`Upgrade help logs a warning when \`scriptPreprocessor\` and/or \`prepro
<yellow></>"
`;

exports[`displayName should throw an error when displayName is is an empty object 1`] = `
"<red><bold><bold>● <bold>Validation Error</>:</>
<red></>
<red> Option \\"<bold>displayName</>\\" must be of type</>
<red> {</>
<red> name: string;</>
<red> color: string;</>
<red> }</>
<red></>
<red></>
<red> <bold>Configuration Documentation:</></>
<red> https://jestjs.io/docs/configuration.html</>
<red></>"
`;

exports[`displayName should throw an error when displayName is missing color 1`] = `
"<red><bold><bold>● <bold>Validation Error</>:</>
<red></>
<red> Option \\"<bold>displayName</>\\" must be of type</>
<red> {</>
<red> name: string;</>
<red> color: string;</>
<red> }</>
<red></>
<red></>
<red> <bold>Configuration Documentation:</></>
<red> https://jestjs.io/docs/configuration.html</>
<red></>"
`;

exports[`displayName should throw an error when displayName is missing name 1`] = `
"<red><bold><bold>● <bold>Validation Error</>:</>
<red></>
<red> Option \\"<bold>displayName</>\\" must be of type</>
<red> {</>
<red> name: string;</>
<red> color: string;</>
<red> }</>
<red></>
<red></>
<red> <bold>Configuration Documentation:</></>
<red> https://jestjs.io/docs/configuration.html</>
<red></>"
`;

exports[`displayName should throw an error when displayName is using invalid values 1`] = `
"<red><bold><bold>● <bold>Validation Error</>:</>
<red></>
<red> Option \\"<bold>displayName</>\\" must be of type</>
<red> {</>
<red> name: string;</>
<red> color: string;</>
<red> }</>
<red></>
<red></>
<red> <bold>Configuration Documentation:</></>
<red> https://jestjs.io/docs/configuration.html</>
<red></>"
`;

exports[`preset throws when module was found but no "jest-preset.js" or "jest-preset.json" files 1`] = `
"<red><bold><bold>● <bold>Validation Error</>:</>
<red></>
Expand Down
23 changes: 23 additions & 0 deletions packages/jest-config/src/__tests__/normalize.test.js
Expand Up @@ -1539,3 +1539,26 @@ describe('Defaults', () => {
expect(console.warn).not.toHaveBeenCalled();
});
});

describe('displayName', () => {
test.each`
displayName | description
${{}} | ${'is an empty object'}
${{name: 'hello'}} | ${'missing color'}
${{color: 'green'}} | ${'missing name'}
${{color: 2, name: []}} | ${'using invalid values'}
`(
'should throw an error when displayName is $description',
({displayName}) => {
expect(() => {
normalize(
{
rootDir: '/root/',
displayName,
},
{},
);
}).toThrowErrorMatchingSnapshot();
},
);
});
46 changes: 45 additions & 1 deletion packages/jest-config/src/normalize.ts
Expand Up @@ -16,6 +16,7 @@ import micromatch from 'micromatch';
import {sync as realpath} from 'realpath-native';
import Resolver from 'jest-resolve';
import {replacePathSepForRegex} from 'jest-regex-util';
import getType from 'jest-get-type';
import validatePattern from './validatePattern';
import getMaxWorkers from './getMaxWorkers';
import {
Expand Down Expand Up @@ -738,6 +739,50 @@ export default function normalize(
}
break;
}
case 'displayName': {
const displayName = oldOptions[key] as Config.DisplayName;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to cast this. Typescript was complaining alot

if (typeof displayName === 'string') {
value = displayName;
break;
}
/**
* Ensuring that displayName shape is correct here so that the
* reporters can trust the shape of the data
* TODO: Normalize "displayName" such that given a config option
* {
* "displayName": "Test"
* }
* becomes
* {
* displayName: {
* name: "Test",
* color: "white"
* }
* }
*
* This can't be done now since this will be a breaking change
* for custom reporters
*/
if (getType(displayName) === 'object') {
const errorMessage =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opting to do a custom error here. Didn't want to overcomplicate it. Open for suggestions here

` Option "${chalk.bold('displayName')}" must be of type\n` +
' {\n' +
' name: string;\n' +
' color: string;\n' +
' }\n';
const {name, color} = displayName;
if (
!name ||
!color ||
typeof name !== 'string' ||
typeof color !== 'string'
) {
throw createConfigError(errorMessage);
}
}
value = oldOptions[key];
break;
}
case 'automock':
case 'browser':
case 'cache':
Expand All @@ -749,7 +794,6 @@ export default function normalize(
case 'coverageThreshold':
case 'detectLeaks':
case 'detectOpenHandles':
case 'displayName':
case 'errorOnDeprecated':
case 'expand':
case 'extraGlobals':
Expand Down
@@ -1,5 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`printDisplayName should correctly print the displayName when color and name are valid values 1`] = `"</><inverse><green> hello </></></>"`;

exports[`printDisplayName should default displayName color to white when color is not a valid value 1`] = `"</><inverse><white> hello </></></>"`;

exports[`printDisplayName should default displayName color to white when displayName is a string 1`] = `"</><inverse><white> hello </></></>"`;

exports[`trimAndFormatPath() does not trim anything 1`] = `"<dim>1234567890/1234567890/</><bold>1234.js</>"`;

exports[`trimAndFormatPath() split at the path.sep index 1`] = `"<dim>.../</><bold>1234.js</>"`;
Expand Down
34 changes: 33 additions & 1 deletion packages/jest-reporters/src/__tests__/utils.test.js
Expand Up @@ -8,7 +8,7 @@
import path from 'path';
import chalk from 'chalk';
import stripAnsi from 'strip-ansi';
import {trimAndFormatPath, wrapAnsiString} from '../utils';
import {trimAndFormatPath, wrapAnsiString, printDisplayName} from '../utils';

describe('wrapAnsiString()', () => {
it('wraps a long string containing ansi chars', () => {
Expand Down Expand Up @@ -111,3 +111,35 @@ describe('trimAndFormatPath()', () => {
expect(stripAnsi(result).length).toBe(columns - pad);
});
});

describe('printDisplayName', () => {
it('should default displayName color to white when displayName is a string', () => {
const config = {
displayName: 'hello',
};

expect(printDisplayName(config)).toMatchSnapshot();
});

it('should default displayName color to white when color is not a valid value', () => {
const config = {
displayName: {
color: 'rubbish',
name: 'hello',
},
};

expect(printDisplayName(config)).toMatchSnapshot();
});

it('should correctly print the displayName when color and name are valid values', () => {
const config = {
displayName: {
color: 'green',
name: 'hello',
},
};

expect(printDisplayName(config)).toMatchSnapshot();
});
});
16 changes: 11 additions & 5 deletions packages/jest-reporters/src/utils.ts
Expand Up @@ -17,14 +17,20 @@ const PROGRESS_BAR_WIDTH = 40;

export const printDisplayName = (config: Config.ProjectConfig) => {
const {displayName} = config;
const white = chalk.reset.inverse.white;
if (!displayName) {
return '';
}

if (displayName) {
return chalk.supportsColor
? chalk.reset.inverse.white(` ${displayName} `)
: displayName;
if (typeof displayName === 'string') {
return chalk.supportsColor ? white(` ${displayName} `) : displayName;
}

return '';
const {name, color} = displayName;
const chosenColor = chalk.reset.inverse[color]
? chalk.reset.inverse[color]
: white;
return chalk.supportsColor ? chosenColor(` ${name} `) : name;
};

export const trimAndFormatPath = (
Expand Down
3 changes: 2 additions & 1 deletion packages/jest-test-result/src/types.ts
Expand Up @@ -8,6 +8,7 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import {CoverageMap, CoverageMapData} from 'istanbul-lib-coverage';
import {ConsoleBuffer} from '@jest/console';
import {Config} from '@jest/types';

export type SerializableError = {
code?: unknown;
Expand Down Expand Up @@ -102,7 +103,7 @@ export type Suite = {
export type TestResult = {
console?: ConsoleBuffer | null;
coverage?: CoverageMapData;
displayName?: string | null;
displayName?: Config.DisplayName;
failureMessage?: string | null;
leaks: boolean;
memoryUsage?: Bytes;
Expand Down
52 changes: 50 additions & 2 deletions packages/jest-types/src/Config.ts
Expand Up @@ -104,6 +104,13 @@ export type DefaultOptions = {
watchman: boolean;
};

export type DisplayName =
| string
| {
name: string;
color: DisplayNameColor;
};

export type InitialOptions = {
automock?: boolean;
bail?: boolean | number;
Expand All @@ -129,7 +136,7 @@ export type InitialOptions = {
dependencyExtractor?: string;
detectLeaks?: boolean;
detectOpenHandles?: boolean;
displayName?: string;
displayName?: DisplayName;
expand?: boolean;
extraGlobals?: Array<string>;
filter?: Path;
Expand Down Expand Up @@ -223,6 +230,47 @@ type NotifyMode =
| 'success-change'
| 'failure-change';

/**
* Hard coding this until
* https://github.com/chalk/chalk/pull/336
* gets merged
*/
type DisplayNameColor =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to extract these from chalk instead of hard coding them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I was hard coding this because of what I mentioned about not being sure if we should curate the colors that we should allow or if we should allow everything. Hence the early PR 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've taken a look at the types provided by chalk and they don't expose the colors. https://github.com/chalk/chalk/blob/master/index.d.ts#L231

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as an FYI, opened up this PR. Hopefully this gets merged and we won't have to hardcode colors here. chalk/chalk#336

| 'black'
| 'red'
| 'green'
| 'yellow'
| 'blue'
| 'magenta'
| 'cyan'
| 'white'
| 'gray'
| 'grey'
| 'blackBright'
| 'redBright'
| 'greenBright'
| 'yellowBright'
| 'blueBright'
| 'magentaBright'
| 'cyanBright'
| 'whiteBright'
| 'bgBlack'
| 'bgRed'
| 'bgGreen'
| 'bgYellow'
| 'bgBlue'
| 'bgMagenta'
| 'bgCyan'
| 'bgWhite'
| 'bgBlackBright'
| 'bgRedBright'
| 'bgGreenBright'
| 'bgYellowBright'
| 'bgBlueBright'
| 'bgMagentaBright'
| 'bgCyanBright'
| 'bgWhiteBright';

type CoverageThreshold = {
[path: string]: {
[key: string]: number;
Expand Down Expand Up @@ -318,7 +366,7 @@ export type ProjectConfig = {
dependencyExtractor?: string;
detectLeaks: boolean;
detectOpenHandles: boolean;
displayName: string | null | undefined;
displayName?: DisplayName;
errorOnDeprecated: boolean;
extraGlobals: Array<keyof NodeJS.Global>;
filter: Path | null | undefined;
Expand Down