From a4dc6bda52d433293b89aadd1ccae018b40c25dd Mon Sep 17 00:00:00 2001 From: Dmitrii Abramov Date: Tue, 28 Mar 2017 19:21:26 -0700 Subject: [PATCH 1/8] node `assert` snapshot tests --- .../__snapshots__/failures-test.js.snap | 70 +++++++++++++++++++ integration_tests/__tests__/failures-test.js | 7 ++ .../__tests__/node-assertion-error-test.js | 45 ++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 integration_tests/failures/__tests__/node-assertion-error-test.js diff --git a/integration_tests/__tests__/__snapshots__/failures-test.js.snap b/integration_tests/__tests__/__snapshots__/failures-test.js.snap index 6f79bb9b56cf..2a33d89ecfa1 100644 --- a/integration_tests/__tests__/__snapshots__/failures-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/failures-test.js.snap @@ -103,3 +103,73 @@ Ran all test suites matching \\"assertion-count-test.js\\". ", } `; + +exports[`works with node assert 1`] = ` +Object { + "rest": " FAIL __tests__/node-assertion-error-test.js + ● assert + + AssertionError: false == true + + at Object.test (__tests__/node-assertion-error-test.js:16:3) + + ● assert with a message + + AssertionError: this is a message + + at Object.test (__tests__/node-assertion-error-test.js:20:3) + + ● assert.ok + + AssertionError: false == true + + at Object.test (__tests__/node-assertion-error-test.js:24:10) + + ● assert.ok with a message + + AssertionError: this is a message + + at Object.test (__tests__/node-assertion-error-test.js:28:10) + + ● assert.equal + + AssertionError: 1 == 2 + + at Object.test (__tests__/node-assertion-error-test.js:32:10) + + ● assert.equal with a message + + AssertionError: this is a message + + at Object.test (__tests__/node-assertion-error-test.js:36:10) + + ● assert.deepEqual + + AssertionError: { a: { b: { c: 5 } } } deepEqual { a: { b: { c: 6 } } } + + at Object.test (__tests__/node-assertion-error-test.js:40:10) + + ● assert.deepEqual with a message + + AssertionError: this is a message + + at Object.test (__tests__/node-assertion-error-test.js:44:10) + + ✕ assert + ✕ assert with a message + ✕ assert.ok + ✕ assert.ok with a message + ✕ assert.equal + ✕ assert.equal with a message + ✕ assert.deepEqual + ✕ assert.deepEqual with a message + +", + "summary": "Test Suites: 1 failed, 1 total +Tests: 8 failed, 8 total +Snapshots: 0 total +Time: <> +Ran all test suites matching \\"node-assertion-error-test.js\\". +", +} +`; diff --git a/integration_tests/__tests__/failures-test.js b/integration_tests/__tests__/failures-test.js index 173bed6d0ce5..fad83070c24d 100644 --- a/integration_tests/__tests__/failures-test.js +++ b/integration_tests/__tests__/failures-test.js @@ -44,3 +44,10 @@ test('throwing not Error objects', () => { extractSummary(stderr), )).toMatchSnapshot(); }); + +test('works with node assert', () => { + const {stderr} = runJest(dir, ['node-assertion-error-test.js']); + expect(stripInconsistentStackLines( + extractSummary(stderr), + )).toMatchSnapshot(); +}); diff --git a/integration_tests/failures/__tests__/node-assertion-error-test.js b/integration_tests/failures/__tests__/node-assertion-error-test.js new file mode 100644 index 000000000000..11153f0e111f --- /dev/null +++ b/integration_tests/failures/__tests__/node-assertion-error-test.js @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @emails oncall+jsinfra + */ + +'use strict'; + +const assert = require('assert'); + +test('assert', () => { + assert(false); +}); + +test('assert with a message', () => { + assert(false, 'this is a message'); +}); + +test('assert.ok', () => { + assert.ok(false); +}); + +test('assert.ok with a message', () => { + assert.ok(false, 'this is a message'); +}); + +test('assert.equal', () => { + assert.equal(1, 2); +}); + +test('assert.equal with a message', () => { + assert.equal(1, 2, 'this is a message'); +}); + +test('assert.deepEqual', () => { + assert.deepEqual({a: {b: {c: 5}}}, {a: {b: {c: 6}}}); +}); + +test('assert.deepEqual with a message', () => { + assert.deepEqual({a: {b: {c: 5}}}, {a: {b: {c: 7}}}, 'this is a message'); +}); From d413b63fd8d1190d2cd15f073d48efb71808b7de Mon Sep 17 00:00:00 2001 From: "Kent C. Dodds" Date: Tue, 28 Mar 2017 07:09:12 -0600 Subject: [PATCH 2/8] WIP: getting close to a working version --- .../__snapshots__/failures-test.js.snap | 98 +++++++++++++------ packages/jest-jasmine2/package.json | 1 + packages/jest-jasmine2/src/jasmine/Spec.js | 24 ++++- 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/integration_tests/__tests__/__snapshots__/failures-test.js.snap b/integration_tests/__tests__/__snapshots__/failures-test.js.snap index 2a33d89ecfa1..a394cc634b05 100644 --- a/integration_tests/__tests__/__snapshots__/failures-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/failures-test.js.snap @@ -57,12 +57,11 @@ Object { "rest": " FAIL __tests__/assertion-count-test.js ● .assertions() › throws - expect(received).toBeTruthy() - - Expected value to be truthy, instead received - false + Error + Error: expect(received).toBeTruthy() - at Object.throws (__tests__/assertion-count-test.js:14:17) + Expected value to be truthy, instead received + false ● .assertions() › throws @@ -74,12 +73,11 @@ Object { ● .assertions() › throws on redeclare of assertion count - expect(received).toBeTruthy() - - Expected value to be truthy, instead received - false + Error + Error: expect(received).toBeTruthy() - at Object.redeclare (__tests__/assertion-count-test.js:18:17) + Expected value to be truthy, instead received + false ● .assertions() › throws on assertion @@ -109,51 +107,91 @@ Object { "rest": " FAIL __tests__/node-assertion-error-test.js ● assert - AssertionError: false == true - - at Object.test (__tests__/node-assertion-error-test.js:16:3) + Error + AssertionError: false == true ● assert with a message - AssertionError: this is a message - - at Object.test (__tests__/node-assertion-error-test.js:20:3) + Error + AssertionError: this is a message ● assert.ok - AssertionError: false == true - - at Object.test (__tests__/node-assertion-error-test.js:24:10) + Error + AssertionError: false == true ● assert.ok with a message - AssertionError: this is a message - - at Object.test (__tests__/node-assertion-error-test.js:28:10) + Error + AssertionError: this is a message ● assert.equal - AssertionError: 1 == 2 + Error + expect(received).toBe(expected) - at Object.test (__tests__/node-assertion-error-test.js:32:10) + Expected value to be (using ===): + 2 + Received: + 1 ● assert.equal with a message - AssertionError: this is a message + Error + expect(received).toBe(expected) - at Object.test (__tests__/node-assertion-error-test.js:36:10) + Expected value to be (using ===): + 2 + Received: + 1 ● assert.deepEqual - AssertionError: { a: { b: { c: 5 } } } deepEqual { a: { b: { c: 6 } } } + Error + expect(received).toBe(expected) + + Expected value to be (using ===): + {\\"a\\": {\\"b\\": {\\"c\\": 6}}} + Received: + {\\"a\\": {\\"b\\": {\\"c\\": 5}}} + + Difference: - at Object.test (__tests__/node-assertion-error-test.js:40:10) + - Expected + + Received + + Object { + \\"a\\": Object { + \\"b\\": Object { + - \\"c\\": 6, + + \\"c\\": 5, + }, + }, + } ● assert.deepEqual with a message - AssertionError: this is a message + Error + expect(received).toBe(expected) + + Expected value to be (using ===): + {\\"a\\": {\\"b\\": {\\"c\\": 7}}} + Received: + {\\"a\\": {\\"b\\": {\\"c\\": 5}}} + + Difference: + + - Expected + + Received - at Object.test (__tests__/node-assertion-error-test.js:44:10) + Object { + \\"a\\": Object { + \\"b\\": Object { + - \\"c\\": 7, + + \\"c\\": 5, + }, + }, + } ✕ assert ✕ assert with a message diff --git a/packages/jest-jasmine2/package.json b/packages/jest-jasmine2/package.json index a4220b2f6ea2..b215c928a86c 100644 --- a/packages/jest-jasmine2/package.json +++ b/packages/jest-jasmine2/package.json @@ -9,6 +9,7 @@ "main": "build/index.js", "dependencies": { "graceful-fs": "^4.1.11", + "jest-diff": "^19.0.0", "jest-matcher-utils": "^19.0.0", "jest-matchers": "^19.0.0", "jest-message-util": "^19.0.0", diff --git a/packages/jest-jasmine2/src/jasmine/Spec.js b/packages/jest-jasmine2/src/jasmine/Spec.js index e9403e869547..b70f45767ea6 100644 --- a/packages/jest-jasmine2/src/jasmine/Spec.js +++ b/packages/jest-jasmine2/src/jasmine/Spec.js @@ -32,6 +32,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; +const diff = require('jest-diff'); +const { + matcherHint, + printReceived, + printExpected, +} = require('jest-matcher-utils'); const ExpectationFailed = require('../ExpectationFailed'); const expectationResultFactory = require('../expectationResultFactory'); @@ -121,10 +127,26 @@ Spec.prototype.onException = function onException(e) { return; } + const {expected, actual} = e || {}; + let message; + if (expected && actual) { + const diffString = diff(expected, actual, { + expand: this.expand, + }); + message = matcherHint('.toBe') + + '\n\n' + + `Expected value to be (using ===):\n` + + ` ${printExpected(expected)}\n` + + `Received:\n` + + ` ${printReceived(actual)}` + + (diffString ? `\n\nDifference:\n\n${diffString}` : ''); + } + this.addExpectationResult( false, { - matcherName: '', + matcherName: 'blah', + message, passed: false, expected: '', actual: '', From 90497d53bee817f93ffdf321dac80b6729a1fdde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 6 Apr 2017 10:43:03 +0200 Subject: [PATCH 3/8] Refactor assert error messages --- .../__snapshots__/failures-test.js.snap | 284 ++++++++++++++---- integration_tests/__tests__/failures-test.js | 20 +- .../__tests__/node-assertion-error-test.js | 36 ++- packages/jest-jasmine2/src/jasmine/Spec.js | 35 +-- packages/jest-matchers/src/assert-support.js | 72 +++++ 5 files changed, 338 insertions(+), 109 deletions(-) create mode 100644 packages/jest-matchers/src/assert-support.js diff --git a/integration_tests/__tests__/__snapshots__/failures-test.js.snap b/integration_tests/__tests__/__snapshots__/failures-test.js.snap index a394cc634b05..d4d99f1df6b8 100644 --- a/integration_tests/__tests__/__snapshots__/failures-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/failures-test.js.snap @@ -57,11 +57,12 @@ Object { "rest": " FAIL __tests__/assertion-count-test.js ● .assertions() › throws - Error - Error: expect(received).toBeTruthy() + expect(received).toBeTruthy() + + Expected value to be truthy, instead received + false - Expected value to be truthy, instead received - false + at Object.throws (__tests__/assertion-count-test.js:14:17) ● .assertions() › throws @@ -73,11 +74,12 @@ Object { ● .assertions() › throws on redeclare of assertion count - Error - Error: expect(received).toBeTruthy() + expect(received).toBeTruthy() + + Expected value to be truthy, instead received + false - Expected value to be truthy, instead received - false + at Object.redeclare (__tests__/assertion-count-test.js:18:17) ● .assertions() › throws on assertion @@ -107,104 +109,254 @@ Object { "rest": " FAIL __tests__/node-assertion-error-test.js ● assert - Error - AssertionError: false == true + assert.equal(received, expected) or assert(received) + + Expected value to be (operator: ==): + true + Received: + false + + at Object..test (__tests__/node-assertion-error-test.js:16:3) ● assert with a message - Error - AssertionError: this is a message + assert.equal(received, expected) or assert(received) + + Expected value to be (operator: ==): + true + Received: + false + + Message: + this is a message + + at Object..test (__tests__/node-assertion-error-test.js:20:3) ● assert.ok - Error - AssertionError: false == true + assert.equal(received, expected) or assert(received) + + Expected value to be (operator: ==): + true + Received: + false + + at Object..test (__tests__/node-assertion-error-test.js:24:10) ● assert.ok with a message - Error - AssertionError: this is a message + assert.equal(received, expected) or assert(received) + + Expected value to be (operator: ==): + true + Received: + false + + Message: + this is a message + + at Object..test (__tests__/node-assertion-error-test.js:28:10) ● assert.equal - Error - expect(received).toBe(expected) + assert.equal(received, expected) or assert(received) + + Expected value to be (operator: ==): + 2 + Received: + 1 - Expected value to be (using ===): - 2 - Received: - 1 + at Object..test (__tests__/node-assertion-error-test.js:32:10) - ● assert.equal with a message + ● assert.notEqual - Error - expect(received).toBe(expected) + assert.notEqual(received, expected) + + Expected value not to be (operator: !=): + 1 + Received: + 1 + + Difference: + + Compared values have no visual difference. - Expected value to be (using ===): - 2 - Received: - 1 + at Object..test (__tests__/node-assertion-error-test.js:36:10) ● assert.deepEqual - Error - expect(received).toBe(expected) + assert.deepEqual(received, expected) + + Expected value to deepEqual to: + {\\"a\\": {\\"b\\": {\\"c\\": 6}}} + Received: + {\\"a\\": {\\"b\\": {\\"c\\": 5}}} + + Difference: + + - Expected + + Received + + Object { + \\"a\\": Object { + \\"b\\": Object { + - \\"c\\": 6, + + \\"c\\": 5, + }, + }, + } + + at Object..test (__tests__/node-assertion-error-test.js:40:10) + + ● assert.deepEqual with a message + + assert.deepEqual(received, expected) + + Expected value to deepEqual to: + {\\"a\\": {\\"b\\": {\\"c\\": 7}}} + Received: + {\\"a\\": {\\"b\\": {\\"c\\": 5}}} + + Message: + this is a message + + Difference: + + - Expected + + Received + + Object { + \\"a\\": Object { + \\"b\\": Object { + - \\"c\\": 7, + + \\"c\\": 5, + }, + }, + } - Expected value to be (using ===): - {\\"a\\": {\\"b\\": {\\"c\\": 6}}} - Received: - {\\"a\\": {\\"b\\": {\\"c\\": 5}}} + at Object..test (__tests__/node-assertion-error-test.js:44:10) + + ● assert.notDeepEqual + + assert.notDeepEqual(received, expected) + + Expected value to notDeepEqual to: + {\\"a\\": 1} + Received: + {\\"a\\": 1} + + Difference: + + Compared values have no visual difference. - Difference: + at Object..test (__tests__/node-assertion-error-test.js:48:10) + + ● assert.strictEqual + + assert.strictEqual(received, expected) + + Expected value to be (operator: ===): + NaN + Received: + 1 - - Expected - + Received + at Object..test (__tests__/node-assertion-error-test.js:52:10) + + ● assert.notStrictEqual + + assert.notStrictEqual(received, expected) + + Expected value not to be (operator: !==): + 1 + Received: + 1 + + Message: + My custom error message + + Difference: + + Compared values have no visual difference. - Object { - \\"a\\": Object { - \\"b\\": Object { - - \\"c\\": 6, - + \\"c\\": 5, - }, - }, - } + at Object..test (__tests__/node-assertion-error-test.js:56:10) - ● assert.deepEqual with a message + ● assert.deepStrictEqual - Error - expect(received).toBe(expected) + assert.deepStrictEqual(received, expected) + + Expected value to deepStrictEqual to: + {\\"a\\": 2} + Received: + {\\"a\\": 1} + + Difference: + + - Expected + + Received + + Object { + - \\"a\\": 2, + + \\"a\\": 1, + } - Expected value to be (using ===): - {\\"a\\": {\\"b\\": {\\"c\\": 7}}} - Received: - {\\"a\\": {\\"b\\": {\\"c\\": 5}}} + at Object..test (__tests__/node-assertion-error-test.js:60:10) + + ● assert.notDeepStrictEqual + + assert.notDeepStrictEqual(received, expected) + + Expected value to notDeepStrictEqual to: + {\\"a\\": 1} + Received: + {\\"a\\": 1} + + Difference: + + Compared values have no visual difference. - Difference: + at Object..test (__tests__/node-assertion-error-test.js:64:10) + + ● assert.ifError + + Error + 1 thrown + + ● assert.doesNotThrow + + AssertionError: Got unwanted exception.. - - Expected - + Received + at _throws (assert.js:356:5) + at Function.doesNotThrow (assert.js:375:3) + at Object..test (__tests__/node-assertion-error-test.js:72:10) + + ● assert.throws + + AssertionError: Missing expected exception.. - Object { - \\"a\\": Object { - \\"b\\": Object { - - \\"c\\": 7, - + \\"c\\": 5, - }, - }, - } + at _throws (assert.js:345:5) + at Function.throws (assert.js:369:3) + at Object..test (__tests__/node-assertion-error-test.js:76:10) ✕ assert ✕ assert with a message ✕ assert.ok ✕ assert.ok with a message ✕ assert.equal - ✕ assert.equal with a message + ✕ assert.notEqual ✕ assert.deepEqual ✕ assert.deepEqual with a message + ✕ assert.notDeepEqual + ✕ assert.strictEqual + ✕ assert.notStrictEqual + ✕ assert.deepStrictEqual + ✕ assert.notDeepStrictEqual + ✕ assert.ifError + ✕ assert.doesNotThrow + ✕ assert.throws ", "summary": "Test Suites: 1 failed, 1 total -Tests: 8 failed, 8 total +Tests: 16 failed, 16 total Snapshots: 0 total Time: <> Ran all test suites matching \\"node-assertion-error-test.js\\". diff --git a/integration_tests/__tests__/failures-test.js b/integration_tests/__tests__/failures-test.js index fad83070c24d..83a76e347596 100644 --- a/integration_tests/__tests__/failures-test.js +++ b/integration_tests/__tests__/failures-test.js @@ -28,26 +28,16 @@ const stripInconsistentStackLines = summary => { test('throwing not Error objects', () => { let stderr; stderr = runJest(dir, ['throw-number-test.js']).stderr; - expect(stripInconsistentStackLines( - extractSummary(stderr), - )).toMatchSnapshot(); + expect(stripInconsistentStackLines(extractSummary(stderr))).toMatchSnapshot(); stderr = runJest(dir, ['throw-string-test.js']).stderr; - expect(stripInconsistentStackLines( - extractSummary(stderr), - )).toMatchSnapshot(); + expect(stripInconsistentStackLines(extractSummary(stderr))).toMatchSnapshot(); stderr = runJest(dir, ['throw-object-test.js']).stderr; - expect(stripInconsistentStackLines( - extractSummary(stderr), - )).toMatchSnapshot(); + expect(stripInconsistentStackLines(extractSummary(stderr))).toMatchSnapshot(); stderr = runJest(dir, ['assertion-count-test.js']).stderr; - expect(stripInconsistentStackLines( - extractSummary(stderr), - )).toMatchSnapshot(); + expect(stripInconsistentStackLines(extractSummary(stderr))).toMatchSnapshot(); }); test('works with node assert', () => { const {stderr} = runJest(dir, ['node-assertion-error-test.js']); - expect(stripInconsistentStackLines( - extractSummary(stderr), - )).toMatchSnapshot(); + expect(stripInconsistentStackLines(extractSummary(stderr))).toMatchSnapshot(); }); diff --git a/integration_tests/failures/__tests__/node-assertion-error-test.js b/integration_tests/failures/__tests__/node-assertion-error-test.js index 11153f0e111f..9be2092db648 100644 --- a/integration_tests/failures/__tests__/node-assertion-error-test.js +++ b/integration_tests/failures/__tests__/node-assertion-error-test.js @@ -32,8 +32,8 @@ test('assert.equal', () => { assert.equal(1, 2); }); -test('assert.equal with a message', () => { - assert.equal(1, 2, 'this is a message'); +test('assert.notEqual', () => { + assert.notEqual(1, 1); }); test('assert.deepEqual', () => { @@ -43,3 +43,35 @@ test('assert.deepEqual', () => { test('assert.deepEqual with a message', () => { assert.deepEqual({a: {b: {c: 5}}}, {a: {b: {c: 7}}}, 'this is a message'); }); + +test('assert.notDeepEqual', () => { + assert.notDeepEqual({a: 1}, {a: 1}); +}); + +test('assert.strictEqual', () => { + assert.strictEqual(1, NaN); +}); + +test('assert.notStrictEqual', () => { + assert.notStrictEqual(1, 1, 'My custom error message'); +}); + +test('assert.deepStrictEqual', () => { + assert.deepStrictEqual({a: 1}, {a: 2}); +}); + +test('assert.notDeepStrictEqual', () => { + assert.notDeepStrictEqual({a: 1}, {a: 1}); +}); + +test('assert.ifError', () => { + assert.ifError(1); +}); + +test('assert.doesNotThrow', () => { + assert.doesNotThrow(() => {throw Error('err!')}); +}); + +test('assert.throws', () => { + assert.throws(() => {}); +}); diff --git a/packages/jest-jasmine2/src/jasmine/Spec.js b/packages/jest-jasmine2/src/jasmine/Spec.js index b70f45767ea6..a5513f596732 100644 --- a/packages/jest-jasmine2/src/jasmine/Spec.js +++ b/packages/jest-jasmine2/src/jasmine/Spec.js @@ -32,12 +32,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* eslint-disable sort-keys */ 'use strict'; -const diff = require('jest-diff'); -const { - matcherHint, - printReceived, - printExpected, -} = require('jest-matcher-utils'); const ExpectationFailed = require('../ExpectationFailed'); const expectationResultFactory = require('../expectationResultFactory'); @@ -117,40 +111,29 @@ Spec.prototype.execute = function(onComplete, enabled) { } }; -Spec.prototype.onException = function onException(e) { - if (Spec.isPendingSpecException(e)) { - this.pend(extractCustomPendingMessage(e)); +Spec.prototype.onException = function onException(error) { + if (Spec.isPendingSpecException(error)) { + this.pend(extractCustomPendingMessage(error)); return; } - if (e instanceof ExpectationFailed) { + if (error instanceof ExpectationFailed) { return; } - const {expected, actual} = e || {}; - let message; - if (expected && actual) { - const diffString = diff(expected, actual, { - expand: this.expand, - }); - message = matcherHint('.toBe') + - '\n\n' + - `Expected value to be (using ===):\n` + - ` ${printExpected(expected)}\n` + - `Received:\n` + - ` ${printReceived(actual)}` + - (diffString ? `\n\nDifference:\n\n${diffString}` : ''); + if (error instanceof require('assert').AssertionError) { + const assertionErrorMessage = require('jest-matchers/build/assert-support'); + error = assertionErrorMessage(error, {expand: this.expand}); } this.addExpectationResult( false, { - matcherName: 'blah', - message, + matcherName: '', passed: false, expected: '', actual: '', - error: e, + error, }, true, ); diff --git a/packages/jest-matchers/src/assert-support.js b/packages/jest-matchers/src/assert-support.js new file mode 100644 index 000000000000..0fa9900d335c --- /dev/null +++ b/packages/jest-matchers/src/assert-support.js @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +'use strict'; + +function assertionErrorMessage(error: Error, options) { + const assertOperatorsMap = { + '!=': 'notEqual', + '!==': 'notStrictEqual', + '==': 'equal', + '===': 'strictEqual', + }; + + const {expected, actual, message, operator} = error || {}; + const { + printReceived, + printExpected, + } = require('jest-matcher-utils'); + + if (expected !== undefined && actual !== undefined) { + const chalk = require('chalk'); + const diff = require('jest-diff'); + const diffString = diff(expected, actual, options); + const negator = operator.startsWith('!') || operator.startsWith('not'); + const hasCustomMessage = !error.generatedMessage; + + const assertMatcherHint = () => { + let message = chalk.dim('assert') + + chalk.dim('.' + (assertOperatorsMap[operator] || operator)) + + chalk.dim('(') + + chalk.red('received') + + chalk.dim(', ') + + chalk.green('expected') + + chalk.dim(')'); + + if (operator === '==') { + message += ' or ' + + chalk.dim('assert') + + chalk.dim('(') + + chalk.red('received') + + chalk.dim(') '); + } + + return message; + }; + + const operatorMessage = () => + operator.startsWith('!') || operator.startsWith('=') + ? `${negator ? 'not ' : ''}to be (operator: ${operator}):\n` + : `to ${operator} to:\n`; + + return assertMatcherHint() + + '\n\n' + + chalk.reset(`Expected value ${operatorMessage()}`) + + ` ${printExpected(expected)}\n` + + chalk.reset(`Received:\n`) + + ` ${printReceived(actual)}` + + chalk.reset(hasCustomMessage ? '\n\nMessage:\n ' + message : '') + + (diffString ? `\n\nDifference:\n\n${diffString}` : '') + + error.stack.replace(/AssertionError(.*)/g, ''); + } + return error; +} + +module.exports = assertionErrorMessage; From 0acdaf74b858eb12d957cd326419856b6c9c5623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 6 Apr 2017 16:06:21 +0200 Subject: [PATCH 4/8] Remove jest-diff from jest-jasmine2 deps --- packages/jest-jasmine2/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/jest-jasmine2/package.json b/packages/jest-jasmine2/package.json index b215c928a86c..a4220b2f6ea2 100644 --- a/packages/jest-jasmine2/package.json +++ b/packages/jest-jasmine2/package.json @@ -9,7 +9,6 @@ "main": "build/index.js", "dependencies": { "graceful-fs": "^4.1.11", - "jest-diff": "^19.0.0", "jest-matcher-utils": "^19.0.0", "jest-matchers": "^19.0.0", "jest-message-util": "^19.0.0", From 8969ed8192d468dd8b4f5b7262ff02d891719cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 6 Apr 2017 18:10:07 +0200 Subject: [PATCH 5/8] Support throws and doesNotThrow assert matchers --- .../__tests__/node-assertion-error-test.js | 4 +- packages/jest-matchers/src/assert-support.js | 140 ++++++++++++------ 2 files changed, 97 insertions(+), 47 deletions(-) diff --git a/integration_tests/failures/__tests__/node-assertion-error-test.js b/integration_tests/failures/__tests__/node-assertion-error-test.js index 9be2092db648..a0979f0d49ff 100644 --- a/integration_tests/failures/__tests__/node-assertion-error-test.js +++ b/integration_tests/failures/__tests__/node-assertion-error-test.js @@ -69,7 +69,9 @@ test('assert.ifError', () => { }); test('assert.doesNotThrow', () => { - assert.doesNotThrow(() => {throw Error('err!')}); + assert.doesNotThrow(() => { + throw Error('err!'); + }); }); test('assert.throws', () => { diff --git a/packages/jest-matchers/src/assert-support.js b/packages/jest-matchers/src/assert-support.js index 0fa9900d335c..aa1054ddf5a7 100644 --- a/packages/jest-matchers/src/assert-support.js +++ b/packages/jest-matchers/src/assert-support.js @@ -10,63 +10,111 @@ 'use strict'; -function assertionErrorMessage(error: Error, options) { - const assertOperatorsMap = { - '!=': 'notEqual', - '!==': 'notStrictEqual', - '==': 'equal', - '===': 'strictEqual', - }; +const { + printReceived, + printExpected, +} = require('jest-matcher-utils'); +const chalk = require('chalk'); +const diff = require('jest-diff'); - const {expected, actual, message, operator} = error || {}; - const { - printReceived, - printExpected, - } = require('jest-matcher-utils'); +declare class AssertionError extends Error { + name: string, + actual: ?string, + expected: ?string, + operator: ?string, + message: string, + generatedMessage: boolean, +} +import type {DiffOptions} from 'jest-diff/src/diffStrings'; - if (expected !== undefined && actual !== undefined) { - const chalk = require('chalk'); - const diff = require('jest-diff'); - const diffString = diff(expected, actual, options); - const negator = operator.startsWith('!') || operator.startsWith('not'); - const hasCustomMessage = !error.generatedMessage; +const assertOperatorsMap = { + '!=': 'notEqual', + '!==': 'notStrictEqual', + '==': 'equal', + '===': 'strictEqual', +}; - const assertMatcherHint = () => { - let message = chalk.dim('assert') + - chalk.dim('.' + (assertOperatorsMap[operator] || operator)) + - chalk.dim('(') + - chalk.red('received') + - chalk.dim(', ') + - chalk.green('expected') + - chalk.dim(')'); +const getOperatorName = (operator: ?string, stack: string) => { + if (typeof operator === 'string') { + return assertOperatorsMap[operator] || operator; + } + if (stack.match('.doesNotThrow')) { + return 'doesNotThrow'; + } + if (stack.match('.throws')) { + return 'throws'; + } + return ''; +}; - if (operator === '==') { - message += ' or ' + - chalk.dim('assert') + - chalk.dim('(') + - chalk.red('received') + - chalk.dim(') '); - } +const operatorMessage = (operator: ?string, negator: boolean) => + typeof operator === 'string' && + (operator.startsWith('!') || operator.startsWith('=')) + ? `${negator ? 'not ' : ''}to be (operator: ${operator}):\n` + : `to ${operator || ''} to:\n`; - return message; - }; +const assertThrowingMatcherHint = (operatorName: string) => { + return chalk.dim('assert') + + chalk.dim('.' + operatorName + '(') + + chalk.red('function') + + chalk.dim(')'); +}; + +const assertMatcherHint = (operator: ?string, operatorName: string) => { + let message = chalk.dim('assert') + + chalk.dim('.' + operatorName + '(') + + chalk.red('received') + + chalk.dim(', ') + + chalk.green('expected') + + chalk.dim(')'); + + if (operator === '==') { + message += ' or ' + + chalk.dim('assert') + + chalk.dim('(') + + chalk.red('received') + + chalk.dim(') '); + } - const operatorMessage = () => - operator.startsWith('!') || operator.startsWith('=') - ? `${negator ? 'not ' : ''}to be (operator: ${operator}):\n` - : `to ${operator} to:\n`; + return message; +}; - return assertMatcherHint() + +function assertionErrorMessage(error: AssertionError, options: DiffOptions) { + const {expected, actual, message, operator, stack} = error; + const diffString = diff(expected, actual, options); + const negator = typeof operator === 'string' && + (operator.startsWith('!') || operator.startsWith('not')); + const hasCustomMessage = !error.generatedMessage; + const operatorName = getOperatorName(operator, stack); + + if (operatorName === 'doesNotThrow') { + return assertThrowingMatcherHint(operatorName) + '\n\n' + - chalk.reset(`Expected value ${operatorMessage()}`) + - ` ${printExpected(expected)}\n` + - chalk.reset(`Received:\n`) + + chalk.reset(`Expected the function not to throw an error.\n`) + + chalk.reset(`Instead, it threw:\n`) + ` ${printReceived(actual)}` + chalk.reset(hasCustomMessage ? '\n\nMessage:\n ' + message : '') + - (diffString ? `\n\nDifference:\n\n${diffString}` : '') + - error.stack.replace(/AssertionError(.*)/g, ''); + stack.replace(/AssertionError(.*)/g, ''); + } + + if (operatorName === 'throws') { + return assertThrowingMatcherHint(operatorName) + + '\n\n' + + chalk.reset(`Expected the function to throw an error.\n`) + + chalk.reset(`But it didn't throw anything.`) + + chalk.reset(hasCustomMessage ? '\n\nMessage:\n ' + message : '') + + stack.replace(/AssertionError(.*)/g, ''); } - return error; + + return assertMatcherHint(operator, operatorName) + + '\n\n' + + chalk.reset(`Expected value ${operatorMessage(operator, negator)}`) + + ` ${printExpected(expected)}\n` + + chalk.reset(`Received:\n`) + + ` ${printReceived(actual)}` + + chalk.reset(hasCustomMessage ? '\n\nMessage:\n ' + message : '') + + (diffString ? `\n\nDifference:\n\n${diffString}` : '') + + stack.replace(/AssertionError(.*)/g, ''); } module.exports = assertionErrorMessage; From cc43225fc69f158644cc0f2f26616130dffffc45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 6 Apr 2017 18:12:23 +0200 Subject: [PATCH 6/8] Update snapshots --- .../__snapshots__/failures-test.js.snap | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/integration_tests/__tests__/__snapshots__/failures-test.js.snap b/integration_tests/__tests__/__snapshots__/failures-test.js.snap index d4d99f1df6b8..bb15de7dae74 100644 --- a/integration_tests/__tests__/__snapshots__/failures-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/failures-test.js.snap @@ -323,7 +323,14 @@ Object { ● assert.doesNotThrow - AssertionError: Got unwanted exception.. + assert.doesNotThrow(function) + + Expected the function not to throw an error. + Instead, it threw: + [Error: err!] + + Message: + Got unwanted exception.. at _throws (assert.js:356:5) at Function.doesNotThrow (assert.js:375:3) @@ -331,11 +338,17 @@ Object { ● assert.throws - AssertionError: Missing expected exception.. + assert.throws(function) + + Expected the function to throw an error. + But it didn't throw anything. + + Message: + Missing expected exception.. at _throws (assert.js:345:5) at Function.throws (assert.js:369:3) - at Object..test (__tests__/node-assertion-error-test.js:76:10) + at Object..test (__tests__/node-assertion-error-test.js:78:10) ✕ assert ✕ assert with a message From 4332df009957fc48f2ec80a6da70b628f32c0943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 7 Apr 2017 23:07:32 +0200 Subject: [PATCH 7/8] Fix snapshots across different node verions --- .../__snapshots__/failures-test.js.snap | 34 ++++++++----------- integration_tests/__tests__/failures-test.js | 6 +++- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/integration_tests/__tests__/__snapshots__/failures-test.js.snap b/integration_tests/__tests__/__snapshots__/failures-test.js.snap index bb15de7dae74..e9c645a0190e 100644 --- a/integration_tests/__tests__/__snapshots__/failures-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/failures-test.js.snap @@ -116,7 +116,7 @@ Object { Received: false - at Object..test (__tests__/node-assertion-error-test.js:16:3) + at Object. (__tests__/node-assertion-error-test.js:16:3) ● assert with a message @@ -130,7 +130,7 @@ Object { Message: this is a message - at Object..test (__tests__/node-assertion-error-test.js:20:3) + at Object. (__tests__/node-assertion-error-test.js:20:3) ● assert.ok @@ -141,7 +141,7 @@ Object { Received: false - at Object..test (__tests__/node-assertion-error-test.js:24:10) + at Object. (__tests__/node-assertion-error-test.js:24:10) ● assert.ok with a message @@ -155,7 +155,7 @@ Object { Message: this is a message - at Object..test (__tests__/node-assertion-error-test.js:28:10) + at Object. (__tests__/node-assertion-error-test.js:28:10) ● assert.equal @@ -166,7 +166,7 @@ Object { Received: 1 - at Object..test (__tests__/node-assertion-error-test.js:32:10) + at Object. (__tests__/node-assertion-error-test.js:32:10) ● assert.notEqual @@ -181,7 +181,7 @@ Object { Compared values have no visual difference. - at Object..test (__tests__/node-assertion-error-test.js:36:10) + at Object. (__tests__/node-assertion-error-test.js:36:10) ● assert.deepEqual @@ -206,7 +206,7 @@ Object { }, } - at Object..test (__tests__/node-assertion-error-test.js:40:10) + at Object. (__tests__/node-assertion-error-test.js:40:10) ● assert.deepEqual with a message @@ -234,7 +234,7 @@ Object { }, } - at Object..test (__tests__/node-assertion-error-test.js:44:10) + at Object. (__tests__/node-assertion-error-test.js:44:10) ● assert.notDeepEqual @@ -249,7 +249,7 @@ Object { Compared values have no visual difference. - at Object..test (__tests__/node-assertion-error-test.js:48:10) + at Object. (__tests__/node-assertion-error-test.js:48:10) ● assert.strictEqual @@ -260,7 +260,7 @@ Object { Received: 1 - at Object..test (__tests__/node-assertion-error-test.js:52:10) + at Object. (__tests__/node-assertion-error-test.js:52:10) ● assert.notStrictEqual @@ -278,7 +278,7 @@ Object { Compared values have no visual difference. - at Object..test (__tests__/node-assertion-error-test.js:56:10) + at Object. (__tests__/node-assertion-error-test.js:56:10) ● assert.deepStrictEqual @@ -299,7 +299,7 @@ Object { + \\"a\\": 1, } - at Object..test (__tests__/node-assertion-error-test.js:60:10) + at Object. (__tests__/node-assertion-error-test.js:60:10) ● assert.notDeepStrictEqual @@ -314,7 +314,7 @@ Object { Compared values have no visual difference. - at Object..test (__tests__/node-assertion-error-test.js:64:10) + at Object. (__tests__/node-assertion-error-test.js:64:10) ● assert.ifError @@ -332,9 +332,7 @@ Object { Message: Got unwanted exception.. - at _throws (assert.js:356:5) - at Function.doesNotThrow (assert.js:375:3) - at Object..test (__tests__/node-assertion-error-test.js:72:10) + at Object. (__tests__/node-assertion-error-test.js:72:10) ● assert.throws @@ -346,9 +344,7 @@ Object { Message: Missing expected exception.. - at _throws (assert.js:345:5) - at Function.throws (assert.js:369:3) - at Object..test (__tests__/node-assertion-error-test.js:78:10) + at Object. (__tests__/node-assertion-error-test.js:78:10) ✕ assert ✕ assert with a message diff --git a/integration_tests/__tests__/failures-test.js b/integration_tests/__tests__/failures-test.js index 83a76e347596..ff5626343191 100644 --- a/integration_tests/__tests__/failures-test.js +++ b/integration_tests/__tests__/failures-test.js @@ -21,7 +21,11 @@ skipOnWindows.suite(); // snapshot tests fail on different machines. This function makes sure // this extra line is always removed. const stripInconsistentStackLines = summary => { - summary.rest = summary.rest.replace(/\n^.*process\._tickCallback.*$/gm, ''); + summary.rest = summary.rest + .replace(/\n^.*process\._tickCallback.*$/gm, '') + .replace(/\n^.*_throws.*$/gm, '') + .replace(/\n^.*Function\..*(throws|doesNotThrow).*$/gm, '') + .replace(/(\n^.*Object.)\.test(.*$)/gm, '$1$2'); return summary; }; From f6d7126198271be56fa0ca5845f57a4b51864c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 11 Apr 2017 15:18:43 +0200 Subject: [PATCH 8/8] Human readable messages --- .../__tests__/__snapshots__/failures-test.js.snap | 10 +++++----- packages/jest-jasmine2/package.json | 2 ++ .../src/assert-support.js | 11 +++++++++-- packages/jest-jasmine2/src/jasmine/Spec.js | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) rename packages/{jest-matchers => jest-jasmine2}/src/assert-support.js (91%) diff --git a/integration_tests/__tests__/__snapshots__/failures-test.js.snap b/integration_tests/__tests__/__snapshots__/failures-test.js.snap index e9c645a0190e..75ae6bd1df25 100644 --- a/integration_tests/__tests__/__snapshots__/failures-test.js.snap +++ b/integration_tests/__tests__/__snapshots__/failures-test.js.snap @@ -187,7 +187,7 @@ Object { assert.deepEqual(received, expected) - Expected value to deepEqual to: + Expected value to deeply equal to: {\\"a\\": {\\"b\\": {\\"c\\": 6}}} Received: {\\"a\\": {\\"b\\": {\\"c\\": 5}}} @@ -212,7 +212,7 @@ Object { assert.deepEqual(received, expected) - Expected value to deepEqual to: + Expected value to deeply equal to: {\\"a\\": {\\"b\\": {\\"c\\": 7}}} Received: {\\"a\\": {\\"b\\": {\\"c\\": 5}}} @@ -240,7 +240,7 @@ Object { assert.notDeepEqual(received, expected) - Expected value to notDeepEqual to: + Expected value not to deeply equal to: {\\"a\\": 1} Received: {\\"a\\": 1} @@ -284,7 +284,7 @@ Object { assert.deepStrictEqual(received, expected) - Expected value to deepStrictEqual to: + Expected value to deeply and strictly equal to: {\\"a\\": 2} Received: {\\"a\\": 1} @@ -305,7 +305,7 @@ Object { assert.notDeepStrictEqual(received, expected) - Expected value to notDeepStrictEqual to: + Expected value not to deeply and strictly equal to: {\\"a\\": 1} Received: {\\"a\\": 1} diff --git a/packages/jest-jasmine2/package.json b/packages/jest-jasmine2/package.json index a4220b2f6ea2..a322d5f148b1 100644 --- a/packages/jest-jasmine2/package.json +++ b/packages/jest-jasmine2/package.json @@ -8,7 +8,9 @@ "license": "BSD-3-Clause", "main": "build/index.js", "dependencies": { + "chalk": "^1.1.3", "graceful-fs": "^4.1.11", + "jest-diff": "^19.0.0", "jest-matcher-utils": "^19.0.0", "jest-matchers": "^19.0.0", "jest-message-util": "^19.0.0", diff --git a/packages/jest-matchers/src/assert-support.js b/packages/jest-jasmine2/src/assert-support.js similarity index 91% rename from packages/jest-matchers/src/assert-support.js rename to packages/jest-jasmine2/src/assert-support.js index aa1054ddf5a7..6afaa6638898 100644 --- a/packages/jest-matchers/src/assert-support.js +++ b/packages/jest-jasmine2/src/assert-support.js @@ -34,6 +34,13 @@ const assertOperatorsMap = { '===': 'strictEqual', }; +const humanReadableOperators = { + deepEqual: 'to deeply equal', + deepStrictEqual: 'to deeply and strictly equal', + notDeepEqual: 'not to deeply equal', + notDeepStrictEqual: 'not to deeply and strictly equal', +}; + const getOperatorName = (operator: ?string, stack: string) => { if (typeof operator === 'string') { return assertOperatorsMap[operator] || operator; @@ -49,9 +56,9 @@ const getOperatorName = (operator: ?string, stack: string) => { const operatorMessage = (operator: ?string, negator: boolean) => typeof operator === 'string' && - (operator.startsWith('!') || operator.startsWith('=')) + (operator.startsWith('!') || operator.startsWith('=') ? `${negator ? 'not ' : ''}to be (operator: ${operator}):\n` - : `to ${operator || ''} to:\n`; + : `${humanReadableOperators[operator] || operator} to:\n`); const assertThrowingMatcherHint = (operatorName: string) => { return chalk.dim('assert') + diff --git a/packages/jest-jasmine2/src/jasmine/Spec.js b/packages/jest-jasmine2/src/jasmine/Spec.js index c6bd8d8c82e0..6b800f921874 100644 --- a/packages/jest-jasmine2/src/jasmine/Spec.js +++ b/packages/jest-jasmine2/src/jasmine/Spec.js @@ -121,7 +121,7 @@ Spec.prototype.onException = function onException(error) { } if (error instanceof require('assert').AssertionError) { - const assertionErrorMessage = require('jest-matchers/build/assert-support'); + const assertionErrorMessage = require('../assert-support'); error = assertionErrorMessage(error, {expand: this.expand}); }