From c79cfebdbdf64edfaf00f8406e422a55fdd20429 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sun, 15 Apr 2018 22:06:16 +0200 Subject: [PATCH 1/3] add stack trace on expect.(has)Assertions --- CHANGELOG.md | 2 + .../__snapshots__/failures.test.js.snap | 52 ++++++++++++++++++- integration-tests/__tests__/failures.test.js | 26 +--------- .../src/extract_expected_assertions_errors.js | 30 ++++++----- packages/expect/src/index.js | 25 ++++++--- 5 files changed, 89 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a2785cb7c69..95a9dd60cad2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,8 @@ ### Fixes +* `[expect]` Add stack trace when `expect.assertions` and `expect.hasAssertions` + causes test failures. ([#5997](https://github.com/facebook/jest/pull/5997)) * `[jest-runtime]` Throw a more useful error when trying to require modules after the test environment is torn down ([#5888](https://github.com/facebook/jest/pull/5888)) diff --git a/integration-tests/__tests__/__snapshots__/failures.test.js.snap b/integration-tests/__tests__/__snapshots__/failures.test.js.snap index e2c73766829e..736dea2a9910 100644 --- a/integration-tests/__tests__/__snapshots__/failures.test.js.snap +++ b/integration-tests/__tests__/__snapshots__/failures.test.js.snap @@ -36,9 +36,13 @@ exports[`not throwing Error objects 4`] = ` ✕ throws on assertion .hasAssertions() ✕ throws when there are not assertions + ● .assertions() › throws + expect(received).toBeTruthy() + Received: false + 11 | const throws = () => { 12 | expect.assertions(2); > 13 | expect(false).toBeTruthy(); @@ -46,27 +50,73 @@ exports[`not throwing Error objects 4`] = ` 14 | }; 15 | const redeclare = () => { 16 | expect.assertions(1); + at __tests__/assertion_count.test.js:13:17 + ● .assertions() › throws + expect.assertions(2) + Expected two assertions to be called but received one assertion call. + + 10 | + 11 | const throws = () => { + > 12 | expect.assertions(2); + | ^ + 13 | expect(false).toBeTruthy(); + 14 | }; + 15 | const redeclare = () => { + + at __tests__/assertion_count.test.js:12:10 + ● .assertions() › throws on redeclare of assertion count + expect(received).toBeTruthy() + Received: false + 15 | const redeclare = () => { 16 | expect.assertions(1); > 17 | expect(false).toBeTruthy(); | ^ 18 | expect.assertions(2); 19 | }; - 20 | + 20 | + at __tests__/assertion_count.test.js:17:17 + ● .assertions() › throws on assertion + expect.assertions(0) + Expected zero assertions to be called but received one assertion call. + + 20 | + 21 | const noAssertions = () => { + > 22 | expect.assertions(0); + | ^ + 23 | expect(true).toBeTruthy(); + 24 | }; + 25 | + + at __tests__/assertion_count.test.js:22:10 + ● .hasAssertions() › throws when there are not assertions + expect.hasAssertions() + Expected at least one assertion to be called but received none. + + 25 | + 26 | const hasNoAssertions = () => { + > 27 | expect.hasAssertions(); + | ^ + 28 | }; + 29 | + 30 | describe('.assertions()', () => { + + at __tests__/assertion_count.test.js:27:10 + " `; diff --git a/integration-tests/__tests__/failures.test.js b/integration-tests/__tests__/failures.test.js index e8fd6d0e65bf..fea9dc4ecc95 100644 --- a/integration-tests/__tests__/failures.test.js +++ b/integration-tests/__tests__/failures.test.js @@ -18,30 +18,6 @@ const normalizeDots = text => text.replace(/\.{1,}$/gm, '.'); SkipOnWindows.suite(); -const cleanupStackTrace = stderr => { - const STACK_REGEXP = /^.*at.*(setup-jest-globals|extractExpectedAssertionsErrors).*\n/gm; - if (!STACK_REGEXP.test(stderr)) { - throw new Error( - ` - This function is used to remove inconsistent stack traces between - jest-jasmine2 and jest-circus. If you see this error, that means the - stack traces are no longer inconsistent and this function can be - safely removed. - - output: - ${stderr} - `, - ); - } - - return ( - stderr - .replace(STACK_REGEXP, '') - // Also remove trailing whitespace. - .replace(/\s+$/gm, '') - ); -}; - test('not throwing Error objects', () => { let stderr; stderr = runJest(dir, ['throw_number.test.js']).stderr; @@ -51,7 +27,7 @@ test('not throwing Error objects', () => { stderr = runJest(dir, ['throw_object.test.js']).stderr; expect(extractSummary(stderr).rest).toMatchSnapshot(); stderr = runJest(dir, ['assertion_count.test.js']).stderr; - expect(extractSummary(cleanupStackTrace(stderr)).rest).toMatchSnapshot(); + expect(extractSummary(stderr).rest).toMatchSnapshot(); stderr = runJest(dir, ['during_tests.test.js']).stderr; expect(extractSummary(stderr).rest).toMatchSnapshot(); }); diff --git a/packages/expect/src/extract_expected_assertions_errors.js b/packages/expect/src/extract_expected_assertions_errors.js index 2f245b46638f..af7d243142ae 100644 --- a/packages/expect/src/extract_expected_assertions_errors.js +++ b/packages/expect/src/extract_expected_assertions_errors.js @@ -25,13 +25,15 @@ const resetAssertionsLocalState = () => { }; // Create and format all errors related to the mismatched number of `expect` -// calls and reset the matchers state. +// calls and reset the matcher's state. const extractExpectedAssertionsErrors = () => { const result = []; const { assertionCalls, expectedAssertionsNumber, + expectedAssertionsNumberError, isExpectingAssertions, + isExpectingAssertionsError, } = getState(); resetAssertionsLocalState(); @@ -43,34 +45,36 @@ const extractExpectedAssertionsErrors = () => { const numOfAssertionsExpected = EXPECTED_COLOR( pluralize('assertion', expectedAssertionsNumber), ); - const error = new Error( + + expectedAssertionsNumberError.message = matcherHint('.assertions', '', String(expectedAssertionsNumber), { isDirectExpectCall: true, }) + - '\n\n' + - `Expected ${numOfAssertionsExpected} to be called but received ` + - RECEIVED_COLOR(pluralize('assertion call', assertionCalls || 0)) + - '.', - ); + '\n\n' + + `Expected ${numOfAssertionsExpected} to be called but received ` + + RECEIVED_COLOR(pluralize('assertion call', assertionCalls || 0)) + + '.'; + result.push({ actual: assertionCalls, - error, + error: expectedAssertionsNumberError, expected: expectedAssertionsNumber, }); } if (isExpectingAssertions && assertionCalls === 0) { const expected = EXPECTED_COLOR('at least one assertion'); const received = RECEIVED_COLOR('received none'); - const error = new Error( + + isExpectingAssertionsError.message = matcherHint('.hasAssertions', '', '', { isDirectExpectCall: true, }) + - '\n\n' + - `Expected ${expected} to be called but ${received}.`, - ); + '\n\n' + + `Expected ${expected} to be called but ${received}.`; + result.push({ actual: 'none', - error, + error: isExpectingAssertionsError, expected: 'at least one', }); } diff --git a/packages/expect/src/index.js b/packages/expect/src/index.js index f78dbfac79a3..26d896bf255d 100644 --- a/packages/expect/src/index.js +++ b/packages/expect/src/index.js @@ -314,19 +314,30 @@ const _validateResult = result => { } }; +function assertions(expected: number) { + const error = new Error(); + Error.captureStackTrace(error, assertions); + + getState().expectedAssertionsNumber = expected; + getState().expectedAssertionsNumberError = error; +} +function hasAssertions(expected: any) { + const error = new Error(); + Error.captureStackTrace(error, hasAssertions); + + utils.ensureNoExpected(expected, '.hasAssertions'); + getState().isExpectingAssertions = true; + getState().isExpectingAssertionsError = error; +} + // add default jest matchers setMatchers(matchers, true, expect); setMatchers(spyMatchers, true, expect); setMatchers(toThrowMatchers, true, expect); expect.addSnapshotSerializer = () => void 0; -expect.assertions = (expected: number) => { - getState().expectedAssertionsNumber = expected; -}; -expect.hasAssertions = (expected: any) => { - utils.ensureNoExpected(expected, '.hasAssertions'); - getState().isExpectingAssertions = true; -}; +expect.assertions = assertions; +expect.hasAssertions = hasAssertions; expect.getState = getState; expect.setState = setState; expect.extractExpectedAssertionsErrors = extractExpectedAssertionsErrors; From 4aee16edc4dc3c9d3bb1b911c4d7fc675c3f7093 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sun, 15 Apr 2018 22:15:22 +0200 Subject: [PATCH 2/3] guard against missing `Error.captureStackTrace` --- packages/expect/src/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/expect/src/index.js b/packages/expect/src/index.js index 26d896bf255d..5926994d9a89 100644 --- a/packages/expect/src/index.js +++ b/packages/expect/src/index.js @@ -316,14 +316,18 @@ const _validateResult = result => { function assertions(expected: number) { const error = new Error(); - Error.captureStackTrace(error, assertions); + if (Error.captureStackTrace) { + Error.captureStackTrace(error, assertions); + } getState().expectedAssertionsNumber = expected; getState().expectedAssertionsNumberError = error; } function hasAssertions(expected: any) { const error = new Error(); - Error.captureStackTrace(error, hasAssertions); + if (Error.captureStackTrace) { + Error.captureStackTrace(error, hasAssertions); + } utils.ensureNoExpected(expected, '.hasAssertions'); getState().isExpectingAssertions = true; From 44f0a60908bdf95e88c08de66f8eb8f0005ef1ea Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sun, 15 Apr 2018 22:27:04 +0200 Subject: [PATCH 3/3] please flow gods --- packages/expect/src/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/expect/src/index.js b/packages/expect/src/index.js index 5926994d9a89..ea25ba324ceb 100644 --- a/packages/expect/src/index.js +++ b/packages/expect/src/index.js @@ -323,13 +323,13 @@ function assertions(expected: number) { getState().expectedAssertionsNumber = expected; getState().expectedAssertionsNumberError = error; } -function hasAssertions(expected: any) { +function hasAssertions(...args) { const error = new Error(); if (Error.captureStackTrace) { Error.captureStackTrace(error, hasAssertions); } - utils.ensureNoExpected(expected, '.hasAssertions'); + utils.ensureNoExpected(args[0], '.hasAssertions'); getState().isExpectingAssertions = true; getState().isExpectingAssertionsError = error; }