/
jest-matcher-utils.ts
143 lines (123 loc) · 3.67 KB
/
jest-matcher-utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// we are using only the ones needed by @testing-library/jest-dom
// if you need more, just ask
import c from 'picocolors'
import type { PrettyFormatOptions } from 'pretty-format'
import { format as prettyFormat, plugins as prettyFormatPlugins } from 'pretty-format'
import { unifiedDiff } from '../../utils/diff'
import type { DiffOptions, MatcherHintOptions } from '../../types/matcher-utils'
export const EXPECTED_COLOR = c.green
export const RECEIVED_COLOR = c.red
export const INVERTED_COLOR = c.inverse
export const BOLD_WEIGHT = c.bold
export const DIM_COLOR = c.dim
const {
AsymmetricMatcher,
DOMCollection,
DOMElement,
Immutable,
ReactElement,
ReactTestComponent,
} = prettyFormatPlugins
const PLUGINS = [
ReactTestComponent,
ReactElement,
DOMElement,
DOMCollection,
Immutable,
AsymmetricMatcher,
]
export function matcherHint(
matcherName: string,
received = 'received',
expected = 'expected',
options: MatcherHintOptions = {},
) {
const {
comment = '',
expectedColor = EXPECTED_COLOR,
isDirectExpectCall = false, // seems redundant with received === ''
isNot = false,
promise = '',
receivedColor = RECEIVED_COLOR,
secondArgument = '',
secondArgumentColor = EXPECTED_COLOR,
} = options
let hint = ''
let dimString = 'expect' // concatenate adjacent dim substrings
if (!isDirectExpectCall && received !== '') {
hint += DIM_COLOR(`${dimString}(`) + receivedColor(received)
dimString = ')'
}
if (promise !== '') {
hint += DIM_COLOR(`${dimString}.`) + promise
dimString = ''
}
if (isNot) {
hint += `${DIM_COLOR(`${dimString}.`)}not`
dimString = ''
}
if (matcherName.includes('.')) {
// Old format: for backward compatibility,
// especially without promise or isNot options
dimString += matcherName
}
else {
// New format: omit period from matcherName arg
hint += DIM_COLOR(`${dimString}.`) + matcherName
dimString = ''
}
if (expected === '') {
dimString += '()'
}
else {
hint += DIM_COLOR(`${dimString}(`) + expectedColor(expected)
if (secondArgument)
hint += DIM_COLOR(', ') + secondArgumentColor(secondArgument)
dimString = ')'
}
if (comment !== '')
dimString += ` // ${comment}`
if (dimString !== '')
hint += DIM_COLOR(dimString)
return hint
}
const SPACE_SYMBOL = '\u{00B7}' // middle dot
// Instead of inverse highlight which now implies a change,
// replace common spaces with middle dot at the end of any line.
const replaceTrailingSpaces = (text: string): string =>
text.replace(/\s+$/gm, spaces => SPACE_SYMBOL.repeat(spaces.length))
export function stringify(object: unknown, maxDepth = 10, { maxLength, ...options }: PrettyFormatOptions & { maxLength?: number } = {}): string {
const MAX_LENGTH = maxLength ?? 10000
let result
try {
result = prettyFormat(object, {
maxDepth,
escapeString: false,
// min: true,
plugins: PLUGINS,
...options,
})
}
catch {
result = prettyFormat(object, {
callToJSON: false,
maxDepth,
escapeString: false,
// min: true,
plugins: PLUGINS,
...options,
})
}
return result.length >= MAX_LENGTH && maxDepth > 1
? stringify(object, Math.floor(maxDepth / 2))
: result
}
export const printReceived = (object: unknown): string =>
RECEIVED_COLOR(replaceTrailingSpaces(stringify(object)))
export const printExpected = (value: unknown): string =>
EXPECTED_COLOR(replaceTrailingSpaces(stringify(value)))
// TODO: do something with options
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function diff(a: any, b: any, options?: DiffOptions) {
return unifiedDiff(stringify(b), stringify(a))
}