/
jest-matcher-utils.ts
174 lines (152 loc) · 4.31 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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// we are using only the ones needed by @testing-library/jest-dom
// if you need more, just ask
import c from 'picocolors'
import type { Formatter } from 'picocolors/types'
import type { PrettyFormatOptions } from 'pretty-format'
import { format as prettyFormat, plugins as prettyFormatPlugins } from 'pretty-format'
import { unifiedDiff } from '../../node/diff'
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 interface MatcherHintOptions {
comment?: string
expectedColor?: Formatter
isDirectExpectCall?: boolean
isNot?: boolean
promise?: string
receivedColor?: Formatter
secondArgument?: string
secondArgumentColor?: Formatter
}
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, options?: PrettyFormatOptions): string {
const MAX_LENGTH = 10000
let result
try {
result = prettyFormat(object, {
maxDepth,
// min: true,
plugins: PLUGINS,
...options,
})
}
catch {
result = prettyFormat(object, {
callToJSON: false,
maxDepth,
// 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)))
export interface DiffOptions {
aAnnotation?: string
aColor?: Formatter
aIndicator?: string
bAnnotation?: string
bColor?: Formatter
bIndicator?: string
changeColor?: Formatter
changeLineTrailingSpaceColor?: Formatter
commonColor?: Formatter
commonIndicator?: string
commonLineTrailingSpaceColor?: Formatter
contextLines?: number
emptyFirstOrLastLinePlaceholder?: string
expand?: boolean
includeChangeCounts?: boolean
omitAnnotationLines?: boolean
patchColor?: Formatter
// pretty-format type
compareKeys?: any
}
// 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))
}