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

[jest-validate] support recursive config check #6802

Merged
merged 10 commits into from
Aug 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- `[jest-runner]` print stack trace when `process.exit` is called from user code ([#6714](https://github.com/facebook/jest/pull/6714))
- `[jest-each]` introduces `%#` option to add index of the test to its title ([#6414](https://github.com/facebook/jest/pull/6414))
- `[pretty-format]` Support serializing `DocumentFragment` ([#6705](https://github.com/facebook/jest/pull/6705))
- `[jest-validate]` Add `recursive` and `recursiveBlacklist` options for deep config checks ([#6802](https://github.com/facebook/jest/pull/6802))

### Fixes

Expand Down
9 changes: 9 additions & 0 deletions packages/jest-config/src/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,15 @@ export default function normalize(options: InitialOptions, argv: Argv) {
comment: DOCUMENTATION_NOTE,
deprecatedConfig: DEPRECATED_CONFIG,
exampleConfig: VALID_CONFIG,
recursiveBlacklist: [
'collectCoverageOnlyFrom',
// 'coverageThreshold' allows to use 'global' and glob strings on the same
// level, there's currently no way we can deal with such config
'coverageThreshold',
'globals',
'moduleNameMapper',
'transform',
],
});

options = normalizePreprocessor(
Expand Down
25 changes: 20 additions & 5 deletions packages/jest-config/src/valid_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default ({
cache: true,
cacheDirectory: '/tmp/user/jest',
changedFilesWithAncestor: false,
changedSince: '',
changedSince: 'master',
clearMocks: false,
collectCoverage: true,
collectCoverageFrom: ['src', '!public'],
Expand All @@ -34,6 +34,9 @@ export default ({
coverageThreshold: {
global: {
branches: 50,
functions: 100,
lines: 100,
statements: 100,
},
},
displayName: 'project-name',
Expand All @@ -44,8 +47,11 @@ export default ({
forceExit: false,
globalSetup: 'setup.js',
globalTeardown: 'teardown.js',
globals: {},
globals: {__DEV__: true},
haste: {
defaultPlatform: 'ios',
hasteImplModulePath: '<rootDir>/haste_impl.js',
platforms: ['ios', 'android'],
providesModuleNodeModules: ['react', 'react-native'],
},
json: false,
Expand Down Expand Up @@ -87,7 +93,7 @@ export default ({
skipNodeResolution: false,
snapshotSerializers: ['my-serializer-module'],
testEnvironment: 'jest-environment-jsdom',
testEnvironmentOptions: {},
testEnvironmentOptions: {userAgent: 'Agent/007'},
Copy link
Contributor

Choose a reason for hiding this comment

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

License to kill? 🕵🏼‍♂️

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🔫

testFailureExitCode: 1,
testLocationInResults: false,
testMatch: ['**/__tests__/**/*.js?(x)', '**/?(*.)+(spec|test).js?(x)'],
Expand All @@ -107,7 +113,16 @@ export default ({
useStderr: false,
verbose: false,
watch: false,
watchPathIgnorePatterns: [],
watchPlugins: [],
watchPathIgnorePatterns: ['<rootDir>/e2e/'],
watchPlugins: [
'path/to/yourWatchPlugin',
[
'jest-watch-typeahead/filename',
{
key: 'k',
prompt: 'do something with my custom prompt',
},
],
],
watchman: true,
}: InitialOptions);
8 changes: 7 additions & 1 deletion packages/jest-validate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Where `ValidationOptions` are:

```js
type ValidationOptions = {
blacklist?: Array<string>,
comment?: string,
condition?: (option: any, validOption: any) => boolean,
deprecate?: (
Expand All @@ -34,6 +35,7 @@ type ValidationOptions = {
options: ValidationOptions,
) => void,
exampleConfig: Object,
recursive?: boolean,
title?: Title,
unknown?: (
config: Object,
Expand All @@ -60,11 +62,13 @@ Almost anything can be overwritten to suite your needs.

### Options

- `recursiveBlacklist` – optional array of string keyPaths that should be excluded from deep (recursive) validation.
- `comment` – optional string to be rendered below error/warning message.
- `condition` – an optional function with validation condition.
- `deprecate`, `error`, `unknown` – optional functions responsible for displaying warning and error messages.
- `deprecatedConfig` – optional object with deprecated config keys.
- `exampleConfig` – the only **required** option with configuration against which you'd like to test.
- `recursive` - optional boolean determining whether recursively compare `exampleConfig` to `config` (default: `true`).
- `title` – optional object of titles for errors and messages.

You will find examples of `condition`, `deprecate`, `error`, `unknown`, and `deprecatedConfig` inside source of this repository, named respectively.
Expand Down Expand Up @@ -116,7 +120,9 @@ This will output:

Example:
{
"transform": {"^.+\\.js$": "<rootDir>/preprocessor.js"}
"transform": {
"^.+\\.js$": "<rootDir>/preprocessor.js"
}
}

Documentation: http://custom-docs.com
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ exports[`pretty prints valid config for Array 1`] = `
<red></>
<red> Example:</>
<red> {</>
<red> <bold>\\"coverageReporters\\"</>: <bold>[\\"json\\", \\"text\\", \\"lcov\\", \\"clover\\"]</></>
<red> <bold>\\"coverageReporters\\"</>: <bold>[</></>
<red><bold> \\"json\\",</></>
<red><bold> \\"text\\",</></>
<red><bold> \\"lcov\\",</></>
<red><bold> \\"clover\\"</></>
<red><bold> ]</></>
<red> }</>
<red></>"
`;
Expand Down Expand Up @@ -77,7 +82,12 @@ exports[`pretty prints valid config for Object 1`] = `
<red></>
<red> Example:</>
<red> {</>
<red> <bold>\\"haste\\"</>: <bold>{\\"providesModuleNodeModules\\": [\\"react\\", \\"react-native\\"]}</></>
<red> <bold>\\"haste\\"</>: <bold>{</></>
<red><bold> \\"providesModuleNodeModules\\": [</></>
<red><bold> \\"react\\",</></>
<red><bold> \\"react-native\\"</></>
<red><bold> ]</></>
<red><bold> }</></>
<red> }</>
<red></>"
`;
Expand Down Expand Up @@ -122,7 +132,10 @@ exports[`works with custom errors 1`] = `
<red></>
<red> Example:</>
<red> {</>
<red> <bold>\\"test\\"</>: <bold>[1, 2]</></>
<red> <bold>\\"test\\"</>: <bold>[</></>
<red><bold> 1,</></>
<red><bold> 2</></>
<red><bold> ]</></>
<red> }</>
<red></>
<red>My custom comment</>"
Expand Down
76 changes: 61 additions & 15 deletions packages/jest-validate/src/__tests__/validate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const {
deprecatedConfig,
} = require('./fixtures/jest_config');

test('validates default Jest config', () => {
test('recursively validates default Jest config', () => {
expect(
validate(defaultConfig, {
exampleConfig: validConfig,
Expand All @@ -29,7 +29,7 @@ test('validates default Jest config', () => {
});
});

test('validates default jest-validate config', () => {
test('recursively validates default jest-validate config', () => {
expect(
validate(jestValidateDefaultConfig, {
exampleConfig: jestValidateExampleConfig,
Expand All @@ -40,19 +40,17 @@ test('validates default jest-validate config', () => {
});
});

[
[{automock: []}, 'Boolean'],
[{coverageReporters: {}}, 'Array'],
[{preset: 1337}, 'String'],
[{haste: 42}, 'Object'],
].forEach(([config, type]) => {
test(`pretty prints valid config for ${type}`, () => {
expect(() =>
validate(config, {
exampleConfig: validConfig,
}),
).toThrowErrorMatchingSnapshot();
});
test.each([
['Boolean', {automock: []}],
['Array', {coverageReporters: {}}],
['String', {preset: 1337}],
['Object', {haste: 42}],
])('pretty prints valid config for %s', (type, config) => {
expect(() =>
validate(config, {
exampleConfig: validConfig,
}),
).toThrowErrorMatchingSnapshot();
});

test(`pretty prints valid config for Function`, () => {
Expand All @@ -76,6 +74,54 @@ test('omits null and undefined config values', () => {
});
});

test('recursively omits null and undefined config values', () => {
const config = {
haste: {
providesModuleNodeModules: null,
},
};
expect(
validate(config, {exampleConfig: validConfig, recursive: true}),
).toEqual({
hasDeprecationWarnings: false,
isValid: true,
});
});

test('respects blacklist', () => {
const warn = console.warn;
console.warn = jest.fn();
const config = {
something: {
nested: {
some_random_key: 'value',
some_random_key2: 'value2',
},
},
};
const exampleConfig = {
something: {
nested: {
test: true,
},
},
};

validate(config, {exampleConfig});

expect(console.warn).toBeCalled();

console.warn.mockReset();

validate(config, {
exampleConfig,
recursiveBlacklist: ['something.nested'],
});

expect(console.warn).not.toBeCalled();
console.warn = warn;
});

test('displays warning for unknown config options', () => {
const config = {unkwon: {}};
const validConfig = {unknown: 'string'};
Expand Down
5 changes: 3 additions & 2 deletions packages/jest-validate/src/default_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import type {ValidationOptions} from './types';
import {deprecationWarning} from './deprecated';
import {unknownOptionWarning} from './warnings';
import {errorMessage} from './errors';
import exampleConfig from './example_config';
import validationCondition from './condition';
import {ERROR, DEPRECATION, WARNING} from './utils';

Expand All @@ -22,7 +21,9 @@ export default ({
deprecate: deprecationWarning,
deprecatedConfig: {},
error: errorMessage,
exampleConfig,
exampleConfig: {},
recursive: true,
recursiveBlacklist: [],
title: {
deprecation: DEPRECATION,
error: ERROR,
Expand Down
11 changes: 8 additions & 3 deletions packages/jest-validate/src/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,27 @@ import type {ValidationOptions} from './types';

import chalk from 'chalk';
import getType from 'jest-get-type';
import {format, ValidationError, ERROR} from './utils';
import {formatPrettyObject, ValidationError, ERROR} from './utils';

export const errorMessage = (
option: string,
received: any,
defaultValue: any,
options: ValidationOptions,
path?: Array<string>,
): void => {
const message = ` Option ${chalk.bold(`"${option}"`)} must be of type:
const message = ` Option ${chalk.bold(
`"${path && path.length > 0 ? path.join('.') + '.' : ''}${option}"`,
)} must be of type:
${chalk.bold.green(getType(defaultValue))}
but instead received:
${chalk.bold.red(getType(received))}

Example:
{
${chalk.bold(`"${option}"`)}: ${chalk.bold(format(defaultValue))}
${chalk.bold(`"${option}"`)}: ${chalk.bold(
formatPrettyObject(defaultValue),
)}
}`;

const comment = options.comment;
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-validate/src/example_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const config: ValidationOptions = {
},
error: (option, received, defaultValue, options) => {},
exampleConfig: {key: 'value', test: 'case'},
recursive: true,
recursiveBlacklist: [],
title: {
deprecation: 'Deprecation Warning',
error: 'Validation Error',
Expand Down
4 changes: 4 additions & 0 deletions packages/jest-validate/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@ export type ValidationOptions = {
received: any,
defaultValue: any,
options: ValidationOptions,
path?: Array<string>,
) => void,
exampleConfig: Object,
recursive?: boolean,
recursiveBlacklist?: Array<string>,
title?: Title,
unknown?: (
config: Object,
exampleConfig: Object,
option: string,
options: ValidationOptions,
path?: Array<string>,
) => void,
};
7 changes: 7 additions & 0 deletions packages/jest-validate/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ export const format = (value: any): string =>
? value.toString()
: prettyFormat(value, {min: true});

export const formatPrettyObject = (value: any): string =>
typeof value === 'function'
? value.toString()
: JSON.stringify(value, null, 2)
.split('\n')
.join('\n ');

export class ValidationError extends Error {
name: string;
message: string;
Expand Down