or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

diff-generation.mdindex.mdmatcher-display.mdvalue-formatting.mdvalue-validation.md
tile.json

diff-generation.mddocs/

0

# Diff Generation

1

2

Functions for comparing values and generating visual diffs for test output, helping developers understand exactly how expected and received values differ.

3

4

## Capabilities

5

6

### Diff Function

7

8

Generates diff output between two values when appropriate, with automatic detection of diffable types.

9

10

```typescript { .api }

11

/**

12

* Generate diff between two values

13

* @param a - First value to compare

14

* @param b - Second value to compare

15

* @param options - Diff generation options

16

* @returns Diff output string or null if not diffable

17

*/

18

function diff(

19

a: unknown,

20

b: unknown,

21

options?: DiffOptions

22

): string | null;

23

24

type DiffOptions = {

25

aAnnotation?: string;

26

bAnnotation?: string;

27

changeColor?: (arg: string) => string;

28

changeLineTrailingSpaceColor?: (arg: string) => string;

29

commonColor?: (arg: string) => string;

30

commonLineTrailingSpaceColor?: (arg: string) => string;

31

contextLines?: number;

32

expand?: boolean;

33

includeChangeCounts?: boolean;

34

omitAnnotationLines?: boolean;

35

patchColor?: (arg: string) => string;

36

};

37

```

38

39

**Usage Examples:**

40

41

```typescript

42

import { diff } from "jest-matcher-utils";

43

44

// Basic object diff

45

const expected = { name: "Alice", age: 25, city: "NYC" };

46

const received = { name: "Alice", age: 30, city: "LA" };

47

const diffResult = diff(expected, received);

48

// Result: Colorized diff showing changed properties

49

50

// Array diff

51

const expectedArray = [1, 2, 3, 4];

52

const receivedArray = [1, 2, 5, 4];

53

const arrayDiff = diff(expectedArray, receivedArray);

54

// Result: Shows element differences

55

56

// String diff

57

const expectedText = "Hello world";

58

const receivedText = "Hello earth";

59

const textDiff = diff(expectedText, receivedText);

60

// Result: Character-level diff highlighting changes

61

62

// Returns null for non-diffable types

63

const numDiff = diff(5, 10);

64

// Result: null (numbers don't generate useful diffs)

65

66

// With options

67

const customDiff = diff(expected, received, {

68

expand: true,

69

includeChangeCounts: true

70

});

71

```

72

73

### Print Diff Or Stringify

74

75

Generates comprehensive diff output or falls back to stringified comparison when diff is not useful.

76

77

```typescript { .api }

78

/**

79

* Generate diff output or stringify values for comparison

80

* @param expected - Expected value

81

* @param received - Received value

82

* @param expectedLabel - Label for expected value

83

* @param receivedLabel - Label for received value

84

* @param expand - Whether to expand diff output

85

* @returns Formatted diff or comparison string

86

*/

87

function printDiffOrStringify(

88

expected: unknown,

89

received: unknown,

90

expectedLabel: string,

91

receivedLabel: string,

92

expand: boolean

93

): string;

94

```

95

96

**Usage Examples:**

97

98

```typescript

99

import { printDiffOrStringify } from "jest-matcher-utils";

100

101

// Object comparison with labels

102

const expected = { user: "Alice", role: "admin" };

103

const received = { user: "Alice", role: "user" };

104

const comparison = printDiffOrStringify(

105

expected,

106

received,

107

"Expected",

108

"Received",

109

false

110

);

111

// Result: Labeled diff output showing role change

112

113

// String comparison with multiline

114

const expectedText = `Line 1

115

Line 2

116

Line 3`;

117

const receivedText = `Line 1

118

Modified Line 2

119

Line 3`;

120

const textComparison = printDiffOrStringify(

121

expectedText,

122

receivedText,

123

"Expected",

124

"Received",

125

true // expanded output

126

);

127

// Result: Unified diff format with line numbers

128

129

// Falls back to stringify for incomparable types

130

const numComparison = printDiffOrStringify(

131

42,

132

43,

133

"Expected",

134

"Received",

135

false

136

);

137

// Result: 'Expected: 42\nReceived: 43'

138

139

// Handles identical values that serialize differently

140

const date1 = new Date('2024-01-01');

141

const date2 = new Date('2024-01-01');

142

const sameComparison = printDiffOrStringify(

143

date1,

144

date2,

145

"Expected",

146

"Received",

147

false

148

);

149

// Result: 'Expected: ...\nReceived: serializes to the same string'

150

```

151

152

### Replace Matched To Asymmetric Matcher

153

154

Advanced function for replacing matched values with asymmetric matchers during comparison, handling Jest's expect.any(), expect.objectContaining(), etc.

155

156

```typescript { .api }

157

/**

158

* Replace matched values with asymmetric matchers for comparison

159

* @param replacedExpected - Expected value to process

160

* @param replacedReceived - Received value to process

161

* @param expectedCycles - Cycle detection for expected value

162

* @param receivedCycles - Cycle detection for received value

163

* @returns Object with processed expected and received values

164

*/

165

function replaceMatchedToAsymmetricMatcher(

166

replacedExpected: unknown,

167

replacedReceived: unknown,

168

expectedCycles: Array<unknown>,

169

receivedCycles: Array<unknown>

170

): {replacedExpected: unknown; replacedReceived: unknown};

171

```

172

173

**Usage Examples:**

174

175

```typescript

176

import { replaceMatchedToAsymmetricMatcher } from "jest-matcher-utils";

177

178

// Handle asymmetric matchers in expected values

179

const expected = {

180

id: expect.any(Number),

181

name: "Alice",

182

metadata: expect.objectContaining({ version: "1.0" })

183

};

184

185

const received = {

186

id: 123,

187

name: "Alice",

188

metadata: { version: "1.0", extra: "data" }

189

};

190

191

const {replacedExpected, replacedReceived} = replaceMatchedToAsymmetricMatcher(

192

expected,

193

received,

194

[], // expectedCycles

195

[] // receivedCycles

196

);

197

198

// Result: Asymmetric matchers that match are replaced in received,

199

// making diff output cleaner by showing what actually differs

200

201

// Handles circular references

202

const circular = { prop: null };

203

circular.prop = circular;

204

205

const processed = replaceMatchedToAsymmetricMatcher(

206

circular,

207

{ prop: { prop: "different" } },

208

[circular], // Track circular reference

209

[]

210

);

211

// Prevents infinite recursion during processing

212

213

// Used internally by Jest matchers

214

function customMatcher(received: unknown, expected: unknown) {

215

const {replacedExpected, replacedReceived} = replaceMatchedToAsymmetricMatcher(

216

expected,

217

received,

218

[],

219

[]

220

);

221

222

// Generate cleaner diff with processed values

223

const diffOutput = diff(replacedExpected, replacedReceived);

224

return diffOutput;

225

}

226

```

227

228

## Diff Strategy

229

230

The diff generation system uses intelligent strategies:

231

232

1. **String Diffs**: Character-level and line-level diffs for strings

233

- Short strings: Character highlighting

234

- Multi-line strings: Unified diff format

235

- Trailing whitespace visualization

236

237

2. **Object/Array Diffs**: Structured comparison

238

- Property-level changes highlighted

239

- Nested object traversal

240

- Array element comparison

241

242

3. **Type-Based Logic**: Different approaches per type

243

- Primitives: Simple before/after display

244

- Complex objects: Recursive property comparison

245

- Functions/Dates/RegExp: String representation fallback

246

247

4. **Asymmetric Matcher Support**:

248

- Replaces matching asymmetric matchers

249

- Cleaner diff output focusing on actual differences

250

- Circular reference handling

251

252

5. **Performance Limits**:

253

- Maximum string length limits (20,000 chars)

254

- Automatic fallback to stringify for large objects

255

- Cycle detection prevents infinite recursion

256

257

The system automatically chooses the most informative representation for any value comparison, ensuring developers get the clearest possible view of test failures.