Security News
ESLint is Now Language-Agnostic: Linting JSON, Markdown, and Beyond
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
jest-diff
Advanced tools
The jest-diff npm package is a utility primarily used to show differences between two values, typically used in testing environments to assert the equality of objects, arrays, or other data structures. It is part of the Jest testing framework but can be used independently for its diffing capabilities.
Diffing two values
This feature allows you to compare two JavaScript objects and outputs a string that visually represents the differences between them. It is useful for debugging and in test assertions to see what exactly differs when a test fails.
const diff = require('jest-diff');
const a = { a: { b: { c: 5 } } };
const b = { a: { b: { c: 6 } } };
console.log(diff(a, b));
Customizing diff output
This feature allows customization of the diff output by passing options. You can specify annotations for the compared values, which helps in making the output more understandable and tailored to specific needs.
const diff = require('jest-diff');
const options = { aAnnotation: 'First', bAnnotation: 'Second' };
const a = [1, 2, 3];
const b = [2, 1, 3];
console.log(diff(a, b, options));
Deep-diff is a library that provides a detailed analysis of differences between any two JavaScript objects. It is more granular than jest-diff as it provides more detailed information about the type of change (edit, delete, add), which can be useful for more complex diffing needs.
The 'diff' package is another popular choice for computing differences between texts. It is not limited to JavaScript objects and can handle strings effectively, making it suitable for applications like text editors or any scenario where text comparison is needed. Unlike jest-diff, it does not provide a structured view for object differences.
Display differences clearly so people can review changes confidently.
The default export serializes JavaScript values, compares them line-by-line, and returns a string which includes comparison lines.
Two named exports compare strings character-by-character:
diffStringsUnified
returns a string.diffStringsRaw
returns an array of Diff
objects.Three named exports compare arrays of strings line-by-line:
diffLinesUnified
and diffLinesUnified2
return a string.diffLinesRaw
returns an array of Diff
objects.To add this package as a dependency of a project, run either of the following commands:
npm install jest-diff
yarn add jest-diff
Given JavaScript values, diffDefault(a, b, options?)
does the following:
pretty-format
packagediff-sequences
packagechalk
packageTo use this function, write either of the following:
const diffDefault = require('jest-diff').default;
in CommonJS modulesimport diffDefault from 'jest-diff';
in ECMAScript modulesconst a = ['delete', 'common', 'changed from'];
const b = ['common', 'changed to', 'insert'];
const difference = diffDefault(a, b);
The returned string consists of:
Expected
lines are green, Received
lines are red, and common lines are dim (by default, see Options)- Expected
+ Received
Array [
- "delete",
"common",
- "changed from",
+ "changed to",
+ "insert",
]
Here are edge cases for the return value:
' 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)'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
packagenull
if either argument is a so-called asymmetric matcher in Jasmine or JestGiven strings, diffStringsUnified(a, b, options?)
does the following:
diff-sequences
packagechalk
packageAlthough the function is mainly for multiline strings, it compares any strings.
Write either of the following:
const {diffStringsUnified} = require('jest-diff');
in CommonJS modulesimport {diffStringsUnified} from 'jest-diff';
in ECMAScript modulesconst a = 'common\nchanged from';
const b = 'common\nchanged to';
const difference = diffStringsUnified(a, b);
The returned string consists of:
from
has white-on-green and to
has white-on-red, which the following example does not show)- Expected
+ Received
common
- changed from
+ changed to
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.
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.
Given arrays of strings, diffLinesUnified(aLines, bLines, options?)
does the following:
diff-sequences
packagechalk
packageYou might call this function when strings have been split into lines and you do not need to see changed substrings within lines.
const aLines = ['delete', 'common', 'changed from'];
const bLines = ['common', 'changed to', 'insert'];
const difference = diffLinesUnified(aLines, bLines);
- Expected
+ Received
- delete
common
- changed from
+ changed to
+ insert
Here are edge cases for arguments and return values:
a
and b
are empty strings: no comparison linesa
is empty string: all comparison lines have bColor
and bIndicator
(see Options)b
is empty string: all comparison lines have aColor
and aIndicator
(see Options)a
and b
are equal non-empty strings: all comparison lines have commonColor
and commonIndicator
(see Options)Given two pairs of arrays of strings, diffLinesUnified2(aLinesDisplay, bLinesDisplay, aLinesCompare, bLinesCompare, options?)
does the following:
Compare
arrays line-by-line using the diff-sequences
packageDisplay
arrays using the chalk
packageJest calls this function to consider lines as common instead of changed if the only difference is indentation.
You might call this function for case insensitive or Unicode equivalence comparison of lines.
import format from 'pretty-format';
const a = {
text: 'Ignore indentation in serialized object',
time: '2019-09-19T12:34:56.000Z',
type: 'CREATE_ITEM',
};
const b = {
payload: {
text: 'Ignore indentation in serialized object',
time: '2019-09-19T12:34:56.000Z',
},
type: 'CREATE_ITEM',
};
const difference = diffLinesUnified2(
// serialize with indentation to display lines
format(a).split('\n'),
format(b).split('\n'),
// serialize without indentation to compare lines
format(a, {indent: 0}).split('\n'),
format(b, {indent: 0}).split('\n'),
);
The text
and time
properties are common, because their only difference is indentation:
- Expected
+ Received
Object {
+ payload: Object {
text: 'Ignore indentation in serialized object',
time: '2019-09-19T12:34:56.000Z',
+ },
type: 'CREATE_ITEM',
}
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.
Given strings and a boolean option, diffStringsRaw(a, b, cleanup)
does the following:
diff-sequences
packageBecause 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).
The returned array describes substrings as instances of the Diff
class, which calling code can access like array tuples:
The value at index 0
is one of the following:
value | named export | description |
---|---|---|
0 | DIFF_EQUAL | in a and in b |
-1 | DIFF_DELETE | in a but not in b |
1 | DIFF_INSERT | in b but not in a |
The value at index 1
is a substring of a
or b
or both.
const diffs = diffStringsRaw('changed from', 'changed to', true);
i | diffs[i][0] | diffs[i][1] |
---|---|---|
0 | 0 | 'changed ' |
1 | -1 | 'from' |
2 | 1 | 'to' |
const diffs = diffStringsRaw('changed from', 'changed to', false);
i | diffs[i][0] | diffs[i][1] |
---|---|---|
0 | 0 | 'changed ' |
1 | -1 | 'fr' |
2 | 1 | 't' |
3 | 0 | 'o' |
4 | -1 | 'm' |
Here are all the named imports that you might need for the diffStringsRaw
function:
const {DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, Diff, diffStringsRaw} = require('jest-diff');
in CommonJS modulesimport {DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, Diff, diffStringsRaw} from 'jest-diff';
in ECMAScript modulesTo write a formatting function, you might need the named constants (and Diff
in TypeScript annotations).
If you write an application-specific cleanup algorithm, then you might need to call the Diff
constructor:
const diffCommon = new Diff(DIFF_EQUAL, 'changed ');
const diffDelete = new Diff(DIFF_DELETE, 'from');
const diffInsert = new Diff(DIFF_INSERT, 'to');
Given arrays of strings, diffLinesRaw(aLines, bLines)
does the following:
diff-sequences
packageBecause diffLinesRaw
returns the difference as data instead of a string, you can format it as your application requires.
const aLines = ['delete', 'common', 'changed from'];
const bLines = ['common', 'changed to', 'insert'];
const diffs = diffLinesRaw(aLines, bLines);
i | diffs[i][0] | diffs[i][1] |
---|---|---|
0 | -1 | 'delete' |
1 | 0 | 'common' |
2 | -1 | 'changed from' |
3 | 1 | 'changed to' |
4 | 1 | 'insert' |
If you call string.split('\n')
for an empty string:
['']
an array which contains an empty string[]
an empty arrayDepending of your application, you might call diffLinesRaw
with either array.
import {diffLinesRaw} from 'jest-diff';
const a = 'non-empty string';
const b = '';
const diffs = diffLinesRaw(a.split('\n'), b.split('\n'));
i | diffs[i][0] | diffs[i][1] |
---|---|---|
0 | -1 | 'non-empty string' |
1 | 1 | '' |
Which you might format as follows:
- Expected - 1
+ Received + 1
- non-empty string
+
For edge case behavior like the diffLinesUnified
function, you might define a splitLines0
function, which given an empty string, returns []
an empty array:
export const splitLines0 = string =>
string.length === 0 ? [] : string.split('\n');
import {diffLinesRaw} from 'jest-diff';
const a = '';
const b = 'line 1\nline 2\nline 3';
const diffs = diffLinesRaw(a.split('\n'), b.split('\n'));
i | diffs[i][0] | diffs[i][1] |
---|---|---|
0 | 1 | 'line 1' |
1 | 1 | 'line 2' |
2 | 1 | 'line 3' |
Which you might format as follows:
- Expected - 0
+ Received + 3
+ line 1
+ line 2
+ line 3
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.
The default options are for the report when an assertion fails from the expect
package used by Jest.
For other applications, you can provide an options object as a third argument:
diffDefault(a, b, options)
diffStringsUnified(a, b, options)
diffLinesUnified(aLines, bLines, options)
diffLinesUnified2(aLinesDisplay, bLinesDisplay, aLinesCompare, bLinesCompare, options)
name | default |
---|---|
aAnnotation | 'Expected' |
aColor | chalk.green |
aIndicator | '-' |
bAnnotation | 'Received' |
bColor | chalk.red |
bIndicator | '+' |
changeColor | chalk.inverse |
changeLineTrailingSpaceColor | string => string |
commonColor | chalk.dim |
commonIndicator | ' ' |
commonLineTrailingSpaceColor | string => string |
contextLines | 5 |
emptyFirstOrLastLinePlaceholder | '' |
expand | true |
includeChangeCounts | false |
omitAnnotationLines | false |
patchColor | chalk.yellow |
For more information about the options, see the following examples.
If the application is code modification, you might replace the labels:
const options = {
aAnnotation: 'Original',
bAnnotation: 'Modified',
};
- Original
+ Modified
common
- changed from
+ changed to
The jest-diff
package does not assume that the 2 labels have equal length.
For consistency with most diff tools, you might exchange the colors:
import chalk = require('chalk');
const options = {
aColor: chalk.red,
bColor: chalk.green,
};
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:
import chalk = require('chalk');
const options = {
changeColor: chalk.bold.bgYellowBright,
};
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.
const options = {
aColor: chalk.rgb(128, 0, 128).bgRgb(255, 215, 255), // magenta
bColor: chalk.rgb(0, 95, 0).bgRgb(215, 255, 215), // green
commonLineTrailingSpaceColor: chalk.bgYellow,
};
The value of a Color option is a function, which given a string, returns a string.
If you want to replace trailing spaces with middle dot characters:
const replaceSpacesWithMiddleDot = string => '·'.repeat(string.length);
const options = {
changeLineTrailingSpaceColor: replaceSpacesWithMiddleDot,
commonLineTrailingSpaceColor: replaceSpacesWithMiddleDot,
};
If you need the TypeScript type of a Color option:
import {DiffOptionsColor} from 'jest-diff';
To store the difference in a file without escape codes for colors, provide an identity function:
const noColor = string => string;
const options = {
aColor: noColor,
bColor: noColor,
changeColor: noColor,
commonColor: noColor,
patchColor: noColor,
};
For consistency with the diff
command, you might replace the indicators:
const options = {
aIndicator: '<',
bIndicator: '>',
};
The jest-diff
package assumes (but does not enforce) that the 3 indicators have equal length.
By default, the output includes all common lines.
To emphasize the changes, you might limit the number of common “context” lines:
const options = {
contextLines: 1,
expand: false,
};
A patch mark like @@ -12,7 +12,9 @@
accounts for omitted common lines.
If you want patch marks to have the same dim color as common lines:
import chalk = require('chalk');
const options = {
expand: false,
patchColor: chalk.dim,
};
To display the number of changed lines at the right of annotation lines:
const a = ['common', 'changed from'];
const b = ['common', 'changed to', 'insert'];
const options = {
includeChangeCounts: true,
};
const difference = diffDefault(a, b, options);
- Expected - 1
+ Received + 2
Array [
"common",
- "changed from",
+ "changed to",
+ "insert",
]
To display only the comparison lines:
const a = 'common\nchanged from';
const b = 'common\nchanged to';
const options = {
omitAnnotationLines: true,
};
const difference = diffStringsUnified(a, b, options);
common
- changed from
+ changed to
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.
The replacement option is a string whose default value is ''
empty string.
Because Jest trims the report when a matcher fails, it deletes an empty last line.
Therefore, Jest uses as placeholder the downwards arrow with corner leftwards:
const options = {
emptyFirstOrLastLinePlaceholder: '↵', // U+21B5
};
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:
Indicator | untrimmed | trimmed |
---|---|---|
aIndicator | '-·' | '-' |
bIndicator | '+·' | '+' |
commonIndicator | ' ·' | '' |
25.1.0
[babel-plugin-jest-hoist]
Show codeframe on static hoisting issues (#8865)[babel-plugin-jest-hoist]
Add BigInt
to ALLOWED_IDENTIFIERS
(#8382)[babel-preset-jest]
Add @babel/plugin-syntax-bigint
(#8382)[expect]
Add BigInt
support to toBeGreaterThan
, toBeGreaterThanOrEqual
, toBeLessThan
and toBeLessThanOrEqual
(#8382)[expect, jest-matcher-utils]
Display change counts in annotation lines (#9035)[expect, jest-snapshot]
Support custom inline snapshot matchers (#9278)[jest-config]
Throw the full error message and stack when a Jest preset is missing a dependency (#8924)[jest-config]
[BREAKING] Set default display name color based on runner (#8689)[jest-config]
Merge preset globals with project globals (#9027)[jest-config]
Support .cjs
config files (#9291)[jest-config]
[BREAKING] Support .mjs
config files (#9431)[jest-core]
Support reporters as default exports (#9161)[jest-core]
Support --findRelatedTests
paths case insensitivity on Windows (#8961)[jest-diff]
Add options for colors and symbols (#8841)[jest-diff]
[BREAKING] Export as ECMAScript module (#8873)[jest-diff]
Add includeChangeCounts
and rename Indicator
options (#8881)[jest-diff]
Add changeColor
and patchColor
options (#8911)[jest-diff]
Add trailingSpaceFormatter
option and replace cyan with commonColor
(#8927)[jest-diff]
Add firstOrLastEmptyLineReplacement
option and export 3 diffLines
functions (#8955)[jest-environment]
Add optional getVmContext
next to runScript
(#9252 & #9428)[jest-environment-jsdom]
Add fakeTimersLolex
(#8925)[jest-environment-node]
Add fakeTimersLolex
(#8925)[jest-environment-node]
Add queueMicrotask
(#9140)[jest-environment-node]
Implement getVmContext
(#9252 & #9428)[@jest/fake-timers]
Add Lolex as implementation of fake timers (#8897)[jest-get-type]
Add BigInt
support. (#8382)[jest-matcher-utils]
Add BigInt
support to ensureNumbers
ensureActualIsNumber
, ensureExpectedIsNumber
(#8382)[jest-matcher-utils]
Ignore highlighting matched asymmetricMatcher in diffs (#9257)[jest-reporters]
Export utils for path formatting (#9162)[jest-reporters]
Provides global coverage thresholds as watermarks for istanbul (#9416)[jest-runner]
Warn if a worker had to be force exited (#8206)[jest-runtime]
[BREAKING] Do not export ScriptTransformer
- it can be imported from @jest/transform
instead (#9256)[jest-runtime]
Use JestEnvironment.getVmContext
and vm.compileFunction
if available to avoid the module wrapper (#9252 & #9428)[jest-snapshot]
Display change counts in annotation lines (#8982)[jest-snapshot]
[BREAKING] Improve report when the matcher has properties (#9104)[jest-snapshot]
Improve colors when snapshots are updatable (#9132)[jest-snapshot]
Ignore indentation for most serialized objects (#9203)[jest-transform]
Create createTranspilingRequire
function for easy transpiling modules (#9194)[jest-transform]
[BREAKING] Return transformed code as a string, do not wrap in vm.Script
(#9253)[@jest/test-result]
Create method to create empty TestResult
(#8867)[jest-worker]
[BREAKING] Return a promise from end()
, resolving with the information whether workers exited gracefully (#8206)[jest-reporters]
Transform file paths into hyperlinks (#8980)[expect]
Display expectedDiff
more carefully in toBeCloseTo
(#8389)[expect]
Avoid incorrect difference for subset when toMatchObject
fails (#9005)[expect]
Consider all RegExp flags for equality (#9167)[expect]
[BREAKING] Consider primitives different from wrappers instantiated with new
(#9167)[expect]
Prevent maintaining RegExp state between multiple tests (#9289)[expect]
Fix subsetEquality false circular reference detection (#9322)[jest-config]
Use half of the available cores when watchAll
mode is enabled (#9117)[jest-config]
Fix Jest multi project runner still cannot handle exactly one project (#8894)[jest-console]
Add missing console.group
calls to NullConsole
(#9024)[jest-core]
Don't include unref'd timers in --detectOpenHandles results (#8941)[jest-core]
Limit number of workers when creating haste maps in projects (#9259)[jest-diff]
Do not inverse format if line consists of one change (#8903)[jest-diff]
Rename some new options and change their default values (#9077)[jest-environment-node]
Fix TextEncoder.encode
not referencing same global Uint8Array
constructor (#9261)[jest-fake-timers]
getTimerCount
will not include cancelled immediates (#8764)[jest-fake-timers]
Support util.promisify
on setTimeout
(#9180)[jest-jasmine2, jest-circus]
Improve error message format for Node's assert.fail (#9262)[jest-leak-detector]
[BREAKING] Use weak-napi
instead of weak
package (#8686)[jest-mock]
Fix for mockReturnValue overriding mockImplementationOnce (#8398)[jest-reporters]
Make node-notifier an optional dependency (#8918)[jest-reporters]
Make all arguments to methods on BaseReporter
optional (#9159)[jest-resolve]
: Set MODULE_NOT_FOUND as error code when module is not resolved from paths (#8487)[jest-resolve-dependencies]
Handle dynamic dependencies correctly even when using module maps (#9303)[jest-snapshot]
Remove only the added newlines in multiline snapshots (#8859)[jest-snapshot]
Distinguish empty string from external snapshot not written (#8880)[jest-snapshot]
[BREAKING] Distinguish empty string from internal snapshot not written (#8898)[jest-snapshot]
[BREAKING] Remove report
method and throw matcher errors (#9049)[jest-snapshot]
Omit irrelevant received
properties when property matchers fail (#9198)[jest-transform]
Properly cache transformed files across tests (#8890)[jest-transform]
Don't fail the test suite when a generated source map is invalid (#9058)[jest-types]
[BREAKING] Use less null | undefined
in config types (#9200)[jest-util]
Allow querying process.domain (#9136)[pretty-format]
Correctly detect memoized elements (#9196)[pretty-format]
Fix pretty-format to respect displayName on forwardRef (#9422)[*]
[BREAKING] Drop support for Node 6 (#8455)[*]
Add Node 12 to CI (#8411)[*]
[BREAKING] Upgrade to Micromatch v4 (#8852)[babel-plugin-jest-hoist]
[BREAKING] Use ESM exports (#8874)[docs]
Add alias and optional boolean value to coverage
CLI Reference (#8996)[docs]
Fix broken link pointing to legacy JS file in "Snapshot Testing".[docs]
Add setupFilesAfterEnv
and jest.setTimeout
example (#8971)[expect]
Test that toStrictEqual
is equivalent to Node's assert.deepStrictEqual
(#9167)[jest]
[BREAKING] Use ESM exports (#8874)[jest-cli]
[BREAKING] Use ESM exports (#8874)[jest-cli]
[BREAKING] Remove re-exports from @jest/core
(#8874)[jest-diff]
Remove the need to export splitLines0
function (#9151)[jest-environment-jsdom]
[BREAKING] Upgrade JSDOM from v11 to v15 (#8851)[jest-haste-map]
Upgrade to fsevents@2
(#9215)[jest-reporters]
[BREAKING] Upgrade Istanbul dependencies, which are used for code coverage (#9192)[jest-util]
[BREAKING] Remove deprecated exports (#8863)[jest-validate]
[BREAKING] Use ESM exports (#8874)[jest-types]
Mark InitialOptions
as Partial
(#8848)[jest-config]
Refactor normalize
to be more type safe (#8848)FAQs
Display differences clearly so people can review changes confidently.
The npm package jest-diff receives a total of 31,758,415 weekly downloads. As such, jest-diff popularity was classified as popular.
We found that jest-diff demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
Security News
Members Hub is conducting large-scale campaigns to artificially boost Discord server metrics, undermining community trust and platform integrity.
Security News
NIST has failed to meet its self-imposed deadline of clearing the NVD's backlog by the end of the fiscal year. Meanwhile, CVE's awaiting analysis have increased by 33% since June.