diff --git a/CHANGELOG.md b/CHANGELOG.md index 0edeb42e11c9..04fa2befe1f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - `[jest-runner]` Warn if a worker had to be force exited ([#8206](https://github.com/facebook/jest/pull/8206)) - `[jest-snapshot]` Display change counts in annotation lines ([#8982](https://github.com/facebook/jest/pull/8982)) - `[jest-snapshot]` [**BREAKING**] Improve report when the matcher has properties ([#9104](https://github.com/facebook/jest/pull/9104)) +- `[jest-snapshot]` Improve colors when snapshots are updatable ([#9132](https://github.com/facebook/jest/pull/9132)) - `[@jest/test-result]` Create method to create empty `TestResult` ([#8867](https://github.com/facebook/jest/pull/8867)) - `[jest-worker]` [**BREAKING**] Return a promise from `end()`, resolving with the information whether workers exited gracefully ([#8206](https://github.com/facebook/jest/pull/8206)) - `[jest-reporters]` Transform file paths into hyperlinks ([#8980](https://github.com/facebook/jest/pull/8980)) diff --git a/packages/jest-snapshot/src/__tests__/__snapshots__/printSnapshot.test.ts.snap b/packages/jest-snapshot/src/__tests__/__snapshots__/printSnapshot.test.ts.snap index 62ab03012dfb..9e0b3a31889b 100644 --- a/packages/jest-snapshot/src/__tests__/__snapshots__/printSnapshot.test.ts.snap +++ b/packages/jest-snapshot/src/__tests__/__snapshots__/printSnapshot.test.ts.snap @@ -27,7 +27,7 @@ Inline snapshot has value: Symbol(is not a string) `; exports[`matcher error toMatchInlineSnapshot Snapshot matchers cannot be used with not 1`] = ` -expect(received).not.toMatchInlineSnapshot(snapshot) +expect(received).not.toMatchInlineSnapshot(snapshot) Matcher error: Snapshot matchers cannot be used with not `; @@ -94,7 +94,7 @@ Inline snapshot has value: 404 `; exports[`matcher error toThrowErrorMatchingInlineSnapshot Snapshot state must be initialized 1`] = ` -expect(received).rejects.toThrowErrorMatchingInlineSnapshot(snapshot) +expect(received).rejects.toThrowErrorMatchingInlineSnapshot(snapshot) Snapshot state must be initialized @@ -151,23 +151,23 @@ Snapshot name: \`with properties 1\` `; exports[`pass false toMatchInlineSnapshot with properties equals true 1`] = ` -expect(received).toMatchInlineSnapshot(properties, snapshot) +expect(received).toMatchInlineSnapshot(properties, snapshot) Snapshot name: \`with properties 1\` -- Snapshot - 1 -+ Received + 1 +- Snapshot - 1 ++ Received + 1 Object { "id": "abcdef", -- "text": "inline snapshot", -+ "text": "received", +- "text": "inline snapshot", ++ "text": "received", "type": "ADD_ITEM", } `; exports[`pass false toMatchSnapshot New snapshot was not written (multi line) 1`] = ` -expect(received).toMatchSnapshot(hint) +expect(received).toMatchSnapshot(hint) Snapshot name: \`New snapshot was not written: (CI) 1\` @@ -176,12 +176,12 @@ New snapshot was not written. The update flag must be explicitly passed to This is likely because this test is run in a continuous integration (CI) environment in which snapshots are not written by default. Received: -"To write or not to write, -that is the question." +"To write or not to write, +that is the question." `; exports[`pass false toMatchSnapshot New snapshot was not written (single line) 1`] = ` -expect(received).toMatchSnapshot(hint) +expect(received).toMatchSnapshot(hint) Snapshot name: \`New snapshot was not written: (CI) 2\` @@ -189,7 +189,7 @@ New snapshot was not written. The update flag must be explicitly passed to This is likely because this test is run in a continuous integration (CI) environment in which snapshots are not written by default. -Received: "Write me if you can!" +Received: "Write me if you can!" `; exports[`pass false toMatchSnapshot with properties equals false isLineDiffable false 1`] = ` @@ -216,28 +216,28 @@ Snapshot name: \`with properties 1\` `; exports[`pass false toMatchSnapshot with properties equals true 1`] = ` -expect(received).toMatchSnapshot(properties, hint) +expect(received).toMatchSnapshot(properties, hint) Snapshot name: \`with properties: change text value 1\` -- Snapshot - 1 -+ Received + 1 +- Snapshot - 1 ++ Received + 1 Object { "id": "abcdef", -- "text": "snapshot", -+ "text": "received", +- "text": "snapshot", ++ "text": "received", "type": "ADD_ITEM", } `; exports[`pass false toThrowErrorMatchingInlineSnapshot with snapshot 1`] = ` -expect(received).toThrowErrorMatchingInlineSnapshot(snapshot) +expect(received).toThrowErrorMatchingInlineSnapshot(snapshot) Snapshot name: \`with snapshot 1\` -Snapshot: "inline snapshot" -Received: "received" +Snapshot: "inline snapshot" +Received: "received" `; exports[`printPropertiesAndReceived omit missing properties 1`] = ` @@ -252,51 +252,51 @@ exports[`printPropertiesAndReceived omit missing properties 1`] = ` `; exports[`printSnapshotAndReceived backtick single line expected and received 1`] = ` -Snapshot: "var foo = \`backtick\`;" -Received: "var foo = tag\`backtick\`;" +Snapshot: "var foo = \`backtick\`;" +Received: "var foo = tag\`backtick\`;" `; exports[`printSnapshotAndReceived empty string expected and received single line 1`] = ` -Snapshot: "" -Received: "single line string" +Snapshot: "" +Received: "single line string" `; exports[`printSnapshotAndReceived empty string received and expected multi line 1`] = ` -- Snapshot - 3 -+ Received + 0 +- Snapshot - 3 ++ Received + 0 -- multi -- line -- string +- multi +- line +- string `; exports[`printSnapshotAndReceived escape backslash in multi line string 1`] = ` -- Snapshot - 1 -+ Received + 2 +- Snapshot - 1 ++ Received + 2 -- Forward / slash and back \\ slash -+ Forward / slash -+ Back \\ slash +- Forward / slash and back \\ slash ++ Forward / slash ++ Back \\ slash `; exports[`printSnapshotAndReceived escape backslash in single line string 1`] = ` -Snapshot: "forward / slash and back \\\\ slash" -Received: "Forward / slash and back \\\\ slash" +Snapshot: "forward / slash and back \\\\ slash" +Received: "Forward / slash and back \\\\ slash" `; exports[`printSnapshotAndReceived escape double quote marks in string 1`] = ` -Snapshot: "What does \\"oobleck\\" mean?" -Received: "What does \\"ewbleck\\" mean?" +Snapshot: "What does \\"oobleck\\" mean?" +Received: "What does \\"ewbleck\\" mean?" `; exports[`printSnapshotAndReceived escape regexp 1`] = ` -Snapshot: /\\\\\\\\\\("\\)/g -Received: /\\\\\\\\\\("\\)/ +Snapshot: /\\\\\\\\\\("\\)/g +Received: /\\\\\\\\\\("\\)/ `; exports[`printSnapshotAndReceived expand false 1`] = ` -- Snapshot - 1 -+ Received + 3 +- Snapshot - 1 ++ Received + 3 @@ -12,7 +12,9 @@ ? "number" @@ -304,16 +304,16 @@ exports[`printSnapshotAndReceived expand false 1`] = ` ? "boolean" : T extends undefined ? "undefined" -- : T extends Function ? "function" : "object"; -+ : T extends Function -+ ? "function" -+ : "object"; +- : T extends Function ? "function" : "object"; ++ : T extends Function ++ ? "function" ++ : "object"; ↵ `; exports[`printSnapshotAndReceived expand true 1`] = ` -- Snapshot - 1 -+ Received + 3 +- Snapshot - 1 ++ Received + 3 type TypeName = T extends string ? "string" : @@ -331,94 +331,94 @@ exports[`printSnapshotAndReceived expand true 1`] = ` ? "boolean" : T extends undefined ? "undefined" -- : T extends Function ? "function" : "object"; -+ : T extends Function -+ ? "function" -+ : "object"; +- : T extends Function ? "function" : "object"; ++ : T extends Function ++ ? "function" ++ : "object"; ↵ `; exports[`printSnapshotAndReceived fallback to line diff 1`] = ` -- Snapshot - 1 -+ Received + 8 - -+ ====================================options===================================== -+ parsers: ["flow", "typescript"] -+ printWidth: 80 -+ | printWidth -+ =====================================input====================================== +- Snapshot - 1 ++ Received + 8 + ++ ====================================options===================================== ++ parsers: ["flow", "typescript"] ++ printWidth: 80 ++ | printWidth ++ =====================================input====================================== [...a, ...b,]; [...a, ...b]; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ -+ =====================================output===================================== +- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++ =====================================output===================================== [...a, ...b]; [...a, ...b]; -+ ================================================================================ ++ ================================================================================ `; exports[`printSnapshotAndReceived has no common after clean up chaff array 1`] = ` -- Snapshot - 2 -+ Received + 2 +- Snapshot - 2 ++ Received + 2 Array [ -- "delete", -- "two", -+ "insert", -+ "2", +- "delete", +- "two", ++ "insert", ++ "2", ] `; exports[`printSnapshotAndReceived has no common after clean up chaff string single line 1`] = ` -Snapshot: "delete" -Received: "insert" +Snapshot: "delete" +Received: "insert" `; exports[`printSnapshotAndReceived isLineDiffable false asymmetric matcher 1`] = ` -Snapshot: null -Received: Object { - "asymmetricMatch": [Function], -} +Snapshot: null +Received: Object { + "asymmetricMatch": [Function], +} `; exports[`printSnapshotAndReceived isLineDiffable false boolean 1`] = ` -Snapshot: true -Received: false +Snapshot: true +Received: false `; exports[`printSnapshotAndReceived isLineDiffable false date 1`] = ` -Snapshot: 2019-09-19T00:00:00.000Z -Received: 2019-09-20T00:00:00.000Z +Snapshot: 2019-09-19T00:00:00.000Z +Received: 2019-09-20T00:00:00.000Z `; exports[`printSnapshotAndReceived isLineDiffable false error 1`] = ` -Snapshot: [Error: Cannot spread fragment "NameAndAppearances" within itself.] -Received: [Error: Cannot spread fragment "NameAndAppearancesAndFriends" within itself.] +Snapshot: [Error: Cannot spread fragment "NameAndAppearances" within itself.] +Received: [Error: Cannot spread fragment "NameAndAppearancesAndFriends" within itself.] `; exports[`printSnapshotAndReceived isLineDiffable false function 1`] = ` -Snapshot: undefined -Received: [Function] +Snapshot: undefined +Received: [Function] `; exports[`printSnapshotAndReceived isLineDiffable false number 1`] = ` -Snapshot: -0 -Received: NaN +Snapshot: -0 +Received: NaN `; exports[`printSnapshotAndReceived isLineDiffable true array 1`] = ` -- Snapshot - 0 -+ Received + 2 +- Snapshot - 0 ++ Received + 2 Array [ Object { -+ "_id": "b14680dec683e744ada1f2fe08614086", ++ "_id": "b14680dec683e744ada1f2fe08614086", "code": 4011, "weight": 2.13, }, Object { -+ "_id": "7fc63ff01769c4fa7d9279e97e307829", ++ "_id": "7fc63ff01769c4fa7d9279e97e307829", "code": 4019, "count": 4, }, @@ -426,112 +426,112 @@ exports[`printSnapshotAndReceived isLineDiffable true array 1`] = ` `; exports[`printSnapshotAndReceived isLineDiffable true object 1`] = ` -- Snapshot - 2 -+ Received + 3 +- Snapshot - 2 ++ Received + 3 Object { "props": Object { -- "className": "logo", -- "src": "/img/jest.png", -+ "alt": "Jest logo", -+ "class": "logo", -+ "src": "/img/jest.svg", +- "className": "logo", +- "src": "/img/jest.png", ++ "alt": "Jest logo", ++ "class": "logo", ++ "src": "/img/jest.svg", }, "type": "img", } `; exports[`printSnapshotAndReceived isLineDiffable true single line expected and multi line received 1`] = ` -- Snapshot - 1 -+ Received + 3 +- Snapshot - 1 ++ Received + 3 -- Array [] -+ Array [ -+ 0, -+ ] +- Array [] ++ Array [ ++ 0, ++ ] `; exports[`printSnapshotAndReceived isLineDiffable true single line expected and received 1`] = ` -- Snapshot - 1 -+ Received + 1 +- Snapshot - 1 ++ Received + 1 -- Array [] -+ Object {} +- Array [] ++ Object {} `; exports[`printSnapshotAndReceived multi line small change in one line and other is unchanged 1`] = ` -- Snapshot - 1 -+ Received + 1 +- Snapshot - 1 ++ Received + 1 -- There is no route defined for key 'Settings'. -+ There is no route defined for key Settings. +- There is no route defined for key 'Settings'. ++ There is no route defined for key Settings. Must be one of: 'Home' `; exports[`printSnapshotAndReceived multi line small changes 1`] = ` -- Snapshot - 7 -+ Received + 7 - -- 69 | -+ 68 | -- 70 | test('assert.doesNotThrow', () => { -+ 69 | test('assert.doesNotThrow', () => { -- > 71 | assert.doesNotThrow(() => { -+ > 70 | assert.doesNotThrow(() => { +- Snapshot - 7 ++ Received + 7 + +- 69 | ++ 68 | +- 70 | test('assert.doesNotThrow', () => { ++ 69 | test('assert.doesNotThrow', () => { +- > 71 | assert.doesNotThrow(() => { ++ > 70 | assert.doesNotThrow(() => { | ^ -- 72 | throw Error('err!'); -+ 71 | throw Error('err!'); -- 73 | }); -+ 72 | }); -- 74 | }); -+ 73 | }); -- at Object.doesNotThrow (__tests__/assertionError.test.js:71:10) -+ at Object.doesNotThrow (__tests__/assertionError.test.js:70:10) +- 72 | throw Error('err!'); ++ 71 | throw Error('err!'); +- 73 | }); ++ 72 | }); +- 74 | }); ++ 73 | }); +- at Object.doesNotThrow (__tests__/assertionError.test.js:71:10) ++ at Object.doesNotThrow (__tests__/assertionError.test.js:70:10) `; exports[`printSnapshotAndReceived single line large changes 1`] = ` -Snapshot: "Array length must be a finite positive integer" -Received: "Invalid array length" +Snapshot: "Array length must be a finite positive integer" +Received: "Invalid array length" `; exports[`printSnapshotAndReceived without serialize backtick single line expected and multi line received 1`] = ` -- Snapshot - 1 -+ Received + 2 +- Snapshot - 1 ++ Received + 2 -- var foo = \`backtick\`; -+ var foo = \`back -+ tick\`; +- var foo = \`backtick\`; ++ var foo = \`back ++ tick\`; `; exports[`printSnapshotAndReceived without serialize backtick single line expected and received 1`] = ` -- Snapshot - 1 -+ Received + 1 +- Snapshot - 1 ++ Received + 1 -- var foo = \`backtick\`; -+ var foo = \`back\${x}tick\`; +- var foo = \`backtick\`; ++ var foo = \`back\${x}tick\`; `; exports[`printSnapshotAndReceived without serialize has no common after clean up chaff multi line 1`] = ` -- Snapshot - 2 -+ Received + 2 +- Snapshot - 2 ++ Received + 2 -- delete -- two -+ insert -+ 2 +- delete +- two ++ insert ++ 2 `; exports[`printSnapshotAndReceived without serialize has no common after clean up chaff single line 1`] = ` -- Snapshot - 1 -+ Received + 1 +- Snapshot - 1 ++ Received + 1 -- delete -+ insert +- delete ++ insert `; exports[`printSnapshotAndReceived without serialize prettier/pull/5590 1`] = ` -- Snapshot - 1 -+ Received + 1 +- Snapshot - 1 ++ Received + 1 @@ -4,8 +4,8 @@ | printWidth @@ -539,8 +539,8 @@ exports[`printSnapshotAndReceived without serialize prettier/pull/5590 1`] = ` John "ShotGun" Nelson =====================================output===================================== -- <i"John "ShotGun" Nelson" /> -+ <i'John "ShotGun" Nelson' /> +- <i"John "ShotGun" Nelson" /> ++ <i'John "ShotGun" Nelson' /> ================================================================================ `; diff --git a/packages/jest-snapshot/src/__tests__/printSnapshot.test.ts b/packages/jest-snapshot/src/__tests__/printSnapshot.test.ts index b3bcab6d85df..97858fdbeb13 100644 --- a/packages/jest-snapshot/src/__tests__/printSnapshot.test.ts +++ b/packages/jest-snapshot/src/__tests__/printSnapshot.test.ts @@ -12,13 +12,60 @@ import format = require('pretty-format'); import jestSnapshot = require('../index'); import { + getReceivedColorForChalkInstance, + getSnapshotColorForChalkInstance, + noColor, printPropertiesAndReceived, printSnapshotAndReceived, } from '../printSnapshot'; import {serialize} from '../utils'; - -const convertAnsi = (val: string): string => - val.replace(ansiRegex(), match => { +import { + aBackground2, + aBackground3, + aForeground2, + aForeground3, + bBackground2, + bBackground3, + bForeground2, + bForeground3, +} from '../colors'; + +const aOpenForeground1 = styles.magenta.open; +const aOpenBackground1 = styles.bgYellowBright.open; +const bOpenForeground1 = styles.cyan.open; +const bOpenBackground1 = styles.bgWhiteBright.open; + +const aOpenForeground2 = styles.color.ansi256.ansi256(aForeground2); +const bOpenForeground2 = styles.color.ansi256.ansi256(bForeground2); +const aOpenBackground2 = styles.bgColor.ansi256.ansi256(aBackground2); +const bOpenBackground2 = styles.bgColor.ansi256.ansi256(bBackground2); + +const aOpenForeground3 = styles.color.ansi16m.rgb( + aForeground3[0], + aForeground3[1], + aForeground3[2], +); +const bOpenForeground3 = styles.color.ansi16m.rgb( + bForeground3[0], + bForeground3[1], + bForeground3[2], +); +const aOpenBackground3 = styles.bgColor.ansi16m.rgb( + aBackground3[0], + aBackground3[1], + aBackground3[2], +); +const bOpenBackground3 = styles.bgColor.ansi16m.rgb( + bBackground3[0], + bBackground3[1], + bBackground3[2], +); + +const convertAnsi = (val: string): string => { + // Trailing spaces in common lines have yellow background color. + let isYellowBackground = false; + + return val.replace(ansiRegex(), match => { switch (match) { case styles.inverse.open: return ''; @@ -29,27 +76,53 @@ const convertAnsi = (val: string): string => return ''; case styles.dim.open: return ''; + case styles.bold.close: + case styles.dim.close: + return ''; + case styles.green.open: return ''; + case aOpenForeground1: + case aOpenForeground2: + case aOpenForeground3: + return ''; case styles.red.open: return ''; + case bOpenForeground1: + case bOpenForeground2: + case bOpenForeground3: + return ''; // teal/cyan/aqua case styles.yellow.open: return ''; - case styles.bgYellow.open: - return ''; - - case styles.bold.close: - case styles.dim.close: + case styles.cyan.close: case styles.green.close: + case styles.magenta.close: case styles.red.close: case styles.yellow.close: - case styles.bgYellow.close: return ''; + case styles.bgYellow.open: + isYellowBackground = true; + return ''; + + case aOpenBackground1: + case bOpenBackground1: + case aOpenBackground2: + case bOpenBackground2: + case aOpenBackground3: + case bOpenBackground3: + isYellowBackground = false; + return ''; + + case styles.bgYellow.close: + // The same code closes any background color. + return isYellowBackground ? '' : ''; + default: return match; } }); +}; expect.addSnapshotSerializer({ serialize(val: string): string { @@ -67,6 +140,77 @@ const { toThrowErrorMatchingSnapshot, } = jestSnapshot; +describe('chalk', () => { + // Because these tests give code coverage of get functions + // and give confidence that the escape sequences are correct, + // convertAnsi can return same serialization for any chalk level + // so snapshot tests pass in any environment with chalk level >= 1. + + // Simulate comparison lines from printSnapshotAndReceived. + const formatLines = chalkInstance => { + const aColor = getSnapshotColorForChalkInstance(chalkInstance); + const bColor = getReceivedColorForChalkInstance(chalkInstance); + const cColor = chalkInstance.dim; + const changeLineTrailingSpaceColor = noColor; + const commonLineTrailingSpaceColor = chalkInstance.bgYellow; + + return [ + aColor(`- delete 1${changeLineTrailingSpaceColor(' ')}`), + cColor(` common 2${commonLineTrailingSpaceColor(' ')}`), + bColor(`+ insert 0`), + ].join('\n'); + }; + + const expected0 = '- delete 1 \n common 2 \n+ insert 0'; + const expected1 = + '- delete 1 \n common 2 \n+ insert 0'; + + test('level 0', () => { + const chalkInstance = new chalk.Instance({level: 0}); + const formatted = formatLines(chalkInstance); + const converted = convertAnsi(formatted); + + expect(converted).toBe(expected0); + expect(formatted).toBe(expected0); + }); + + test('level 1', () => { + const chalkInstance = new chalk.Instance({level: 1}); + const formatted = formatLines(chalkInstance); + const converted = convertAnsi(formatted); + + expect(converted).toBe(expected1); + expect(formatted).toMatch(aOpenForeground1 + aOpenBackground1 + '-'); + expect(formatted).toMatch(bOpenForeground1 + bOpenBackground1 + '+'); + expect(formatted).not.toMatch(chalkInstance.bgYellow(' ')); // noColor + expect(formatted).toMatch(chalkInstance.bgYellow(' ')); + }); + + test('level 2', () => { + const chalkInstance = new chalk.Instance({level: 2}); + const formatted = formatLines(chalkInstance); + const converted = convertAnsi(formatted); + + expect(converted).toBe(expected1); + expect(formatted).toMatch(aOpenForeground2 + aOpenBackground2 + '-'); + expect(formatted).toMatch(bOpenForeground2 + bOpenBackground2 + '+'); + expect(formatted).not.toMatch(chalkInstance.bgYellow(' ')); // noColor + expect(formatted).toMatch(chalkInstance.bgYellow(' ')); + }); + + test('level 3', () => { + const chalkInstance = new chalk.Instance({level: 3}); + const formatted = formatLines(chalkInstance); + const converted = convertAnsi(formatted); + + expect(converted).toBe(expected1); + expect(formatted).toMatch(aOpenForeground3 + aOpenBackground3 + '-'); + expect(formatted).toMatch(bOpenForeground3 + bOpenBackground3 + '+'); + expect(formatted).not.toMatch(chalkInstance.bgYellow(' ')); // noColor + expect(formatted).toMatch(chalkInstance.bgYellow(' ')); + }); +}); + describe('matcher error', () => { describe('toMatchInlineSnapshot', () => { const received = { diff --git a/packages/jest-snapshot/src/colors.ts b/packages/jest-snapshot/src/colors.ts new file mode 100644 index 000000000000..5f62153568d9 --- /dev/null +++ b/packages/jest-snapshot/src/colors.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// https://jonasjacek.github.io/colors/ + +export const aForeground2 = 90; +export const aBackground2 = 225; + +export const bForeground2 = 23; +export const bBackground2 = 195; + +export type RGB = [number, number, number]; + +export const aForeground3: RGB = [0x80, 0, 0x80]; +export const aBackground3: RGB = [0xff, 0xd7, 0xff]; + +export const bForeground3: RGB = [0, 0x5f, 0x5f]; +export const bBackground3: RGB = [0xd7, 0xff, 0xff]; diff --git a/packages/jest-snapshot/src/index.ts b/packages/jest-snapshot/src/index.ts index 33b5c9176429..1fbabce0fc22 100644 --- a/packages/jest-snapshot/src/index.ts +++ b/packages/jest-snapshot/src/index.ts @@ -30,6 +30,7 @@ import {addSerializer, getSerializers} from './plugins'; import { PROPERTIES_ARG, SNAPSHOT_ARG, + bReceivedColor, matcherHintFromConfig, noColor, printExpected, @@ -384,7 +385,7 @@ const _toMatchSnapshot = (config: MatchSnapshotConfig) => { `must be explicitly passed to write a new snapshot.\n\n` + `This is likely because this test is run in a continuous integration ` + `(CI) environment in which snapshots are not written by default.\n\n` + - `Received:${actual.includes('\n') ? '\n' : ' '}${RECEIVED_COLOR( + `Received:${actual.includes('\n') ? '\n' : ' '}${bReceivedColor( actual, )}` : () => diff --git a/packages/jest-snapshot/src/printSnapshot.ts b/packages/jest-snapshot/src/printSnapshot.ts index 8ba097570f5c..4b7bbb80a9a1 100644 --- a/packages/jest-snapshot/src/printSnapshot.ts +++ b/packages/jest-snapshot/src/printSnapshot.ts @@ -15,6 +15,7 @@ import { DIFF_EQUAL, DIFF_INSERT, Diff, + DiffOptionsColor, diffLinesUnified, diffStringsRaw, diffStringsUnified, @@ -30,9 +31,61 @@ import { matcherHint, } from 'jest-matcher-utils'; import prettyFormat = require('pretty-format'); + +import { + aBackground2, + aBackground3, + aForeground2, + aForeground3, + bBackground2, + bBackground3, + bForeground2, + bForeground3, +} from './colors'; import {MatchSnapshotConfig} from './types'; import {deserializeString, minify, serialize} from './utils'; +type Chalk = chalk.Chalk; + +export const getSnapshotColorForChalkInstance = ( + chalkInstance: Chalk, +): DiffOptionsColor => { + const level = chalkInstance.level; + + if (level === 3) { + return chalkInstance + .rgb(aForeground3[0], aForeground3[1], aForeground3[2]) + .bgRgb(aBackground3[0], aBackground3[1], aBackground3[2]); + } + + if (level === 2) { + return chalkInstance.ansi256(aForeground2).bgAnsi256(aBackground2); + } + + return chalkInstance.magenta.bgYellowBright; +}; + +export const getReceivedColorForChalkInstance = ( + chalkInstance: Chalk, +): DiffOptionsColor => { + const level = chalkInstance.level; + + if (level === 3) { + return chalkInstance + .rgb(bForeground3[0], bForeground3[1], bForeground3[2]) + .bgRgb(bBackground3[0], bBackground3[1], bBackground3[2]); + } + + if (level === 2) { + return chalkInstance.ansi256(bForeground2).bgAnsi256(bBackground2); + } + + return chalkInstance.cyan.bgWhiteBright; // also known as teal +}; + +export const aSnapshotColor = getSnapshotColorForChalkInstance(chalk); +export const bReceivedColor = getReceivedColorForChalkInstance(chalk); + export const noColor = (string: string) => string; export const HINT_ARG = 'hint'; @@ -50,6 +103,9 @@ export const matcherHintFromConfig = ( isUpdatable: boolean, ): string => { const options: MatcherHintOptions = {isNot, promise}; + if (isUpdatable) { + options.receivedColor = bReceivedColor; + } let expectedArgument = ''; @@ -64,7 +120,9 @@ export const matcherHintFromConfig = ( options.secondArgumentColor = BOLD_WEIGHT; } else if (typeof inlineSnapshot === 'string') { options.secondArgument = SNAPSHOT_ARG; - if (!isUpdatable) { + if (isUpdatable) { + options.secondArgumentColor = aSnapshotColor; + } else { options.secondArgumentColor = noColor; } } @@ -74,8 +132,8 @@ export const matcherHintFromConfig = ( options.expectedColor = BOLD_WEIGHT; } else if (typeof inlineSnapshot === 'string') { expectedArgument = SNAPSHOT_ARG; - if (!isUpdatable) { - options.expectedColor = noColor; + if (isUpdatable) { + options.expectedColor = aSnapshotColor; } } } @@ -184,14 +242,14 @@ export const printSnapshotAndReceived = ( ): string => { const aAnnotation = 'Snapshot'; const bAnnotation = 'Received'; - const aColor = EXPECTED_COLOR; - const bColor = RECEIVED_COLOR; + const aColor = aSnapshotColor; + const bColor = bReceivedColor; const options = { aAnnotation, aColor, bAnnotation, bColor, - changeLineTrailingSpaceColor: chalk.bgYellow, + changeLineTrailingSpaceColor: noColor, commonLineTrailingSpaceColor: chalk.bgYellow, emptyFirstOrLastLinePlaceholder: '↵', // U+21B5 expand,