From bb471f07977ce18a91c88c8cfceeb08ac69406dd Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Tue, 12 Feb 2019 09:53:17 -0500 Subject: [PATCH 1/5] expect: Improve report when matcher fails, part 7 (#7866) * expect: Improve report when matcher fails, part 7 * Update CHANGELOG.md --- CHANGELOG.md | 2 + .../__snapshots__/matchers.test.js.snap | 396 +++++++++--------- packages/expect/src/matchers.js | 88 ++-- 3 files changed, 256 insertions(+), 230 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e8004209de7..24f72e8ba875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Features +- `[expect]`: Improve report when matcher fails, part 7 ([#7866](https://github.com/facebook/jest/pull/7866)) + ### Fixes - `[jest-cli]` Refactor `-o` and `--coverage` combined ([#7611](https://github.com/facebook/jest/pull/7611)) diff --git a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap index 1debb403a675..1ab89d930b1b 100644 --- a/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap +++ b/packages/expect/src/__tests__/__snapshots__/matchers.test.js.snap @@ -645,465 +645,465 @@ Received: undefined" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [-Infinity, -Infinity] 1`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: -Infinity -Received: -Infinity" +Expected: not >= -Infinity +Received: -Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [-Infinity, -Infinity] 2`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: -Infinity -Received: -Infinity" +Expected: not <= -Infinity +Received: -Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [1, 1] 1`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: 1 -Received: 1" +Expected: not >= 1 +Received: 1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [1, 1] 2`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: 1 -Received: 1" +Expected: not <= 1 +Received: 1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [1.7976931348623157e+308, 1.7976931348623157e+308] 1`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: 1.7976931348623157e+308 -Received: 1.7976931348623157e+308" +Expected: not >= 1.7976931348623157e+308 +Received: 1.7976931348623157e+308" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [1.7976931348623157e+308, 1.7976931348623157e+308] 2`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: 1.7976931348623157e+308 -Received: 1.7976931348623157e+308" +Expected: not <= 1.7976931348623157e+308 +Received: 1.7976931348623157e+308" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [5e-324, 5e-324] 1`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: 5e-324 -Received: 5e-324" +Expected: not >= 5e-324 +Received: 5e-324" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [5e-324, 5e-324] 2`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: 5e-324 -Received: 5e-324" +Expected: not <= 5e-324 +Received: 5e-324" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [Infinity, Infinity] 1`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: Infinity -Received: Infinity" +Expected: not >= Infinity +Received: Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [Infinity, Infinity] 2`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: Infinity -Received: Infinity" +Expected: not <= Infinity +Received: Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] 1`] = ` -"expect(received).toBeGreaterThan(expected) +"expect(received).toBeGreaterThan(expected) -Expected: Infinity -Received: -Infinity" +Expected: > Infinity +Received: -Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] 2`] = ` -"expect(received).not.toBeLessThan(expected) +"expect(received).not.toBeLessThan(expected) -Expected: Infinity -Received: -Infinity" +Expected: not < Infinity +Received: -Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] 3`] = ` -"expect(received).not.toBeGreaterThan(expected) +"expect(received).not.toBeGreaterThan(expected) -Expected: -Infinity -Received: Infinity" +Expected: not > -Infinity +Received: Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] 4`] = ` -"expect(received).toBeLessThan(expected) +"expect(received).toBeLessThan(expected) -Expected: -Infinity -Received: Infinity" +Expected: < -Infinity +Received: Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] 5`] = ` -"expect(received).toBeGreaterThanOrEqual(expected) +"expect(received).toBeGreaterThanOrEqual(expected) -Expected: Infinity -Received: -Infinity" +Expected: >= Infinity +Received: -Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] 6`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: Infinity -Received: -Infinity" +Expected: not <= Infinity +Received: -Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] 7`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: -Infinity -Received: Infinity" +Expected: not >= -Infinity +Received: Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] 8`] = ` -"expect(received).toBeLessThanOrEqual(expected) +"expect(received).toBeLessThanOrEqual(expected) -Expected: -Infinity -Received: Infinity" +Expected: <= -Infinity +Received: Infinity" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] 1`] = ` -"expect(received).toBeGreaterThan(expected) +"expect(received).toBeGreaterThan(expected) -Expected: 0.2 -Received: 0.1" +Expected: > 0.2 +Received: 0.1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] 2`] = ` -"expect(received).not.toBeLessThan(expected) +"expect(received).not.toBeLessThan(expected) -Expected: 0.2 -Received: 0.1" +Expected: not < 0.2 +Received: 0.1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] 3`] = ` -"expect(received).not.toBeGreaterThan(expected) +"expect(received).not.toBeGreaterThan(expected) -Expected: 0.1 -Received: 0.2" +Expected: not > 0.1 +Received: 0.2" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] 4`] = ` -"expect(received).toBeLessThan(expected) +"expect(received).toBeLessThan(expected) -Expected: 0.1 -Received: 0.2" +Expected: < 0.1 +Received: 0.2" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] 5`] = ` -"expect(received).toBeGreaterThanOrEqual(expected) +"expect(received).toBeGreaterThanOrEqual(expected) -Expected: 0.2 -Received: 0.1" +Expected: >= 0.2 +Received: 0.1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] 6`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: 0.2 -Received: 0.1" +Expected: not <= 0.2 +Received: 0.1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] 7`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: 0.1 -Received: 0.2" +Expected: not >= 0.1 +Received: 0.2" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] 8`] = ` -"expect(received).toBeLessThanOrEqual(expected) +"expect(received).toBeLessThanOrEqual(expected) -Expected: 0.1 -Received: 0.2" +Expected: <= 0.1 +Received: 0.2" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] 1`] = ` -"expect(received).toBeGreaterThan(expected) +"expect(received).toBeGreaterThan(expected) -Expected: 2 -Received: 1" +Expected: > 2 +Received: 1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] 2`] = ` -"expect(received).not.toBeLessThan(expected) +"expect(received).not.toBeLessThan(expected) -Expected: 2 -Received: 1" +Expected: not < 2 +Received: 1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] 3`] = ` -"expect(received).not.toBeGreaterThan(expected) +"expect(received).not.toBeGreaterThan(expected) -Expected: 1 -Received: 2" +Expected: not > 1 +Received: 2" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] 4`] = ` -"expect(received).toBeLessThan(expected) +"expect(received).toBeLessThan(expected) -Expected: 1 -Received: 2" +Expected: < 1 +Received: 2" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] 5`] = ` -"expect(received).toBeGreaterThanOrEqual(expected) +"expect(received).toBeGreaterThanOrEqual(expected) -Expected: 2 -Received: 1" +Expected: >= 2 +Received: 1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] 6`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: 2 -Received: 1" +Expected: not <= 2 +Received: 1" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] 7`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: 1 -Received: 2" +Expected: not >= 1 +Received: 2" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] 8`] = ` -"expect(received).toBeLessThanOrEqual(expected) +"expect(received).toBeLessThanOrEqual(expected) -Expected: 1 -Received: 2" +Expected: <= 1 +Received: 2" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] 1`] = ` -"expect(received).toBeGreaterThan(expected) +"expect(received).toBeGreaterThan(expected) -Expected: 7 -Received: 3" +Expected: > 7 +Received: 3" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] 2`] = ` -"expect(received).not.toBeLessThan(expected) +"expect(received).not.toBeLessThan(expected) -Expected: 7 -Received: 3" +Expected: not < 7 +Received: 3" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] 3`] = ` -"expect(received).not.toBeGreaterThan(expected) +"expect(received).not.toBeGreaterThan(expected) -Expected: 3 -Received: 7" +Expected: not > 3 +Received: 7" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] 4`] = ` -"expect(received).toBeLessThan(expected) +"expect(received).toBeLessThan(expected) -Expected: 3 -Received: 7" +Expected: < 3 +Received: 7" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] 5`] = ` -"expect(received).toBeGreaterThanOrEqual(expected) +"expect(received).toBeGreaterThanOrEqual(expected) -Expected: 7 -Received: 3" +Expected: >= 7 +Received: 3" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] 6`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: 7 -Received: 3" +Expected: not <= 7 +Received: 3" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] 7`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: 3 -Received: 7" +Expected: not >= 3 +Received: 7" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] 8`] = ` -"expect(received).toBeLessThanOrEqual(expected) +"expect(received).toBeLessThanOrEqual(expected) -Expected: 3 -Received: 7" +Expected: <= 3 +Received: 7" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] 1`] = ` -"expect(received).toBeGreaterThan(expected) +"expect(received).toBeGreaterThan(expected) -Expected: 1.7976931348623157e+308 -Received: 5e-324" +Expected: > 1.7976931348623157e+308 +Received: 5e-324" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] 2`] = ` -"expect(received).not.toBeLessThan(expected) +"expect(received).not.toBeLessThan(expected) -Expected: 1.7976931348623157e+308 -Received: 5e-324" +Expected: not < 1.7976931348623157e+308 +Received: 5e-324" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] 3`] = ` -"expect(received).not.toBeGreaterThan(expected) +"expect(received).not.toBeGreaterThan(expected) -Expected: 5e-324 -Received: 1.7976931348623157e+308" +Expected: not > 5e-324 +Received: 1.7976931348623157e+308" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] 4`] = ` -"expect(received).toBeLessThan(expected) +"expect(received).toBeLessThan(expected) -Expected: 5e-324 -Received: 1.7976931348623157e+308" +Expected: < 5e-324 +Received: 1.7976931348623157e+308" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] 5`] = ` -"expect(received).toBeGreaterThanOrEqual(expected) +"expect(received).toBeGreaterThanOrEqual(expected) -Expected: 1.7976931348623157e+308 -Received: 5e-324" +Expected: >= 1.7976931348623157e+308 +Received: 5e-324" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] 6`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: 1.7976931348623157e+308 -Received: 5e-324" +Expected: not <= 1.7976931348623157e+308 +Received: 5e-324" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] 7`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: 5e-324 -Received: 1.7976931348623157e+308" +Expected: not >= 5e-324 +Received: 1.7976931348623157e+308" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] 8`] = ` -"expect(received).toBeLessThanOrEqual(expected) +"expect(received).toBeLessThanOrEqual(expected) -Expected: 5e-324 -Received: 1.7976931348623157e+308" +Expected: <= 5e-324 +Received: 1.7976931348623157e+308" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] 1`] = ` -"expect(received).toBeGreaterThan(expected) +"expect(received).toBeGreaterThan(expected) -Expected: 18 -Received: 9" +Expected: > 18 +Received: 9" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] 2`] = ` -"expect(received).not.toBeLessThan(expected) +"expect(received).not.toBeLessThan(expected) -Expected: 18 -Received: 9" +Expected: not < 18 +Received: 9" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] 3`] = ` -"expect(received).not.toBeGreaterThan(expected) +"expect(received).not.toBeGreaterThan(expected) -Expected: 9 -Received: 18" +Expected: not > 9 +Received: 18" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] 4`] = ` -"expect(received).toBeLessThan(expected) +"expect(received).toBeLessThan(expected) -Expected: 9 -Received: 18" +Expected: < 9 +Received: 18" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] 5`] = ` -"expect(received).toBeGreaterThanOrEqual(expected) +"expect(received).toBeGreaterThanOrEqual(expected) -Expected: 18 -Received: 9" +Expected: >= 18 +Received: 9" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] 6`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: 18 -Received: 9" +Expected: not <= 18 +Received: 9" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] 7`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: 9 -Received: 18" +Expected: not >= 9 +Received: 18" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] 8`] = ` -"expect(received).toBeLessThanOrEqual(expected) +"expect(received).toBeLessThanOrEqual(expected) -Expected: 9 -Received: 18" +Expected: <= 9 +Received: 18" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] 1`] = ` -"expect(received).toBeGreaterThan(expected) +"expect(received).toBeGreaterThan(expected) -Expected: 34 -Received: 17" +Expected: > 34 +Received: 17" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] 2`] = ` -"expect(received).not.toBeLessThan(expected) +"expect(received).not.toBeLessThan(expected) -Expected: 34 -Received: 17" +Expected: not < 34 +Received: 17" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] 3`] = ` -"expect(received).not.toBeGreaterThan(expected) +"expect(received).not.toBeGreaterThan(expected) -Expected: 17 -Received: 34" +Expected: not > 17 +Received: 34" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] 4`] = ` -"expect(received).toBeLessThan(expected) +"expect(received).toBeLessThan(expected) -Expected: 17 -Received: 34" +Expected: < 17 +Received: 34" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] 5`] = ` -"expect(received).toBeGreaterThanOrEqual(expected) +"expect(received).toBeGreaterThanOrEqual(expected) -Expected: 34 -Received: 17" +Expected: >= 34 +Received: 17" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] 6`] = ` -"expect(received).not.toBeLessThanOrEqual(expected) +"expect(received).not.toBeLessThanOrEqual(expected) -Expected: 34 -Received: 17" +Expected: not <= 34 +Received: 17" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] 7`] = ` -"expect(received).not.toBeGreaterThanOrEqual(expected) +"expect(received).not.toBeGreaterThanOrEqual(expected) -Expected: 17 -Received: 34" +Expected: not >= 17 +Received: 34" `; exports[`.toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] 8`] = ` -"expect(received).toBeLessThanOrEqual(expected) +"expect(received).toBeLessThanOrEqual(expected) -Expected: 17 -Received: 34" +Expected: <= 17 +Received: 34" `; exports[`.toBeInstanceOf() failing "a" and [Function String] 1`] = ` diff --git a/packages/expect/src/matchers.js b/packages/expect/src/matchers.js index 298f1d1cb681..844d6fc1b986 100644 --- a/packages/expect/src/matchers.js +++ b/packages/expect/src/matchers.js @@ -144,29 +144,41 @@ const matchers: MatchersObject = { return {message, pass}; }, - toBeGreaterThan(actual: number, expected: number) { - ensureNumbers(actual, expected, '.toBeGreaterThan'); - const pass = actual > expected; + toBeGreaterThan(received: number, expected: number) { + const isNot = this.isNot; + const options = { + isNot, + promise: this.promise, + }; + ensureNumbers(received, expected, '.toBeGreaterThan'); + + const pass = received > expected; + const message = () => - matcherHint('.toBeGreaterThan', undefined, undefined, { - isNot: this.isNot, - }) + + matcherHint('toBeGreaterThan', undefined, undefined, options) + '\n\n' + - `Expected: ${printExpected(expected)}\n` + - `Received: ${printReceived(actual)}`; + `Expected:${isNot ? ' not' : ''} > ${printExpected(expected)}\n` + + `Received:${isNot ? ' ' : ''} ${printReceived(received)}`; + return {message, pass}; }, - toBeGreaterThanOrEqual(actual: number, expected: number) { - ensureNumbers(actual, expected, '.toBeGreaterThanOrEqual'); - const pass = actual >= expected; + toBeGreaterThanOrEqual(received: number, expected: number) { + const isNot = this.isNot; + const options = { + isNot, + promise: this.promise, + }; + ensureNumbers(received, expected, '.toBeGreaterThanOrEqual'); + + const pass = received >= expected; + const message = () => - matcherHint('.toBeGreaterThanOrEqual', undefined, undefined, { - isNot: this.isNot, - }) + + matcherHint('toBeGreaterThanOrEqual', undefined, undefined, options) + '\n\n' + - `Expected: ${printExpected(expected)}\n` + - `Received: ${printReceived(actual)}`; + `Expected:${isNot ? ' not' : ''} >= ${printExpected(expected)}\n` + + `Received:${isNot ? ' ' : ''} ${printReceived(received)}`; + return {message, pass}; }, @@ -214,29 +226,41 @@ const matchers: MatchersObject = { return {message, pass}; }, - toBeLessThan(actual: number, expected: number) { - ensureNumbers(actual, expected, '.toBeLessThan'); - const pass = actual < expected; + toBeLessThan(received: number, expected: number) { + const isNot = this.isNot; + const options = { + isNot, + promise: this.promise, + }; + ensureNumbers(received, expected, '.toBeLessThan'); + + const pass = received < expected; + const message = () => - matcherHint('.toBeLessThan', undefined, undefined, { - isNot: this.isNot, - }) + + matcherHint('toBeLessThan', undefined, undefined, options) + '\n\n' + - `Expected: ${printExpected(expected)}\n` + - `Received: ${printReceived(actual)}`; + `Expected:${isNot ? ' not' : ''} < ${printExpected(expected)}\n` + + `Received:${isNot ? ' ' : ''} ${printReceived(received)}`; + return {message, pass}; }, - toBeLessThanOrEqual(actual: number, expected: number) { - ensureNumbers(actual, expected, '.toBeLessThanOrEqual'); - const pass = actual <= expected; + toBeLessThanOrEqual(received: number, expected: number) { + const isNot = this.isNot; + const options = { + isNot, + promise: this.promise, + }; + ensureNumbers(received, expected, '.toBeLessThanOrEqual'); + + const pass = received <= expected; + const message = () => - matcherHint('.toBeLessThanOrEqual', undefined, undefined, { - isNot: this.isNot, - }) + + matcherHint('toBeLessThanOrEqual', undefined, undefined, options) + '\n\n' + - `Expected: ${printExpected(expected)}\n` + - `Received: ${printReceived(actual)}`; + `Expected:${isNot ? ' not' : ''} <= ${printExpected(expected)}\n` + + `Received:${isNot ? ' ' : ''} ${printReceived(received)}`; + return {message, pass}; }, From 1df98cb17de2a586213b76154e5f5a49d1cede5f Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Tue, 12 Feb 2019 21:52:29 +0100 Subject: [PATCH 2/5] contributing guide section about changelog entries (#7877) --- CONTRIBUTING.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c22883451815..c09425c85741 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -72,6 +72,14 @@ _Before_ submitting a pull request, please make sure the following is done… 1. If you haven't already, complete the CLA. +#### Changelog entries + +All changes that add a feature to or fix a bug in any of Jest's packages require a changelog entry containing the names of the packages affected, a description of the change, and the number of and link to the pull request. Try to match the structure of the existing entries. + +For significant changes to the documentation or website and things like cleanup, refactoring, and dependency updates, the "Chore & Maintenance" section of the changelog can be used. + +You can add or edit the changelog entry in the GitHub web interface once you have opened the pull request and know the number and link to it. + #### Testing Code that is written needs to be tested to ensure that it achieves the desired behaviour. Tests either fall into a unit test or an integration test. From 9ba62ada66f731880229073eb193e8cb60863ae3 Mon Sep 17 00:00:00 2001 From: George Buckingham Date: Tue, 12 Feb 2019 23:14:49 +0100 Subject: [PATCH 3/5] Fix image URLs (#7872) --- CHANGELOG.md | 1 + docs/SnapshotTesting.md | 11 +++++------ .../versioned_docs/version-24.0/SnapshotTesting.md | 11 +++++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24f72e8ba875..872870ca9577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - `[jest-mock]`: Migrate to TypeScript ([#7847](https://github.com/facebook/jest/pull/7847), [#7850](https://github.com/facebook/jest/pull/7850)) - `[jest-worker]`: Migrate to TypeScript ([#7853](https://github.com/facebook/jest/pull/7853)) - `[jest-haste-map]`: Migrate to TypeScript ([#7854](https://github.com/facebook/jest/pull/7854)) +- `[docs]`: Fix image paths in SnapshotTesting.md for current and version 24 ([#7872](https://github.com/facebook/jest/pull/7872)) ### Performance diff --git a/docs/SnapshotTesting.md b/docs/SnapshotTesting.md index c31926c68dd3..8f0d3b0c6be4 100644 --- a/docs/SnapshotTesting.md +++ b/docs/SnapshotTesting.md @@ -41,8 +41,7 @@ exports[`renders correctly 1`] = ` The snapshot artifact should be committed alongside code changes, and reviewed as part of your code review process. Jest uses [pretty-format](https://github.com/facebook/jest/tree/master/packages/pretty-format) to make snapshots human-readable during code review. On subsequent test runs Jest will simply compare the rendered output with the previous snapshot. If they match, the test will pass. If they don't match, either the test runner found a bug in your code (in this case, it's `` component) that should be fixed, or the implementation has changed and the snapshot needs to be updated. -> Note: The snapshot is directly scoped to the data you render – in our example it's `` component with page prop passed to it. This implies that even if any other file has missing props (Say, `App.js`) in the `` component, it will still pass the test as the test doesn't know the usage of `` component and it's scoped only to the `Link.react.js`. -> Also, Rendering the same component with different props in other snapshot tests will not affect the first one, as the tests don't know about each other. +> Note: The snapshot is directly scoped to the data you render – in our example it's `` component with page prop passed to it. This implies that even if any other file has missing props (Say, `App.js`) in the `` component, it will still pass the test as the test doesn't know the usage of `` component and it's scoped only to the `Link.react.js`. Also, Rendering the same component with different props in other snapshot tests will not affect the first one, as the tests don't know about each other. More information on how snapshot testing works and why we built it can be found on the [release blog post](https://jestjs.io/blog/2016/07/27/jest-14.html). We recommend reading [this blog post](http://benmccormick.org/2016/09/19/testing-with-jest-snapshots-first-impressions/) to get a good sense of when you should use snapshot testing. We also recommend watching this [egghead video](https://egghead.io/lessons/javascript-use-jest-s-snapshot-testing-feature?pl=testing-javascript-with-jest-a36c4074) on Snapshot Testing with Jest. @@ -64,7 +63,7 @@ it('renders correctly', () => { In that case, Jest will print this output: -![](/website/static/img/content/failedSnapshotTest.png) +![](/img/content/failedSnapshotTest.png) Since we just updated our component to point to a different address, it's reasonable to expect changes in the snapshot for this component. Our snapshot test case is failing because the snapshot for our updated component no longer matches the snapshot artifact for this test case. @@ -84,17 +83,17 @@ You can try out this functionality by cloning the [snapshot example](https://git Failed snapshots can also be updated interactively in watch mode: -![](/website/static/img/content/interactiveSnapshot.png) +![](/img/content/interactiveSnapshot.png) Once you enter Interactive Snapshot Mode, Jest will step you through the failed snapshots one test at a time and give you the opportunity to review the failed output. From here you can choose to update that snapshot or skip to the next: -![](/website/static/img/content/interactiveSnapshotUpdate.gif) +![](/img/content/interactiveSnapshotUpdate.gif) Once you're finished, Jest will give you a summary before returning back to watch mode: -![](/website/static/img/content/interactiveSnapshotDone.png) +![](/img/content/interactiveSnapshotDone.png) ### Inline Snapshots diff --git a/website/versioned_docs/version-24.0/SnapshotTesting.md b/website/versioned_docs/version-24.0/SnapshotTesting.md index df7c7ed847e3..072efda901b8 100644 --- a/website/versioned_docs/version-24.0/SnapshotTesting.md +++ b/website/versioned_docs/version-24.0/SnapshotTesting.md @@ -42,8 +42,7 @@ exports[`renders correctly 1`] = ` The snapshot artifact should be committed alongside code changes, and reviewed as part of your code review process. Jest uses [pretty-format](https://github.com/facebook/jest/tree/master/packages/pretty-format) to make snapshots human-readable during code review. On subsequent test runs Jest will simply compare the rendered output with the previous snapshot. If they match, the test will pass. If they don't match, either the test runner found a bug in your code (in this case, it's `` component) that should be fixed, or the implementation has changed and the snapshot needs to be updated. -> Note: The snapshot is directly scoped to the data you render – in our example it's `` component with page prop passed to it. This implies that even if any other file has missing props (Say, `App.js`) in the `` component, it will still pass the test as the test doesn't know the usage of `` component and it's scoped only to the `Link.react.js`. -> Also, Rendering the same component with different props in other snapshot tests will not affect the first one, as the tests don't know about each other. +> Note: The snapshot is directly scoped to the data you render – in our example it's `` component with page prop passed to it. This implies that even if any other file has missing props (Say, `App.js`) in the `` component, it will still pass the test as the test doesn't know the usage of `` component and it's scoped only to the `Link.react.js`. Also, Rendering the same component with different props in other snapshot tests will not affect the first one, as the tests don't know about each other. More information on how snapshot testing works and why we built it can be found on the [release blog post](https://jestjs.io/blog/2016/07/27/jest-14.html). We recommend reading [this blog post](http://benmccormick.org/2016/09/19/testing-with-jest-snapshots-first-impressions/) to get a good sense of when you should use snapshot testing. We also recommend watching this [egghead video](https://egghead.io/lessons/javascript-use-jest-s-snapshot-testing-feature?pl=testing-javascript-with-jest-a36c4074) on Snapshot Testing with Jest. @@ -65,7 +64,7 @@ it('renders correctly', () => { In that case, Jest will print this output: -![](/website/static/img/content/failedSnapshotTest.png) +![](/img/content/failedSnapshotTest.png) Since we just updated our component to point to a different address, it's reasonable to expect changes in the snapshot for this component. Our snapshot test case is failing because the snapshot for our updated component no longer matches the snapshot artifact for this test case. @@ -85,17 +84,17 @@ You can try out this functionality by cloning the [snapshot example](https://git Failed snapshots can also be updated interactively in watch mode: -![](/website/static/img/content/interactiveSnapshot.png) +![](/img/content/interactiveSnapshot.png) Once you enter Interactive Snapshot Mode, Jest will step you through the failed snapshots one test at a time and give you the opportunity to review the failed output. From here you can choose to update that snapshot or skip to the next: -![](/website/static/img/content/interactiveSnapshotUpdate.gif) +![](/img/content/interactiveSnapshotUpdate.gif) Once you're finished, Jest will give you a summary before returning back to watch mode: -![](/website/static/img/content/interactiveSnapshotDone.png) +![](/img/content/interactiveSnapshotDone.png) ### Inline Snapshots From 3f19f674161ec6b78dc07799cf41ea96defdd441 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 13 Feb 2019 09:50:43 +0100 Subject: [PATCH 4/5] chore: fix jest-mock spyOn argument inferring (#7878) --- packages/jest-mock/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index 4d7d3a567664..4015f09a1a16 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -940,7 +940,7 @@ class ModuleMockerClass { object: T, methodName: M, ): T[M] extends (...args: any[]) => any - ? SpyInstance, ArgsType> + ? SpyInstance, Parameters> : never; spyOn>( From a4a04b2d5d4ff0839b3f8f0973f09440135339ce Mon Sep 17 00:00:00 2001 From: Don Schrimsher Date: Wed, 13 Feb 2019 03:52:34 -0500 Subject: [PATCH 5/5] Fix custom async matcher stack traces (#7652) --- CHANGELOG.md | 1 + .../customMatcherStackTrace.test.js.snap | 33 ++++++-- .../expectAsyncMatcher.test.js.snap | 80 +++++++++++-------- e2e/__tests__/customMatcherStackTrace.test.js | 12 ++- .../__tests__/asynchronous.test.js | 18 +++++ .../{customMatcher.test.js => sync.test.js} | 0 .../__tests__/failure.test.js | 29 +++---- .../__tests__/success.test.js | 29 +++---- packages/expect/src/index.js | 14 +++- 9 files changed, 133 insertions(+), 83 deletions(-) create mode 100644 e2e/custom-matcher-stack-trace/__tests__/asynchronous.test.js rename e2e/custom-matcher-stack-trace/__tests__/{customMatcher.test.js => sync.test.js} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 872870ca9577..ca91b9d179c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Fixes - `[jest-cli]` Refactor `-o` and `--coverage` combined ([#7611](https://github.com/facebook/jest/pull/7611)) +- `[expect]` Fix custom async matcher stack trace ([#7652](https://github.com/facebook/jest/pull/7652)) ### Chore & Maintenance diff --git a/e2e/__tests__/__snapshots__/customMatcherStackTrace.test.js.snap b/e2e/__tests__/__snapshots__/customMatcherStackTrace.test.js.snap index 8faa1ffd5ebd..15df98763079 100644 --- a/e2e/__tests__/__snapshots__/customMatcherStackTrace.test.js.snap +++ b/e2e/__tests__/__snapshots__/customMatcherStackTrace.test.js.snap @@ -1,7 +1,26 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`custom async matchers 1`] = ` +FAIL __tests__/asynchronous.test.js + ✕ showing the stack trace for an async matcher + + ● showing the stack trace for an async matcher + + We expect the stack trace and code fence for this matcher to be shown in the console. + + 9 | + 10 | test('showing the stack trace for an async matcher', async () => { + > 11 | await expect(true).toThrowCustomAsyncMatcherError(); + | ^ + 12 | }); + 13 | + 14 | async function toThrowCustomAsyncMatcherError() { + + at Object.toThrowCustomAsyncMatcherError (__tests__/asynchronous.test.js:11:22) +`; + exports[`works with custom matchers 1`] = ` -FAIL __tests__/customMatcher.test.js +FAIL __tests__/sync.test.js Custom matcher ✓ passes ✓ fails @@ -19,10 +38,10 @@ FAIL __tests__/customMatcher.test.js 47 | 48 | // This expecation fails due to an error we throw (intentionally) - at Error (__tests__/customMatcher.test.js:45:13) - at baz (__tests__/customMatcher.test.js:43:23) - at bar (__tests__/customMatcher.test.js:42:23) - at foo (__tests__/customMatcher.test.js:52:7) - at Object.callback (__tests__/customMatcher.test.js:11:18) - at Object.toCustomMatch (__tests__/customMatcher.test.js:53:8) + at Error (__tests__/sync.test.js:45:13) + at baz (__tests__/sync.test.js:43:23) + at bar (__tests__/sync.test.js:42:23) + at foo (__tests__/sync.test.js:52:7) + at Object.callback (__tests__/sync.test.js:11:18) + at Object.toCustomMatch (__tests__/sync.test.js:53:8) `; diff --git a/e2e/__tests__/__snapshots__/expectAsyncMatcher.test.js.snap b/e2e/__tests__/__snapshots__/expectAsyncMatcher.test.js.snap index 6ef5f68f3fca..b7d07fa98db9 100644 --- a/e2e/__tests__/__snapshots__/expectAsyncMatcher.test.js.snap +++ b/e2e/__tests__/__snapshots__/expectAsyncMatcher.test.js.snap @@ -10,22 +10,40 @@ FAIL __tests__/failure.test.js ● fail with expected non promise values Expected value to have length: + 2 + Received: + 1 + received.length: + 1 + + 11 | + 12 | it('fail with expected non promise values', () => + > 13 | expect([1]).toHaveLengthAsync(Promise.resolve(2))); + | ^ + 14 | + 15 | it('fail with expected non promise values and not', () => + 16 | expect([1, 2]).not.toHaveLengthAsync(Promise.resolve(2))); - 2 - Received: - 1 - received.length: - 1 + at Object.toHaveLengthAsync (__tests__/failure.test.js:13:15) ● fail with expected non promise values and not Expected value to not have length: + 2 + Received: + 1,2 + received.length: + 2 + + 14 | + 15 | it('fail with expected non promise values and not', () => + > 16 | expect([1, 2]).not.toHaveLengthAsync(Promise.resolve(2))); + | ^ + 17 | + 18 | it('fail with expected promise values', () => + 19 | expect(Promise.resolve([1])).resolves.toHaveLengthAsync(Promise.resolve(2))); - 2 - Received: - 1,2 - received.length: - 2 + at Object.toHaveLengthAsync (__tests__/failure.test.js:16:22) ● fail with expected promise values @@ -36,19 +54,15 @@ FAIL __tests__/failure.test.js received.length: 1 - 22 | - 23 | it('fail with expected promise values', async () => { - > 24 | await (expect(Promise.resolve([1])): any).resolves.toHaveLengthAsync( - | ^ - 25 | Promise.resolve(2) - 26 | ); - 27 | }); + 17 | + 18 | it('fail with expected promise values', () => + > 19 | expect(Promise.resolve([1])).resolves.toHaveLengthAsync(Promise.resolve(2))); + | ^ + 20 | + 21 | it('fail with expected promise values and not', () => + 22 | expect(Promise.resolve([1, 2])).resolves.not.toHaveLengthAsync( - at Object.toHaveLengthAsync (__tests__/failure.test.js:24:54) - at asyncGeneratorStep (__tests__/failure.test.js:11:103) - at _next (__tests__/failure.test.js:13:194) - at __tests__/failure.test.js:13:364 - at Object. (__tests__/failure.test.js:13:97) + at Object.toHaveLengthAsync (__tests__/failure.test.js:19:41) ● fail with expected promise values and not @@ -59,17 +73,13 @@ FAIL __tests__/failure.test.js received.length: 2 - 28 | - 29 | it('fail with expected promise values and not', async () => { - > 30 | await (expect(Promise.resolve([1, 2])).resolves.not: any).toHaveLengthAsync( - | ^ - 31 | Promise.resolve(2) - 32 | ); - 33 | }); - - at Object.toHaveLengthAsync (__tests__/failure.test.js:30:61) - at asyncGeneratorStep (__tests__/failure.test.js:11:103) - at _next (__tests__/failure.test.js:13:194) - at __tests__/failure.test.js:13:364 - at Object. (__tests__/failure.test.js:13:97) + 20 | + 21 | it('fail with expected promise values and not', () => + > 22 | expect(Promise.resolve([1, 2])).resolves.not.toHaveLengthAsync( + | ^ + 23 | Promise.resolve(2) + 24 | )); + 25 | + + at Object.toHaveLengthAsync (__tests__/failure.test.js:22:48) `; diff --git a/e2e/__tests__/customMatcherStackTrace.test.js b/e2e/__tests__/customMatcherStackTrace.test.js index c9b13df573e0..be338b2b7ee7 100644 --- a/e2e/__tests__/customMatcherStackTrace.test.js +++ b/e2e/__tests__/customMatcherStackTrace.test.js @@ -12,7 +12,7 @@ import {extractSummary} from '../Utils'; import {wrap} from 'jest-snapshot-serializer-raw'; test('works with custom matchers', () => { - const {stderr} = runJest('custom-matcher-stack-trace'); + const {stderr} = runJest('custom-matcher-stack-trace', ['sync.test.js']); let {rest} = extractSummary(stderr); @@ -23,3 +23,13 @@ test('works with custom matchers', () => { expect(wrap(rest)).toMatchSnapshot(); }); + +test('custom async matchers', () => { + const {stderr} = runJest('custom-matcher-stack-trace', [ + 'asynchronous.test.js', + ]); + + const {rest} = extractSummary(stderr); + + expect(wrap(rest)).toMatchSnapshot(); +}); diff --git a/e2e/custom-matcher-stack-trace/__tests__/asynchronous.test.js b/e2e/custom-matcher-stack-trace/__tests__/asynchronous.test.js new file mode 100644 index 000000000000..33061bffa53e --- /dev/null +++ b/e2e/custom-matcher-stack-trace/__tests__/asynchronous.test.js @@ -0,0 +1,18 @@ +/** + * 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. + */ + +expect.extend({toThrowCustomAsyncMatcherError}); + +test('showing the stack trace for an async matcher', async () => { + await expect(true).toThrowCustomAsyncMatcherError(); +}); + +async function toThrowCustomAsyncMatcherError() { + const message = () => + 'We expect the stack trace and code fence for this matcher to be shown in the console.'; + return {message, pass: false}; +} diff --git a/e2e/custom-matcher-stack-trace/__tests__/customMatcher.test.js b/e2e/custom-matcher-stack-trace/__tests__/sync.test.js similarity index 100% rename from e2e/custom-matcher-stack-trace/__tests__/customMatcher.test.js rename to e2e/custom-matcher-stack-trace/__tests__/sync.test.js diff --git a/e2e/expect-async-matcher/__tests__/failure.test.js b/e2e/expect-async-matcher/__tests__/failure.test.js index e10b1947c556..206948d90a9b 100644 --- a/e2e/expect-async-matcher/__tests__/failure.test.js +++ b/e2e/expect-async-matcher/__tests__/failure.test.js @@ -4,30 +4,21 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -'use strict'; import {toHaveLengthAsync} from '../matchers'; -expect.extend({ - toHaveLengthAsync, -}); +expect.extend({toHaveLengthAsync}); -it('fail with expected non promise values', async () => { - await (expect([1]): any).toHaveLengthAsync(Promise.resolve(2)); -}); +it('fail with expected non promise values', () => + expect([1]).toHaveLengthAsync(Promise.resolve(2))); -it('fail with expected non promise values and not', async () => { - await (expect([1, 2]): any).not.toHaveLengthAsync(Promise.resolve(2)); -}); +it('fail with expected non promise values and not', () => + expect([1, 2]).not.toHaveLengthAsync(Promise.resolve(2))); -it('fail with expected promise values', async () => { - await (expect(Promise.resolve([1])): any).resolves.toHaveLengthAsync( - Promise.resolve(2) - ); -}); +it('fail with expected promise values', () => + expect(Promise.resolve([1])).resolves.toHaveLengthAsync(Promise.resolve(2))); -it('fail with expected promise values and not', async () => { - await (expect(Promise.resolve([1, 2])).resolves.not: any).toHaveLengthAsync( +it('fail with expected promise values and not', () => + expect(Promise.resolve([1, 2])).resolves.not.toHaveLengthAsync( Promise.resolve(2) - ); -}); + )); diff --git a/e2e/expect-async-matcher/__tests__/success.test.js b/e2e/expect-async-matcher/__tests__/success.test.js index ac3a8a738b94..8f597b9788ea 100644 --- a/e2e/expect-async-matcher/__tests__/success.test.js +++ b/e2e/expect-async-matcher/__tests__/success.test.js @@ -4,30 +4,21 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -'use strict'; import {toHaveLengthAsync} from '../matchers'; -expect.extend({ - toHaveLengthAsync, -}); +expect.extend({toHaveLengthAsync}); -it('works with expected non promise values', async () => { - await (expect([1]): any).toHaveLengthAsync(Promise.resolve(1)); -}); +it('works with expected non promise values', () => + expect([1]).toHaveLengthAsync(Promise.resolve(1))); -it('works with expected non promise values and not', async () => { - await (expect([1, 2]): any).not.toHaveLengthAsync(Promise.resolve(1)); -}); +it('works with expected non promise values and not', () => + expect([1, 2]).not.toHaveLengthAsync(Promise.resolve(1))); -it('works with expected promise values', async () => { - await (expect(Promise.resolve([1])).resolves: any).toHaveLengthAsync( - Promise.resolve(1) - ); -}); +it('works with expected promise values', () => + expect(Promise.resolve([1])).resolves.toHaveLengthAsync(Promise.resolve(1))); -it('works with expected promise values and not', async () => { - await (expect(Promise.resolve([1, 2])).resolves.not: any).toHaveLengthAsync( +it('works with expected promise values and not', () => + expect(Promise.resolve([1, 2])).resolves.not.toHaveLengthAsync( Promise.resolve(1) - ); -}); + )); diff --git a/packages/expect/src/index.js b/packages/expect/src/index.js index 1c41fc8e683f..1f50866a4e67 100644 --- a/packages/expect/src/index.js +++ b/packages/expect/src/index.js @@ -251,7 +251,10 @@ const makeThrowingMatcher = ( utils, }; - const processResult = (result: SyncExpectationResult) => { + const processResult = ( + result: SyncExpectationResult, + asyncError?: JestAssertionError, + ) => { _validateResult(result); getState().assertionCalls++; @@ -264,6 +267,9 @@ const makeThrowingMatcher = ( if (err) { error = err; error.message = message; + } else if (asyncError) { + error = asyncError; + error.message = message; } else { error = new JestAssertionError(message); @@ -307,9 +313,13 @@ const makeThrowingMatcher = ( if (isPromise((potentialResult: any))) { const asyncResult = ((potentialResult: any): AsyncExpectationResult); + const asyncError = new JestAssertionError(); + if (Error.captureStackTrace) { + Error.captureStackTrace(asyncError, throwingMatcher); + } return asyncResult - .then(aResult => processResult(aResult)) + .then(aResult => processResult(aResult, asyncError)) .catch(error => handlError(error)); } else { const syncResult = ((potentialResult: any): SyncExpectationResult);