Skip to content

Commit

Permalink
feat(pretty-format): allow to opt out from sorting object keys with `…
Browse files Browse the repository at this point in the history
…compareKeys: null` (#12443)
  • Loading branch information
Andarist committed Aug 22, 2022
1 parent ae2bed7 commit 187566a
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 36 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -14,6 +14,7 @@
- `[@jest/test-result, @jest/types]` [**BREAKING**] Replace `Bytes` and `Milliseconds` types with `number` ([#13155](https://github.com/facebook/jest/pull/13155))
- `[jest-worker]` Adds `workerIdleMemoryLimit` option which is used as a check for worker memory leaks >= Node 16.11.0 and recycles child workers as required ([#13056](https://github.com/facebook/jest/pull/13056), [#13105](https://github.com/facebook/jest/pull/13105), [#13106](https://github.com/facebook/jest/pull/13106), [#13107](https://github.com/facebook/jest/pull/13107))
- `[pretty-format]` [**BREAKING**] Remove `ConvertAnsi` plugin in favour of `jest-serializer-ansi-escapes` ([#13040](https://github.com/facebook/jest/pull/13040))
- `[pretty-format]` Allow to opt out from sorting object keys with `compareKeys: null` ([#12443](https://github.com/facebook/jest/pull/12443))

### Fixes

Expand Down
1 change: 1 addition & 0 deletions packages/jest-schemas/src/index.ts
Expand Up @@ -10,6 +10,7 @@ import {Static, Type} from '@sinclair/typebox';
const RawSnapshotFormat = Type.Partial(
Type.Object({
callToJSON: Type.Readonly(Type.Boolean()),
compareKeys: Type.Readonly(Type.Null()),
escapeRegex: Type.Readonly(Type.Boolean()),
escapeString: Type.Readonly(Type.Boolean()),
highlight: Type.Readonly(Type.Boolean()),
Expand Down
58 changes: 29 additions & 29 deletions packages/pretty-format/README.md
Expand Up @@ -66,21 +66,21 @@ console.log(prettyFormat(onClick, options));
```

<!-- prettier-ignore -->
| key | type | default | description |
| :-------------------- | :-------- | :--------- | :------------------------------------------------------ |
| `callToJSON` | `boolean` | `true` | call `toJSON` method (if it exists) on objects |
| `compareKeys` | `function`| `undefined`| compare function used when sorting object keys |
| `escapeRegex` | `boolean` | `false` | escape special characters in regular expressions |
| `escapeString` | `boolean` | `true` | escape special characters in strings |
| `highlight` | `boolean` | `false` | highlight syntax with colors in terminal (some plugins) |
| `indent` | `number` | `2` | spaces in each level of indentation |
| `maxDepth` | `number` | `Infinity` | levels to print in arrays, objects, elements, and so on |
| `maxWidth` | `number` | `Infinity` | number of elements to print in arrays, sets, and so on |
| `min` | `boolean` | `false` | minimize added space: no indentation nor line breaks |
| `plugins` | `array` | `[]` | plugins to serialize application-specific data types |
| `printBasicPrototype` | `boolean` | `false` | print the prototype for plain objects and arrays |
| `printFunctionName` | `boolean` | `true` | include or omit the name of a function |
| `theme` | `object` | | colors to highlight syntax in terminal |
| key | type | default | description |
| :-------------------- | :--------------- | :---------- | :-------------------------------------------------------------------------------------- |
| `callToJSON` | `boolean` | `true` | call `toJSON` method (if it exists) on objects |
| `compareKeys` | `function\|null` | `undefined` | compare function used when sorting object keys, `null` can be used to skip over sorting |
| `escapeRegex` | `boolean` | `false` | escape special characters in regular expressions |
| `escapeString` | `boolean` | `true` | escape special characters in strings |
| `highlight` | `boolean` | `false` | highlight syntax with colors in terminal (some plugins) |
| `indent` | `number` | `2` | spaces in each level of indentation |
| `maxDepth` | `number` | `Infinity` | levels to print in arrays, objects, elements, and so on |
| `maxWidth` | `number` | `Infinity` | number of elements to print in arrays, sets, and so on |
| `min` | `boolean` | `false` | minimize added space: no indentation nor line breaks |
| `plugins` | `array` | `[]` | plugins to serialize application-specific data types |
| `printBasicPrototype` | `boolean` | `false` | print the prototype for plain objects and arrays |
| `printFunctionName` | `boolean` | `true` | include or omit the name of a function |
| `theme` | `object` | | colors to highlight syntax in terminal |

Property values of `theme` are from [ansi-styles colors](https://github.com/chalk/ansi-styles#colors)

Expand Down Expand Up @@ -206,20 +206,20 @@ Write `serialize` to return a string, given the arguments:
### config

<!-- prettier-ignore -->
| key | type | description |
| :------------------ | :-------- | :------------------------------------------------------ |
| `callToJSON` | `boolean` | call `toJSON` method (if it exists) on objects |
| `compareKeys` | `function`| compare function used when sorting object keys |
| `colors` | `Object` | escape codes for colors to highlight syntax |
| `escapeRegex` | `boolean` | escape special characters in regular expressions |
| `escapeString` | `boolean` | escape special characters in strings |
| `indent` | `string` | spaces in each level of indentation |
| `maxDepth` | `number` | levels to print in arrays, objects, elements, and so on |
| `min` | `boolean` | minimize added space: no indentation nor line breaks |
| `plugins` | `array` | plugins to serialize application-specific data types |
| `printFunctionName` | `boolean` | include or omit the name of a function |
| `spacingInner` | `string` | spacing to separate items in a list |
| `spacingOuter` | `string` | spacing to enclose a list of items |
| key | type | description |
| :------------------ | :--------------- | :-------------------------------------------------------------------------------------- |
| `callToJSON` | `boolean` | call `toJSON` method (if it exists) on objects |
| `compareKeys` | `function\|null` | compare function used when sorting object keys, `null` can be used to skip over sorting |
| `colors` | `Object` | escape codes for colors to highlight syntax |
| `escapeRegex` | `boolean` | escape special characters in regular expressions |
| `escapeString` | `boolean` | escape special characters in strings |
| `indent` | `string` | spaces in each level of indentation |
| `maxDepth` | `number` | levels to print in arrays, objects, elements, and so on |
| `min` | `boolean` | minimize added space: no indentation nor line breaks |
| `plugins` | `array` | plugins to serialize application-specific data types |
| `printFunctionName` | `boolean` | include or omit the name of a function |
| `spacingInner` | `string` | spacing to separate items in a list |
| `spacingOuter` | `string` | spacing to enclose a list of items |

Each property of `colors` in `config` corresponds to a property of `theme` in `options`:

Expand Down
10 changes: 9 additions & 1 deletion packages/pretty-format/src/__tests__/prettyFormat.test.ts
Expand Up @@ -334,7 +334,7 @@ describe('prettyFormat()', () => {
expect(prettyFormat(val)).toEqual('Object {\n "a": 2,\n "b": 1,\n}');
});

it('prints an object with keys in their original order', () => {
it('prints an object with keys in their original order with the appropriate comparing function', () => {
// eslint-disable-next-line sort-keys
const val = {b: 1, a: 2};
const compareKeys = () => 0;
Expand All @@ -343,6 +343,14 @@ describe('prettyFormat()', () => {
);
});

it('prints an object with keys in their original order with compareKeys set to null', () => {
// eslint-disable-next-line sort-keys
const val = {b: 1, a: 2};
expect(prettyFormat(val, {compareKeys: null})).toEqual(
'Object {\n "b": 1,\n "a": 2,\n}',
);
});

it('prints an object with keys sorted in reverse order', () => {
const val = {a: 1, b: 2};
const compareKeys = (a: string, b: string) => (a > b ? -1 : 1);
Expand Down
4 changes: 3 additions & 1 deletion packages/pretty-format/src/collections.ts
Expand Up @@ -12,7 +12,9 @@ const getKeysOfEnumerableProperties = (
object: Record<string, unknown>,
compareKeys: CompareKeys,
) => {
const keys: Array<string | symbol> = Object.keys(object).sort(compareKeys);
const rawKeys = Object.keys(object);
const keys: Array<string | symbol> =
compareKeys !== null ? rawKeys.sort(compareKeys) : rawKeys;

if (Object.getOwnPropertySymbols) {
Object.getOwnPropertySymbols(object).forEach(symbol => {
Expand Down
9 changes: 6 additions & 3 deletions packages/pretty-format/src/index.ts
Expand Up @@ -400,7 +400,10 @@ const DEFAULT_THEME_KEYS = Object.keys(DEFAULT_THEME) as Array<
keyof typeof DEFAULT_THEME
>;

export const DEFAULT_OPTIONS: Options = {
// could be replaced by `satisfies` operator in the future: https://github.com/microsoft/TypeScript/issues/47920
const toOptionsSubtype = <T extends Options>(options: T) => options;

export const DEFAULT_OPTIONS = toOptionsSubtype({
callToJSON: true,
compareKeys: undefined,
escapeRegex: false,
Expand All @@ -414,7 +417,7 @@ export const DEFAULT_OPTIONS: Options = {
printBasicPrototype: true,
printFunctionName: true,
theme: DEFAULT_THEME,
};
});

function validateOptions(options: OptionsReceived) {
Object.keys(options).forEach(key => {
Expand Down Expand Up @@ -482,7 +485,7 @@ const getConfig = (options?: OptionsReceived): Config => ({
callToJSON: options?.callToJSON ?? DEFAULT_OPTIONS.callToJSON,
colors: options?.highlight ? getColorsHighlight(options) : getColorsEmpty(),
compareKeys:
typeof options?.compareKeys === 'function'
typeof options?.compareKeys === 'function' || options?.compareKeys === null
? options.compareKeys
: DEFAULT_OPTIONS.compareKeys,
escapeRegex: getEscapeRegex(options),
Expand Down
5 changes: 3 additions & 2 deletions packages/pretty-format/src/types.ts
Expand Up @@ -20,7 +20,7 @@ type Print = (arg0: unknown) => string;

export type Theme = Options['theme'];

export type CompareKeys = ((a: string, b: string) => number) | undefined;
export type CompareKeys = ((a: string, b: string) => number) | null | undefined;

type RequiredOptions = Required<PrettyFormatOptions>;

Expand All @@ -30,7 +30,8 @@ export interface Options
theme: Required<RequiredOptions['theme']>;
}

export interface PrettyFormatOptions extends SnapshotFormat {
export interface PrettyFormatOptions
extends Omit<SnapshotFormat, 'compareKeys'> {
compareKeys?: CompareKeys;
plugins?: Plugins;
}
Expand Down

0 comments on commit 187566a

Please sign in to comment.