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

Adds options for configuring the snapshot and inline snapshot serializers #11654

Merged
merged 16 commits into from Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,8 @@

### Features

- `[jest-cli]` Adds 2 config ptions (`inlineSnapshotFormatter` and `snapshotFormat`) which offers a way to override any of the formatting settings which come with [pretty-format](https://www.npmjs.com/package/pretty-format#usage-with-options). ([#11654](https://github.com/facebook/jest/pull/11654))

### Fixes

### Chore & Maintenance
Expand Down
55 changes: 55 additions & 0 deletions docs/Configuration.md
Expand Up @@ -537,6 +537,43 @@ test('some test', () => {

_Note: This option is only supported using the default `jest-circus`. test runner_

### `inlineSnapshotFormat` \[object]

Default: `undefined`

Allows to overriding specific snapshot formatting options documented in the [pretty-format readme](https://www.npmjs.com/package/pretty-format#usage-with-options). For example, this config would have the inline snapshot formatter not print a prefix for "Object" and "Array":
orta marked this conversation as resolved.
Show resolved Hide resolved

```json
{
"jest": {
"inlineSnapshotFormat": {
"printBasicPrototype": false
}
}
}
```

```ts
import {expect, test} from '@jest/globals';

test('does not show prototypes for object and array inline', () => {
const object = {
array: [{hello: 'Danger'}],
};
expect(object).toMatchInlineSnapshot(`
{
"array": [
{
"hello": "Danger",
},
],
}
`);
});
```

There is a corresponding [`snapshotFormat`](#snapshotformat-object) option for separate file snapshots.

### `maxConcurrency` \[number]

Default: `5`
Expand Down Expand Up @@ -945,6 +982,24 @@ Default: `5`

The number of seconds after which a test is considered as slow and reported as such in the results.

### `snapshotFormat` \[object]

Default: `undefined`

Allows to overriding specific snapshot formatting options documented in the [pretty-format readme](https://www.npmjs.com/package/pretty-format#usage-with-options). For example, this config would have the snapshot formatter which prints with 4 spaces instead of 2:
orta marked this conversation as resolved.
Show resolved Hide resolved

```json
{
"jest": {
"snapshotFormat": {
"indent": 4
}
}
}
```

There is a corresponding [`inlineSnapshotFormat`](#inlinesnapshotformat-object) option for inline snapshots.

### `snapshotResolver` \[string]

Default: `undefined`
Expand Down
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`snapshot serializer uses 8 chars for indent, and shows no prototypes for object and array in a snapshot: no prototypes 1`] = `
{
"array": [
{
"hello": "Danger",
},
],
}
`;
32 changes: 32 additions & 0 deletions e2e/snapshot-formatting-changes/__tests__/snapshot.test.js
@@ -0,0 +1,32 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';

describe('snapshot serializer', () => {
it('does not show prototypes for object and array inline', () => {
const object = {
array: [{hello: 'Danger'}],
};
expect(object).toMatchInlineSnapshot(`
{
"array": [
{
"hello": "Danger",
},
],
}
`);
});

it('uses 8 chars for indent, and shows no prototypes for object and array in a snapshot', () => {
const object = {
array: [{hello: 'Danger'}],
};
expect(object).toMatchSnapshot('no prototypes');
});
});
12 changes: 12 additions & 0 deletions e2e/snapshot-formatting-changes/package.json
@@ -0,0 +1,12 @@
{
"jest": {
"testEnvironment": "node",
"inlineSnapshotFormat": {
"printBasicPrototype": false
},
"snapshotFormat": {
"printBasicPrototype": false,
"indent": 8
}
}
}
Expand Up @@ -155,7 +155,9 @@ export const initialize = async ({
const snapshotPath = snapshotResolver.resolveSnapshotPath(testPath);
const snapshotState = new SnapshotState(snapshotPath, {
expand,
inlineSnapshotFormat: config.inlineSnapshotFormat,
prettierPath: config.prettierPath,
snapshotFormat: config.snapshotFormat,
updateSnapshot,
});
// @ts-expect-error: snapshotState is a jest extension of `expect`
Expand Down
3 changes: 3 additions & 0 deletions packages/jest-config/src/ValidConfig.ts
Expand Up @@ -8,6 +8,7 @@
import type {Config} from '@jest/types';
import {replacePathSepForRegex} from 'jest-regex-util';
import {multipleValidOptions} from 'jest-validate';
import {DEFAULT_OPTIONS as PRETTY_FORMAT_DEFAULTS} from 'pretty-format';
import {NODE_MODULES} from './constants';

const NODE_MODULES_REGEXP = replacePathSepForRegex(NODE_MODULES);
Expand Down Expand Up @@ -66,6 +67,7 @@ const initialOptions: Config.InitialOptions = {
throwOnModuleCollision: false,
},
injectGlobals: true,
inlineSnapshotFormat: PRETTY_FORMAT_DEFAULTS,
json: false,
lastCommit: false,
listTests: false,
Expand Down Expand Up @@ -109,6 +111,7 @@ const initialOptions: Config.InitialOptions = {
skipFilter: false,
skipNodeResolution: false,
slowTestThreshold: 5,
snapshotFormat: PRETTY_FORMAT_DEFAULTS,
snapshotResolver: '<rootDir>/snapshotResolver.js',
snapshotSerializers: ['my-serializer-module'],
testEnvironment: 'jest-environment-jsdom',
Expand Down
4 changes: 4 additions & 0 deletions packages/jest-config/src/index.ts
Expand Up @@ -127,6 +127,7 @@ const groupOptions = (
forceExit: options.forceExit,
globalSetup: options.globalSetup,
globalTeardown: options.globalTeardown,
inlineSnapshotFormat: options.inlineSnapshotFormat,
json: options.json,
lastCommit: options.lastCommit,
listTests: options.listTests,
Expand All @@ -149,6 +150,7 @@ const groupOptions = (
runTestsByPath: options.runTestsByPath,
silent: options.silent,
skipFilter: options.skipFilter,
snapshotFormat: options.snapshotFormat,
testFailureExitCode: options.testFailureExitCode,
testNamePattern: options.testNamePattern,
testPathPattern: options.testPathPattern,
Expand Down Expand Up @@ -184,6 +186,7 @@ const groupOptions = (
globals: options.globals,
haste: options.haste,
injectGlobals: options.injectGlobals,
inlineSnapshotFormat: options.inlineSnapshotFormat,
moduleDirectories: options.moduleDirectories,
moduleFileExtensions: options.moduleFileExtensions,
moduleLoader: options.moduleLoader,
Expand All @@ -204,6 +207,7 @@ const groupOptions = (
skipFilter: options.skipFilter,
skipNodeResolution: options.skipNodeResolution,
slowTestThreshold: options.slowTestThreshold,
snapshotFormat: options.snapshotFormat,
snapshotResolver: options.snapshotResolver,
snapshotSerializers: options.snapshotSerializers,
testEnvironment: options.testEnvironment,
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-config/src/normalize.ts
Expand Up @@ -970,6 +970,7 @@ export default async function normalize(
case 'extensionsToTreatAsEsm':
case 'extraGlobals':
case 'globals':
case 'inlineSnapshotFormat':
case 'findRelatedTests':
case 'forceCoverageMatch':
case 'forceExit':
Expand Down Expand Up @@ -997,6 +998,7 @@ export default async function normalize(
case 'skipFilter':
case 'skipNodeResolution':
case 'slowTestThreshold':
case 'snapshotFormat':
case 'testEnvironment':
case 'testEnvironmentOptions':
case 'testFailureExitCode':
Expand Down
Expand Up @@ -18,6 +18,7 @@ exports[`prints the config object 1`] = `
"globals": {},
"haste": {},
"injectGlobals": true,
"inlineSnapshotFormat": {},
"moduleDirectories": [],
"moduleFileExtensions": [
"js"
Expand All @@ -41,6 +42,7 @@ exports[`prints the config object 1`] = `
"skipFilter": false,
"skipNodeResolution": false,
"slowTestThreshold": 5,
"snapshotFormat": {},
"snapshotSerializers": [],
"testEnvironment": "node",
"testEnvironmentOptions": {},
Expand Down Expand Up @@ -75,6 +77,7 @@ exports[`prints the config object 1`] = `
"expand": false,
"findRelatedTests": false,
"forceExit": false,
"inlineSnapshotFormat": {},
"json": false,
"lastCommit": false,
"listTests": false,
Expand All @@ -94,6 +97,7 @@ exports[`prints the config object 1`] = `
"runTestsByPath": false,
"silent": false,
"skipFilter": false,
"snapshotFormat": {},
"testFailureExitCode": 1,
"testNamePattern": "",
"testPathPattern": "",
Expand Down
4 changes: 3 additions & 1 deletion packages/jest-jasmine2/src/setup_jest_globals.ts
Expand Up @@ -106,12 +106,14 @@ export default async ({

patchJasmine();
const {expand, updateSnapshot} = globalConfig;
const {prettierPath} = config;
const {prettierPath, inlineSnapshotFormat, snapshotFormat} = config;
const snapshotResolver = await buildSnapshotResolver(config, localRequire);
const snapshotPath = snapshotResolver.resolveSnapshotPath(testPath);
const snapshotState = new SnapshotState(snapshotPath, {
expand,
inlineSnapshotFormat,
prettierPath,
snapshotFormat,
updateSnapshot,
});
// @ts-expect-error: snapshotState is a jest extension of `expect`
Expand Down
16 changes: 15 additions & 1 deletion packages/jest-snapshot/src/State.ts
Expand Up @@ -8,6 +8,7 @@
import * as fs from 'graceful-fs';
import type {Config} from '@jest/types';
import {getStackTraceLines, getTopFrame} from 'jest-message-util';
import type {OptionsReceived as PrettyFormatOptions} from 'pretty-format';
import {InlineSnapshot, saveInlineSnapshots} from './InlineSnapshots';
import type {SnapshotData} from './types';
import {
Expand All @@ -25,6 +26,8 @@ export type SnapshotStateOptions = {
updateSnapshot: Config.SnapshotUpdateState;
prettierPath: Config.Path;
expand?: boolean;
snapshotFormat: PrettyFormatOptions;
inlineSnapshotFormat: PrettyFormatOptions;
};

export type SnapshotMatchOptions = {
Expand Down Expand Up @@ -61,6 +64,8 @@ export default class SnapshotState {
private _inlineSnapshots: Array<InlineSnapshot>;
private _uncheckedKeys: Set<string>;
private _prettierPath: Config.Path;
private _snapshotFormat: PrettyFormatOptions;
private _inlineSnapshotFormat: PrettyFormatOptions;

added: number;
expand: boolean;
Expand Down Expand Up @@ -88,6 +93,9 @@ export default class SnapshotState {
this.unmatched = 0;
this._updateSnapshot = options.updateSnapshot;
this.updated = 0;

SimenB marked this conversation as resolved.
Show resolved Hide resolved
this._snapshotFormat = options.snapshotFormat;
this._inlineSnapshotFormat = options.inlineSnapshotFormat;
}

markSnapshotsAsCheckedForTest(testName: string): void {
Expand Down Expand Up @@ -201,7 +209,13 @@ export default class SnapshotState {
this._uncheckedKeys.delete(key);
}

const receivedSerialized = addExtraLineBreaks(serialize(received));
const customFormat = isInline
? this._inlineSnapshotFormat
: this._snapshotFormat;

const receivedSerialized = addExtraLineBreaks(
serialize(received, undefined, customFormat),
);
const expected = isInline ? inlineSnapshot : this._snapshotData[key];
const pass = expected === receivedSerialized;
const hasSnapshot = expected !== undefined;
Expand Down
12 changes: 10 additions & 2 deletions packages/jest-snapshot/src/utils.ts
Expand Up @@ -10,7 +10,10 @@ import chalk = require('chalk');
import * as fs from 'graceful-fs';
import naturalCompare = require('natural-compare');
import type {Config} from '@jest/types';
import {format as prettyFormat} from 'pretty-format';
import {
OptionsReceived as PrettyFormatOptions,
format as prettyFormat,
} from 'pretty-format';
import {getSerializers} from './plugins';
import type {SnapshotData} from './types';

Expand Down Expand Up @@ -152,13 +155,18 @@ export const removeLinesBeforeExternalMatcherTrap = (stack: string): string => {
const escapeRegex = true;
const printFunctionName = false;

export const serialize = (val: unknown, indent = 2): string =>
export const serialize = (
val: unknown,
indent = 2,
formatOverrides: PrettyFormatOptions = {},
): string =>
normalizeNewlines(
prettyFormat(val, {
escapeRegex,
indent,
plugins: getSerializers(),
printFunctionName,
...formatOverrides,
}),
);

Expand Down