README.md
  1  # jest-diff
  2  
  3  Display differences clearly so people can review changes confidently.
  4  
  5  The default export serializes JavaScript **values**, compares them line-by-line, and returns a string which includes comparison lines.
  6  
  7  Two named exports compare **strings** character-by-character:
  8  
  9  - `diffStringsUnified` returns a string.
 10  - `diffStringsRaw` returns an array of `Diff` objects.
 11  
 12  Three named exports compare **arrays of strings** line-by-line:
 13  
 14  - `diffLinesUnified` and `diffLinesUnified2` return a string.
 15  - `diffLinesRaw` returns an array of `Diff` objects.
 16  
 17  ## Installation
 18  
 19  To add this package as a dependency of a project, run either of the following commands:
 20  
 21  - `npm install jest-diff`
 22  - `yarn add jest-diff`
 23  
 24  ## Usage of default export
 25  
 26  Given JavaScript **values**, `diffDefault(a, b, options?)` does the following:
 27  
 28  1. **serialize** the values as strings using the `pretty-format` package
 29  2. **compare** the strings line-by-line using the `diff-sequences` package
 30  3. **format** the changed or common lines using the `chalk` package
 31  
 32  To use this function, write either of the following:
 33  
 34  - `const diffDefault = require('jest-diff').default;` in CommonJS modules
 35  - `import diffDefault from 'jest-diff';` in ECMAScript modules
 36  
 37  ### Example of default export
 38  
 39  ```js
 40  const a = ['delete', 'common', 'changed from'];
 41  const b = ['common', 'changed to', 'insert'];
 42  
 43  const difference = diffDefault(a, b);
 44  ```
 45  
 46  The returned **string** consists of:
 47  
 48  - annotation lines: describe the two change indicators with labels, and a blank line
 49  - comparison lines: similar to “unified” view on GitHub, but `Expected` lines are green, `Received` lines are red, and common lines are dim (by default, see Options)
 50  
 51  ```diff
 52  - Expected
 53  + Received
 54  
 55    Array [
 56  -   "delete",
 57      "common",
 58  -   "changed from",
 59  +   "changed to",
 60  +   "insert",
 61    ]
 62  ```
 63  
 64  ### Edge cases of default export
 65  
 66  Here are edge cases for the return value:
 67  
 68  - `' Comparing two different types of values. …'` if the arguments have **different types** according to the `jest-get-type` package (instances of different classes have the same `'object'` type)
 69  - `'Compared values have no visual difference.'` if the arguments have either **referential identity** according to `Object.is` method or **same serialization** according to the `pretty-format` package
 70  - `null` if either argument is a so-called **asymmetric matcher** in Jasmine or Jest
 71  
 72  ## Usage of diffStringsUnified
 73  
 74  Given **strings**, `diffStringsUnified(a, b, options?)` does the following:
 75  
 76  1. **compare** the strings character-by-character using the `diff-sequences` package
 77  2. **clean up** small (often coincidental) common substrings, also known as chaff
 78  3. **format** the changed or common lines using the `chalk` package
 79  
 80  Although the function is mainly for **multiline** strings, it compares any strings.
 81  
 82  Write either of the following:
 83  
 84  - `const {diffStringsUnified} = require('jest-diff');` in CommonJS modules
 85  - `import {diffStringsUnified} from 'jest-diff';` in ECMAScript modules
 86  
 87  ### Example of diffStringsUnified
 88  
 89  ```js
 90  const a = 'common\nchanged from';
 91  const b = 'common\nchanged to';
 92  
 93  const difference = diffStringsUnified(a, b);
 94  ```
 95  
 96  The returned **string** consists of:
 97  
 98  - annotation lines: describe the two change indicators with labels, and a blank line
 99  - comparison lines: similar to “unified” view on GitHub, and **changed substrings** have **inverse** foreground and background colors (that is, `from` has white-on-green and `to` has white-on-red, which the following example does not show)
100  
101  ```diff
102  - Expected
103  + Received
104  
105    common
106  - changed from
107  + changed to
108  ```
109  
110  ### Performance of diffStringsUnified
111  
112  To get the benefit of **changed substrings** within the comparison lines, a character-by-character comparison has a higher computational cost (in time and space) than a line-by-line comparison.
113  
114  If the input strings can have **arbitrary length**, we recommend that the calling code set a limit, beyond which splits the strings, and then calls `diffLinesUnified` instead. For example, Jest falls back to line-by-line comparison if either string has length greater than 20K characters.
115  
116  ## Usage of diffLinesUnified
117  
118  Given **arrays of strings**, `diffLinesUnified(aLines, bLines, options?)` does the following:
119  
120  1. **compare** the arrays line-by-line using the `diff-sequences` package
121  2. **format** the changed or common lines using the `chalk` package
122  
123  You might call this function when strings have been split into lines and you do not need to see changed substrings within lines.
124  
125  ### Example of diffLinesUnified
126  
127  ```js
128  const aLines = ['delete', 'common', 'changed from'];
129  const bLines = ['common', 'changed to', 'insert'];
130  
131  const difference = diffLinesUnified(aLines, bLines);
132  ```
133  
134  ```diff
135  - Expected
136  + Received
137  
138  - delete
139    common
140  - changed from
141  + changed to
142  + insert
143  ```
144  
145  ### Edge cases of diffLinesUnified or diffStringsUnified
146  
147  Here are edge cases for arguments and return values:
148  
149  - both `a` and `b` are empty strings: no comparison lines
150  - only `a` is empty string: all comparison lines have `bColor` and `bIndicator` (see Options)
151  - only `b` is empty string: all comparison lines have `aColor` and `aIndicator` (see Options)
152  - `a` and `b` are equal non-empty strings: all comparison lines have `commonColor` and `commonIndicator` (see Options)
153  
154  ## Usage of diffLinesUnified2
155  
156  Given two **pairs** of arrays of strings, `diffLinesUnified2(aLinesDisplay, bLinesDisplay, aLinesCompare, bLinesCompare, options?)` does the following:
157  
158  1. **compare** the pair of `Compare` arrays line-by-line using the `diff-sequences` package
159  2. **format** the corresponding lines in the pair of `Display` arrays using the `chalk` package
160  
161  Jest calls this function to consider lines as common instead of changed if the only difference is indentation.
162  
163  You might call this function for case insensitive or Unicode equivalence comparison of lines.
164  
165  ### Example of diffLinesUnified2
166  
167  ```js
168  import format from 'pretty-format';
169  
170  const a = {
171    text: 'Ignore indentation in serialized object',
172    time: '2019-09-19T12:34:56.000Z',
173    type: 'CREATE_ITEM',
174  };
175  const b = {
176    payload: {
177      text: 'Ignore indentation in serialized object',
178      time: '2019-09-19T12:34:56.000Z',
179    },
180    type: 'CREATE_ITEM',
181  };
182  
183  const difference = diffLinesUnified2(
184    // serialize with indentation to display lines
185    format(a).split('\n'),
186    format(b).split('\n'),
187    // serialize without indentation to compare lines
188    format(a, {indent: 0}).split('\n'),
189    format(b, {indent: 0}).split('\n'),
190  );
191  ```
192  
193  The `text` and `time` properties are common, because their only difference is indentation:
194  
195  ```diff
196  - Expected
197  + Received
198  
199    Object {
200  +   payload: Object {
201        text: 'Ignore indentation in serialized object',
202        time: '2019-09-19T12:34:56.000Z',
203  +   },
204      type: 'CREATE_ITEM',
205    }
206  ```
207  
208  The preceding example illustrates why (at least for indentation) it seems more intuitive that the function returns the common line from the `bLinesDisplay` array instead of from the `aLinesDisplay` array.
209  
210  ## Usage of diffStringsRaw
211  
212  Given **strings** and a boolean option, `diffStringsRaw(a, b, cleanup)` does the following:
213  
214  1. **compare** the strings character-by-character using the `diff-sequences` package
215  2. optionally **clean up** small (often coincidental) common substrings, also known as chaff
216  
217  Because `diffStringsRaw` returns the difference as **data** instead of a string, you can format it as your application requires (for example, enclosed in HTML markup for browser instead of escape sequences for console).
218  
219  The returned **array** describes substrings as instances of the `Diff` class, which calling code can access like array tuples:
220  
221  The value at index `0` is one of the following:
222  
223  | value | named export  | description           |
224  | ----: | :------------ | :-------------------- |
225  |   `0` | `DIFF_EQUAL`  | in `a` and in `b`     |
226  |  `-1` | `DIFF_DELETE` | in `a` but not in `b` |
227  |   `1` | `DIFF_INSERT` | in `b` but not in `a` |
228  
229  The value at index `1` is a substring of `a` or `b` or both.
230  
231  ### Example of diffStringsRaw with cleanup
232  
233  ```js
234  const diffs = diffStringsRaw('changed from', 'changed to', true);
235  ```
236  
237  | `i` | `diffs[i][0]` | `diffs[i][1]` |
238  | --: | ------------: | :------------ |
239  | `0` |           `0` | `'changed '`  |
240  | `1` |          `-1` | `'from'`      |
241  | `2` |           `1` | `'to'`        |
242  
243  ### Example of diffStringsRaw without cleanup
244  
245  ```js
246  const diffs = diffStringsRaw('changed from', 'changed to', false);
247  ```
248  
249  | `i` | `diffs[i][0]` | `diffs[i][1]` |
250  | --: | ------------: | :------------ |
251  | `0` |           `0` | `'changed '`  |
252  | `1` |          `-1` | `'fr'`        |
253  | `2` |           `1` | `'t'`         |
254  | `3` |           `0` | `'o'`         |
255  | `4` |          `-1` | `'m'`         |
256  
257  ### Advanced import for diffStringsRaw
258  
259  Here are all the named imports that you might need for the `diffStringsRaw` function:
260  
261  - `const {DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, Diff, diffStringsRaw} = require('jest-diff');` in CommonJS modules
262  - `import {DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, Diff, diffStringsRaw} from 'jest-diff';` in ECMAScript modules
263  
264  To write a **formatting** function, you might need the named constants (and `Diff` in TypeScript annotations).
265  
266  If you write an application-specific **cleanup** algorithm, then you might need to call the `Diff` constructor:
267  
268  ```js
269  const diffCommon = new Diff(DIFF_EQUAL, 'changed ');
270  const diffDelete = new Diff(DIFF_DELETE, 'from');
271  const diffInsert = new Diff(DIFF_INSERT, 'to');
272  ```
273  
274  ## Usage of diffLinesRaw
275  
276  Given **arrays of strings**, `diffLinesRaw(aLines, bLines)` does the following:
277  
278  - **compare** the arrays line-by-line using the `diff-sequences` package
279  
280  Because `diffLinesRaw` returns the difference as **data** instead of a string, you can format it as your application requires.
281  
282  ### Example of diffLinesRaw
283  
284  ```js
285  const aLines = ['delete', 'common', 'changed from'];
286  const bLines = ['common', 'changed to', 'insert'];
287  
288  const diffs = diffLinesRaw(aLines, bLines);
289  ```
290  
291  | `i` | `diffs[i][0]` | `diffs[i][1]`    |
292  | --: | ------------: | :--------------- |
293  | `0` |          `-1` | `'delete'`       |
294  | `1` |           `0` | `'common'`       |
295  | `2` |          `-1` | `'changed from'` |
296  | `3` |           `1` | `'changed to'`   |
297  | `4` |           `1` | `'insert'`       |
298  
299  ### Edge case of diffLinesRaw
300  
301  If you call `string.split('\n')` for an empty string:
302  
303  - the result is `['']` an array which contains an empty string
304  - instead of `[]` an empty array
305  
306  Depending of your application, you might call `diffLinesRaw` with either array.
307  
308  ### Example of split method
309  
310  ```js
311  import {diffLinesRaw} from 'jest-diff';
312  
313  const a = 'non-empty string';
314  const b = '';
315  
316  const diffs = diffLinesRaw(a.split('\n'), b.split('\n'));
317  ```
318  
319  | `i` | `diffs[i][0]` | `diffs[i][1]`        |
320  | --: | ------------: | :------------------- |
321  | `0` |          `-1` | `'non-empty string'` |
322  | `1` |           `1` | `''`                 |
323  
324  Which you might format as follows:
325  
326  ```diff
327  - Expected  - 1
328  + Received  + 1
329  
330  - non-empty string
331  +
332  ```
333  
334  ### Example of splitLines0 function
335  
336  For edge case behavior like the `diffLinesUnified` function, you might define a `splitLines0` function, which given an empty string, returns `[]` an empty array:
337  
338  ```js
339  export const splitLines0 = string =>
340    string.length === 0 ? [] : string.split('\n');
341  ```
342  
343  ```js
344  import {diffLinesRaw} from 'jest-diff';
345  
346  const a = '';
347  const b = 'line 1\nline 2\nline 3';
348  
349  const diffs = diffLinesRaw(a.split('\n'), b.split('\n'));
350  ```
351  
352  | `i` | `diffs[i][0]` | `diffs[i][1]` |
353  | --: | ------------: | :------------ |
354  | `0` |           `1` | `'line 1'`    |
355  | `1` |           `1` | `'line 2'`    |
356  | `2` |           `1` | `'line 3'`    |
357  
358  Which you might format as follows:
359  
360  ```diff
361  - Expected  - 0
362  + Received  + 3
363  
364  + line 1
365  + line 2
366  + line 3
367  ```
368  
369  In contrast to the `diffLinesRaw` function, the `diffLinesUnified` and `diffLinesUnified2` functions **automatically** convert array arguments computed by string `split` method, so callers do **not** need a `splitLine0` function.
370  
371  ## Options
372  
373  The default options are for the report when an assertion fails from the `expect` package used by Jest.
374  
375  For other applications, you can provide an options object as a third argument:
376  
377  - `diffDefault(a, b, options)`
378  - `diffStringsUnified(a, b, options)`
379  - `diffLinesUnified(aLines, bLines, options)`
380  - `diffLinesUnified2(aLinesDisplay, bLinesDisplay, aLinesCompare, bLinesCompare, options)`
381  
382  ### Properties of options object
383  
384  | name                              | default            |
385  | :-------------------------------- | :----------------- |
386  | `aAnnotation`                     | `'Expected'`       |
387  | `aColor`                          | `chalk.green`      |
388  | `aIndicator`                      | `'-'`              |
389  | `bAnnotation`                     | `'Received'`       |
390  | `bColor`                          | `chalk.red`        |
391  | `bIndicator`                      | `'+'`              |
392  | `changeColor`                     | `chalk.inverse`    |
393  | `changeLineTrailingSpaceColor`    | `string => string` |
394  | `commonColor`                     | `chalk.dim`        |
395  | `commonIndicator`                 | `' '`              |
396  | `commonLineTrailingSpaceColor`    | `string => string` |
397  | `contextLines`                    | `5`                |
398  | `emptyFirstOrLastLinePlaceholder` | `''`               |
399  | `expand`                          | `true`             |
400  | `includeChangeCounts`             | `false`            |
401  | `omitAnnotationLines`             | `false`            |
402  | `patchColor`                      | `chalk.yellow`     |
403  
404  For more information about the options, see the following examples.
405  
406  ### Example of options for labels
407  
408  If the application is code modification, you might replace the labels:
409  
410  ```js
411  const options = {
412    aAnnotation: 'Original',
413    bAnnotation: 'Modified',
414  };
415  ```
416  
417  ```diff
418  - Original
419  + Modified
420  
421    common
422  - changed from
423  + changed to
424  ```
425  
426  The `jest-diff` package does not assume that the 2 labels have equal length.
427  
428  ### Example of options for colors of changed lines
429  
430  For consistency with most diff tools, you might exchange the colors:
431  
432  ```ts
433  import chalk = require('chalk');
434  
435  const options = {
436    aColor: chalk.red,
437    bColor: chalk.green,
438  };
439  ```
440  
441  ### Example of option for color of changed substrings
442  
443  Although the default inverse of foreground and background colors is hard to beat for changed substrings **within lines**, especially because it highlights spaces, if you want bold font weight on yellow background color:
444  
445  ```ts
446  import chalk = require('chalk');
447  
448  const options = {
449    changeColor: chalk.bold.bgYellowBright,
450  };
451  ```
452  
453  ### Example of option to format trailing spaces
454  
455  Because the default export does not display substring differences within lines, formatting can help you see when lines differ by the presence or absence of trailing spaces found by `/\s+$/` regular expression.
456  
457  - If change lines have a background color, then you can see trailing spaces.
458  - If common lines have default dim color, then you cannot see trailing spaces. You might want yellowish background color to see them.
459  
460  ```js
461  const options = {
462    aColor: chalk.rgb(128, 0, 128).bgRgb(255, 215, 255), // magenta
463    bColor: chalk.rgb(0, 95, 0).bgRgb(215, 255, 215), // green
464    commonLineTrailingSpaceColor: chalk.bgYellow,
465  };
466  ```
467  
468  The value of a Color option is a function, which given a string, returns a string.
469  
470  If you want to replace trailing spaces with middle dot characters:
471  
472  ```js
473  const replaceSpacesWithMiddleDot = string => '·'.repeat(string.length);
474  
475  const options = {
476    changeLineTrailingSpaceColor: replaceSpacesWithMiddleDot,
477    commonLineTrailingSpaceColor: replaceSpacesWithMiddleDot,
478  };
479  ```
480  
481  If you need the TypeScript type of a Color option:
482  
483  ```ts
484  import {DiffOptionsColor} from 'jest-diff';
485  ```
486  
487  ### Example of options for no colors
488  
489  To store the difference in a file without escape codes for colors, provide an identity function:
490  
491  ```js
492  const noColor = string => string;
493  
494  const options = {
495    aColor: noColor,
496    bColor: noColor,
497    changeColor: noColor,
498    commonColor: noColor,
499    patchColor: noColor,
500  };
501  ```
502  
503  ### Example of options for indicators
504  
505  For consistency with the `diff` command, you might replace the indicators:
506  
507  ```js
508  const options = {
509    aIndicator: '<',
510    bIndicator: '>',
511  };
512  ```
513  
514  The `jest-diff` package assumes (but does not enforce) that the 3 indicators have equal length.
515  
516  ### Example of options to limit common lines
517  
518  By default, the output includes all common lines.
519  
520  To emphasize the changes, you might limit the number of common “context” lines:
521  
522  ```js
523  const options = {
524    contextLines: 1,
525    expand: false,
526  };
527  ```
528  
529  A patch mark like `@@ -12,7 +12,9 @@` accounts for omitted common lines.
530  
531  ### Example of option for color of patch marks
532  
533  If you want patch marks to have the same dim color as common lines:
534  
535  ```ts
536  import chalk = require('chalk');
537  
538  const options = {
539    expand: false,
540    patchColor: chalk.dim,
541  };
542  ```
543  
544  ### Example of option to include change counts
545  
546  To display the number of changed lines at the right of annotation lines:
547  
548  ```js
549  const a = ['common', 'changed from'];
550  const b = ['common', 'changed to', 'insert'];
551  
552  const options = {
553    includeChangeCounts: true,
554  };
555  
556  const difference = diffDefault(a, b, options);
557  ```
558  
559  ```diff
560  - Expected  - 1
561  + Received  + 2
562  
563    Array [
564      "common",
565  -   "changed from",
566  +   "changed to",
567  +   "insert",
568    ]
569  ```
570  
571  ### Example of option to omit annotation lines
572  
573  To display only the comparison lines:
574  
575  ```js
576  const a = 'common\nchanged from';
577  const b = 'common\nchanged to';
578  
579  const options = {
580    omitAnnotationLines: true,
581  };
582  
583  const difference = diffStringsUnified(a, b, options);
584  ```
585  
586  ```diff
587    common
588  - changed from
589  + changed to
590  ```
591  
592  ### Example of option for empty first or last lines
593  
594  If the **first** or **last** comparison line is **empty**, because the content is empty and the indicator is a space, you might not notice it.
595  
596  The replacement option is a string whose default value is `''` empty string.
597  
598  Because Jest trims the report when a matcher fails, it deletes an empty last line.
599  
600  Therefore, Jest uses as placeholder the downwards arrow with corner leftwards:
601  
602  ```js
603  const options = {
604    emptyFirstOrLastLinePlaceholder: '↵', // U+21B5
605  };
606  ```
607  
608  If a content line is empty, then the corresponding comparison line is automatically trimmed to remove the margin space (represented as a middle dot below) for the default indicators:
609  
610  |         Indicator | untrimmed | trimmed |
611  | ----------------: | :-------- | :------ |
612  |      `aIndicator` | `'-·'`    | `'-'`   |
613  |      `bIndicator` | `'+·'`    | `'+'`   |
614  | `commonIndicator` | `' ·'`    | `''`    |