From 0b69ab0959aedf0810d44b15022a27a4a2ff8d84 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes da Costa Date: Sun, 7 Jul 2019 17:00:05 +0100 Subject: [PATCH] fix: make test suite exit early if beforeEach hook fails (closes #6527) --- CHANGELOG.md | 1 + .../beforeEachAbortsTests.test.ts.snap | 435 ++++++++++++++++++ e2e/__tests__/beforeEachAbortsTests.test.ts | 72 +++ .../__tests__/global/afterAllHook.test.js | 19 + .../__tests__/global/afterEachHook.test.js | 19 + .../__tests__/global/skipsTests.test.js | 27 ++ .../nestedBlocks/afterAllHook.test.js | 31 ++ .../nestedBlocks/afterEachHook.test.js | 31 ++ .../testsInDifferentBlocks.test.js | 27 ++ .../singleBlock/afterAllHook.test.js | 21 + .../singleBlock/afterEachHook.test.js | 21 + .../multipleBeforeEachHooks.test.js | 22 + .../singleBlock/multipleTests.test.js | 21 + .../__tests__/singleBlock/singleTest.test.js | 17 + e2e/before-each-aborts-tests/package.json | 6 + packages/jest-jasmine2/src/jasmine/Spec.ts | 49 +- 16 files changed, 803 insertions(+), 16 deletions(-) create mode 100644 e2e/__tests__/__snapshots__/beforeEachAbortsTests.test.ts.snap create mode 100644 e2e/__tests__/beforeEachAbortsTests.test.ts create mode 100644 e2e/before-each-aborts-tests/__tests__/global/afterAllHook.test.js create mode 100644 e2e/before-each-aborts-tests/__tests__/global/afterEachHook.test.js create mode 100755 e2e/before-each-aborts-tests/__tests__/global/skipsTests.test.js create mode 100644 e2e/before-each-aborts-tests/__tests__/nestedBlocks/afterAllHook.test.js create mode 100644 e2e/before-each-aborts-tests/__tests__/nestedBlocks/afterEachHook.test.js create mode 100644 e2e/before-each-aborts-tests/__tests__/nestedBlocks/testsInDifferentBlocks.test.js create mode 100644 e2e/before-each-aborts-tests/__tests__/singleBlock/afterAllHook.test.js create mode 100644 e2e/before-each-aborts-tests/__tests__/singleBlock/afterEachHook.test.js create mode 100644 e2e/before-each-aborts-tests/__tests__/singleBlock/multipleBeforeEachHooks.test.js create mode 100755 e2e/before-each-aborts-tests/__tests__/singleBlock/multipleTests.test.js create mode 100644 e2e/before-each-aborts-tests/__tests__/singleBlock/singleTest.test.js create mode 100644 e2e/before-each-aborts-tests/package.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f377ac43c15..0e2935bb7f79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - `[jest-snapshot]` Prevent inline snapshots from drifting when inline snapshots are updated ([#8492](https://github.com/facebook/jest/pull/8492)) - `[jest-haste-map]` Don't throw on missing mapper in Node crawler ([#8558](https://github.com/facebook/jest/pull/8558)) - `[jest-core]` Fix incorrect `passWithNoTests` warning ([#8595](https://github.com/facebook/jest/pull/8595)) +- `[jest-jasmine2]` Make test suite exit early if a `beforeEach` hook fails ([#8654](https://github.com/facebook/jest/pull/8654)) ### Chore & Maintenance diff --git a/e2e/__tests__/__snapshots__/beforeEachAbortsTests.test.ts.snap b/e2e/__tests__/__snapshots__/beforeEachAbortsTests.test.ts.snap new file mode 100644 index 000000000000..a7517ccdffb7 --- /dev/null +++ b/e2e/__tests__/__snapshots__/beforeEachAbortsTests.test.ts.snap @@ -0,0 +1,435 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`in the global context does not run any tests if a global beforeEach hook fails 1`] = ` +FAIL __tests__/global/skipsTests.test.js + ● Console + + console.log __tests__/global/skipsTests.test.js:9 + global beforeEach + console.log __tests__/global/skipsTests.test.js:9 + global beforeEach + console.log __tests__/global/skipsTests.test.js:9 + global beforeEach + + ● global test + + The global beforeEach hook failed. + + 8 | beforeEach(() => { + 9 | console.log('global beforeEach'); + > 10 | throw new Error('The global beforeEach hook failed.'); + | ^ + 11 | }); + 12 | + 13 | it('global test', () => { + + at Object..beforeEach (__tests__/global/skipsTests.test.js:10:9) + + ● test suite › outer test + + The global beforeEach hook failed. + + 8 | beforeEach(() => { + 9 | console.log('global beforeEach'); + > 10 | throw new Error('The global beforeEach hook failed.'); + | ^ + 11 | }); + 12 | + 13 | it('global test', () => { + + at Object..beforeEach (__tests__/global/skipsTests.test.js:10:9) + + ● test suite › nested block › nested test + + The global beforeEach hook failed. + + 8 | beforeEach(() => { + 9 | console.log('global beforeEach'); + > 10 | throw new Error('The global beforeEach hook failed.'); + | ^ + 11 | }); + 12 | + 13 | it('global test', () => { + + at Object..beforeEach (__tests__/global/skipsTests.test.js:10:9) +`; + +exports[`in the global context does not run any tests if a global beforeEach hook fails 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 3 failed, 3 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /global\\/skipsTests.test.js/i. +`; + +exports[`in the global context still runs global afterAll hooks if a global beforeEach fails 1`] = ` +FAIL __tests__/global/afterAllHook.test.js + ● Console + + console.log __tests__/global/afterAllHook.test.js:9 + global beforeEach + console.log __tests__/global/afterAllHook.test.js:18 + global afterAll + + ● global test + + The global beforeEach hook failed. + + 8 | beforeEach(() => { + 9 | console.log('global beforeEach'); + > 10 | throw new Error('The global beforeEach hook failed.'); + | ^ + 11 | }); + 12 | + 13 | it('global test', () => { + + at Object..beforeEach (__tests__/global/afterAllHook.test.js:10:9) +`; + +exports[`in the global context still runs global afterAll hooks if a global beforeEach fails 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /global\\/afterAllHook.test.js/i. +`; + +exports[`in the global context still runs global afterEach hooks if a global beforeEach fails 1`] = ` +FAIL __tests__/global/afterEachHook.test.js + ● Console + + console.log __tests__/global/afterEachHook.test.js:9 + global beforeEach + console.log __tests__/global/afterEachHook.test.js:18 + global afterEach + + ● global test + + The global beforeEach hook failed. + + 8 | beforeEach(() => { + 9 | console.log('global beforeEach'); + > 10 | throw new Error('The global beforeEach hook failed.'); + | ^ + 11 | }); + 12 | + 13 | it('global test', () => { + + at Object..beforeEach (__tests__/global/afterEachHook.test.js:10:9) +`; + +exports[`in the global context still runs global afterEach hooks if a global beforeEach fails 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /global\\/afterEachHook.test.js/i. +`; + +exports[`inside deeply nested blocks can cancel tests only for the nested describe block it is in 1`] = ` +FAIL __tests__/nestedBlocks/testsInDifferentBlocks.test.js + ● Console + + console.log __tests__/nestedBlocks/testsInDifferentBlocks.test.js:10 + outer test + console.log __tests__/nestedBlocks/testsInDifferentBlocks.test.js:15 + nested beforeEach + console.log __tests__/nestedBlocks/testsInDifferentBlocks.test.js:15 + nested beforeEach + + ● tests for the nested beforeEach › nested block › first nested test + + The nested beforeEach hook failed. + + 14 | beforeEach(() => { + 15 | console.log('nested beforeEach'); + > 16 | throw new Error('The nested beforeEach hook failed.'); + | ^ + 17 | }); + 18 | + 19 | it('first nested test', () => { + + at Object.beforeEach (__tests__/nestedBlocks/testsInDifferentBlocks.test.js:16:13) + + ● tests for the nested beforeEach › nested block › second nested test + + The nested beforeEach hook failed. + + 14 | beforeEach(() => { + 15 | console.log('nested beforeEach'); + > 16 | throw new Error('The nested beforeEach hook failed.'); + | ^ + 17 | }); + 18 | + 19 | it('first nested test', () => { + + at Object.beforeEach (__tests__/nestedBlocks/testsInDifferentBlocks.test.js:16:13) +`; + +exports[`inside deeply nested blocks can cancel tests only for the nested describe block it is in 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 2 failed, 1 passed, 3 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /nestedBlocks\\/testsInDifferentBlocks.test.js/i. +`; + +exports[`inside deeply nested blocks still runs afterEach hooks for the test whose beforeEach failed 1`] = ` +FAIL __tests__/nestedBlocks/afterEachHook.test.js + ● Console + + console.log __tests__/nestedBlocks/afterEachHook.test.js:10 + outer test + console.log __tests__/nestedBlocks/afterEachHook.test.js:29 + outer afterEach + console.log __tests__/nestedBlocks/afterEachHook.test.js:15 + nested beforeEach + console.log __tests__/nestedBlocks/afterEachHook.test.js:24 + nested afterEach + console.log __tests__/nestedBlocks/afterEachHook.test.js:29 + outer afterEach + + ● afterEach hooks with a nested beforeEach › nested block › nested test + + The nested beforeEach hook failed. + + 14 | beforeEach(() => { + 15 | console.log('nested beforeEach'); + > 16 | throw new Error('The nested beforeEach hook failed.'); + | ^ + 17 | }); + 18 | + 19 | it('nested test', () => { + + at Object.beforeEach (__tests__/nestedBlocks/afterEachHook.test.js:16:13) +`; + +exports[`inside deeply nested blocks still runs afterEach hooks for the test whose beforeEach failed 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 passed, 2 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /nestedBlocks\\/afterEachHook.test.js/i. +`; + +exports[`inside deeply nested blocks still runs the afterAll hooks if a nested beforeEach fails 1`] = ` +FAIL __tests__/nestedBlocks/afterAllHook.test.js + ● Console + + console.log __tests__/nestedBlocks/afterAllHook.test.js:10 + outer test + console.log __tests__/nestedBlocks/afterAllHook.test.js:15 + nested beforeEach + console.log __tests__/nestedBlocks/afterAllHook.test.js:24 + nested afterAll + console.log __tests__/nestedBlocks/afterAllHook.test.js:29 + outer afterAll + + ● afterAll hooks with a nested beforeEach › nested block › nested test + + The nested beforeEach hook failed. + + 14 | beforeEach(() => { + 15 | console.log('nested beforeEach'); + > 16 | throw new Error('The nested beforeEach hook failed.'); + | ^ + 17 | }); + 18 | + 19 | it('nested test', () => { + + at Object.beforeEach (__tests__/nestedBlocks/afterAllHook.test.js:16:13) +`; + +exports[`inside deeply nested blocks still runs the afterAll hooks if a nested beforeEach fails 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 passed, 2 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /nestedBlocks\\/afterAllHook.test.js/i. +`; + +exports[`without nested blocks does not run any of the tests if beforeEach fails 1`] = ` +FAIL __tests__/singleBlock/multipleTests.test.js + ● Console + + console.log __tests__/singleBlock/multipleTests.test.js:10 + beforeEach + console.log __tests__/singleBlock/multipleTests.test.js:10 + beforeEach + + ● a block with multiple tests › skipped first test + + The beforeEach hook failed. + + 9 | beforeEach(() => { + 10 | console.log('beforeEach'); + > 11 | throw new Error('The beforeEach hook failed.'); + | ^ + 12 | }); + 13 | + 14 | test('skipped first test', () => { + + at Object.beforeEach (__tests__/singleBlock/multipleTests.test.js:11:11) + + ● a block with multiple tests › skipped second test + + The beforeEach hook failed. + + 9 | beforeEach(() => { + 10 | console.log('beforeEach'); + > 11 | throw new Error('The beforeEach hook failed.'); + | ^ + 12 | }); + 13 | + 14 | test('skipped first test', () => { + + at Object.beforeEach (__tests__/singleBlock/multipleTests.test.js:11:11) +`; + +exports[`without nested blocks does not run any of the tests if beforeEach fails 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 2 failed, 2 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /singleBlock\\/multipleTests.test.js/i. +`; + +exports[`without nested blocks does not run the test if beforeEach fails 1`] = ` +FAIL __tests__/singleBlock/singleTest.test.js + ● Console + + console.log __tests__/singleBlock/singleTest.test.js:10 + beforeEach + + ● a block with a single test › skipped test + + The beforeEach hook failed. + + 9 | beforeEach(() => { + 10 | console.log('beforeEach'); + > 11 | throw new Error('The beforeEach hook failed.'); + | ^ + 12 | }); + 13 | + 14 | test('skipped test', () => { + + at Object.beforeEach (__tests__/singleBlock/singleTest.test.js:11:11) +`; + +exports[`without nested blocks does not run the test if beforeEach fails 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /singleBlock\\/singleTest.test.js/i. +`; + +exports[`without nested blocks runs all of the beforeEach hooks if one fails but does not run the tests 1`] = ` +FAIL __tests__/singleBlock/multipleBeforeEachHooks.test.js + ● Console + + console.log __tests__/singleBlock/multipleBeforeEachHooks.test.js:10 + first beforeEach + console.log __tests__/singleBlock/multipleBeforeEachHooks.test.js:15 + second beforeEach + + ● a block with multiple beforeEach hooks › skipped test + + The first beforeEach hook failed. + + 9 | beforeEach(() => { + 10 | console.log('first beforeEach'); + > 11 | throw new Error('The first beforeEach hook failed.'); + | ^ + 12 | }); + 13 | + 14 | beforeEach(() => { + + at Object.beforeEach (__tests__/singleBlock/multipleBeforeEachHooks.test.js:11:11) + + ● a block with multiple beforeEach hooks › skipped test + + The second beforeEach hook failed. + + 14 | beforeEach(() => { + 15 | console.log('second beforeEach'); + > 16 | throw new Error('The second beforeEach hook failed.'); + | ^ + 17 | }); + 18 | + 19 | test('skipped test', () => { + + at Object.beforeEach (__tests__/singleBlock/multipleBeforeEachHooks.test.js:16:11) +`; + +exports[`without nested blocks runs all of the beforeEach hooks if one fails but does not run the tests 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /singleBlock\\/multipleBeforeEachHooks.test.js/i. +`; + +exports[`without nested blocks still runs afterEach hook if the beforeEach hook fails 1`] = ` +FAIL __tests__/singleBlock/afterEachHook.test.js + ● Console + + console.log __tests__/singleBlock/afterEachHook.test.js:10 + beforeEach + console.log __tests__/singleBlock/afterEachHook.test.js:19 + afterEach + + ● a block with afterEach hooks › skipped test + + The beforeEach hook failed. + + 9 | beforeEach(() => { + 10 | console.log('beforeEach'); + > 11 | throw new Error('The beforeEach hook failed.'); + | ^ + 12 | }); + 13 | + 14 | test('skipped test', () => { + + at Object.beforeEach (__tests__/singleBlock/afterEachHook.test.js:11:11) +`; + +exports[`without nested blocks still runs afterEach hook if the beforeEach hook fails 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /singleBlock\\/afterEachHook.test.js/i. +`; + +exports[`without nested blocks still runs the afterAll hook if the beforeEach hook fails 1`] = ` +FAIL __tests__/singleBlock/afterAllHook.test.js + ● Console + + console.log __tests__/singleBlock/afterAllHook.test.js:10 + beforeEach + console.log __tests__/singleBlock/afterAllHook.test.js:19 + afterAll + + ● a block with an afterAll hook › skipped test + + The beforeEach hook failed. + + 9 | beforeEach(() => { + 10 | console.log('beforeEach'); + > 11 | throw new Error('The beforeEach hook failed.'); + | ^ + 12 | }); + 13 | + 14 | test('skipped test', () => { + + at Object.beforeEach (__tests__/singleBlock/afterAllHook.test.js:11:11) +`; + +exports[`without nested blocks still runs the afterAll hook if the beforeEach hook fails 2`] = ` +Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /singleBlock\\/afterAllHook.test.js/i. +`; diff --git a/e2e/__tests__/beforeEachAbortsTests.test.ts b/e2e/__tests__/beforeEachAbortsTests.test.ts new file mode 100644 index 000000000000..b1a949d5d702 --- /dev/null +++ b/e2e/__tests__/beforeEachAbortsTests.test.ts @@ -0,0 +1,72 @@ +/** + * 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. + */ + +import path from 'path'; +import {wrap} from 'jest-snapshot-serializer-raw'; +import runJest from '../runJest'; +import {extractSummary} from '../Utils'; + +const dir = path.resolve(__dirname, '../before-each-aborts-tests'); + +const runAgainstSnapshot = testPath => { + const {status, stderr} = runJest(dir, [testPath]); + const {summary, rest} = extractSummary(stderr); + + expect(status).toBe(1); + expect(wrap(rest)).toMatchSnapshot(); + expect(wrap(summary)).toMatchSnapshot(); +}; + +describe('in the global context', () => { + test('does not run any tests if a global beforeEach hook fails', () => { + runAgainstSnapshot('global/skipsTests.test.js'); + }); + + test('still runs global afterEach hooks if a global beforeEach fails', () => { + runAgainstSnapshot('global/afterEachHook.test.js'); + }); + + test('still runs global afterAll hooks if a global beforeEach fails', () => { + runAgainstSnapshot('global/afterAllHook.test.js'); + }); +}); + +describe('without nested blocks', () => { + test('does not run the test if beforeEach fails', () => { + runAgainstSnapshot('singleBlock/singleTest.test.js'); + }); + + test('does not run any of the tests if beforeEach fails', () => { + runAgainstSnapshot('singleBlock/multipleTests.test.js'); + }); + + test('runs all of the beforeEach hooks if one fails but does not run the tests', () => { + runAgainstSnapshot('singleBlock/multipleBeforeEachHooks.test.js'); + }); + + test('still runs afterEach hook if the beforeEach hook fails', () => { + runAgainstSnapshot('singleBlock/afterEachHook.test.js'); + }); + + test('still runs the afterAll hook if the beforeEach hook fails', () => { + runAgainstSnapshot('singleBlock/afterAllHook.test.js'); + }); +}); + +describe('inside deeply nested blocks', () => { + test('can cancel tests only for the nested describe block it is in', () => { + runAgainstSnapshot('nestedBlocks/testsInDifferentBlocks.test.js'); + }); + + test('still runs the afterAll hooks if a nested beforeEach fails', () => { + runAgainstSnapshot('nestedBlocks/afterAllHook.test.js'); + }); + + test('still runs afterEach hooks for the test whose beforeEach failed', () => { + runAgainstSnapshot('nestedBlocks/afterEachHook.test.js'); + }); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/global/afterAllHook.test.js b/e2e/before-each-aborts-tests/__tests__/global/afterAllHook.test.js new file mode 100644 index 000000000000..541dd2efaf7f --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/global/afterAllHook.test.js @@ -0,0 +1,19 @@ +/** + * 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. + */ + +beforeEach(() => { + console.log('global beforeEach'); + throw new Error('The global beforeEach hook failed.'); +}); + +it('global test', () => { + console.log('global test'); +}); + +afterAll(() => { + console.log('global afterAll'); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/global/afterEachHook.test.js b/e2e/before-each-aborts-tests/__tests__/global/afterEachHook.test.js new file mode 100644 index 000000000000..5cf7a8b41cce --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/global/afterEachHook.test.js @@ -0,0 +1,19 @@ +/** + * 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. + */ + +beforeEach(() => { + console.log('global beforeEach'); + throw new Error('The global beforeEach hook failed.'); +}); + +it('global test', () => { + console.log('global test'); +}); + +afterEach(() => { + console.log('global afterEach'); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/global/skipsTests.test.js b/e2e/before-each-aborts-tests/__tests__/global/skipsTests.test.js new file mode 100755 index 000000000000..68d8f91684dc --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/global/skipsTests.test.js @@ -0,0 +1,27 @@ +/** + * 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. + */ + +beforeEach(() => { + console.log('global beforeEach'); + throw new Error('The global beforeEach hook failed.'); +}); + +it('global test', () => { + console.log('outer test'); +}); + +describe('test suite', () => { + it('outer test', () => { + console.log('outer test'); + }); + + describe('nested block', () => { + it('nested test', () => { + console.log('nested test'); + }); + }); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/nestedBlocks/afterAllHook.test.js b/e2e/before-each-aborts-tests/__tests__/nestedBlocks/afterAllHook.test.js new file mode 100644 index 000000000000..3f930a867701 --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/nestedBlocks/afterAllHook.test.js @@ -0,0 +1,31 @@ +/** + * 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. + */ + +describe('afterAll hooks with a nested beforeEach', () => { + it('outer test', () => { + console.log('outer test'); + }); + + describe('nested block', () => { + beforeEach(() => { + console.log('nested beforeEach'); + throw new Error('The nested beforeEach hook failed.'); + }); + + it('nested test', () => { + console.log('nested test'); + }); + + afterAll(() => { + console.log('nested afterAll'); + }); + }); + + afterAll(() => { + console.log('outer afterAll'); + }); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/nestedBlocks/afterEachHook.test.js b/e2e/before-each-aborts-tests/__tests__/nestedBlocks/afterEachHook.test.js new file mode 100644 index 000000000000..6bba12925f7d --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/nestedBlocks/afterEachHook.test.js @@ -0,0 +1,31 @@ +/** + * 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. + */ + +describe('afterEach hooks with a nested beforeEach', () => { + it('outer test', () => { + console.log('outer test'); + }); + + describe('nested block', () => { + beforeEach(() => { + console.log('nested beforeEach'); + throw new Error('The nested beforeEach hook failed.'); + }); + + it('nested test', () => { + console.log('nested test'); + }); + + afterEach(() => { + console.log('nested afterEach'); + }); + }); + + afterEach(() => { + console.log('outer afterEach'); + }); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/nestedBlocks/testsInDifferentBlocks.test.js b/e2e/before-each-aborts-tests/__tests__/nestedBlocks/testsInDifferentBlocks.test.js new file mode 100644 index 000000000000..fb349ccf7d10 --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/nestedBlocks/testsInDifferentBlocks.test.js @@ -0,0 +1,27 @@ +/** + * 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. + */ + +describe('tests for the nested beforeEach', () => { + it('outer test', () => { + console.log('outer test'); + }); + + describe('nested block', () => { + beforeEach(() => { + console.log('nested beforeEach'); + throw new Error('The nested beforeEach hook failed.'); + }); + + it('first nested test', () => { + console.log('first nested test'); + }); + + it('second nested test', () => { + console.log('second nested test'); + }); + }); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/singleBlock/afterAllHook.test.js b/e2e/before-each-aborts-tests/__tests__/singleBlock/afterAllHook.test.js new file mode 100644 index 000000000000..252184d99062 --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/singleBlock/afterAllHook.test.js @@ -0,0 +1,21 @@ +/** + * 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. + */ + +describe('a block with an afterAll hook', () => { + beforeEach(() => { + console.log('beforeEach'); + throw new Error('The beforeEach hook failed.'); + }); + + test('skipped test', () => { + console.log('test'); + }); + + afterAll(() => { + console.log('afterAll'); + }); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/singleBlock/afterEachHook.test.js b/e2e/before-each-aborts-tests/__tests__/singleBlock/afterEachHook.test.js new file mode 100644 index 000000000000..c2569088f1e0 --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/singleBlock/afterEachHook.test.js @@ -0,0 +1,21 @@ +/** + * 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. + */ + +describe('a block with afterEach hooks', () => { + beforeEach(() => { + console.log('beforeEach'); + throw new Error('The beforeEach hook failed.'); + }); + + test('skipped test', () => { + console.log('test'); + }); + + afterEach(() => { + console.log('afterEach'); + }); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/singleBlock/multipleBeforeEachHooks.test.js b/e2e/before-each-aborts-tests/__tests__/singleBlock/multipleBeforeEachHooks.test.js new file mode 100644 index 000000000000..a6e35b593f02 --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/singleBlock/multipleBeforeEachHooks.test.js @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('a block with multiple beforeEach hooks', () => { + beforeEach(() => { + console.log('first beforeEach'); + throw new Error('The first beforeEach hook failed.'); + }); + + beforeEach(() => { + console.log('second beforeEach'); + throw new Error('The second beforeEach hook failed.'); + }); + + test('skipped test', () => { + console.log('test'); + }); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/singleBlock/multipleTests.test.js b/e2e/before-each-aborts-tests/__tests__/singleBlock/multipleTests.test.js new file mode 100755 index 000000000000..439b2923f706 --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/singleBlock/multipleTests.test.js @@ -0,0 +1,21 @@ +/** + * 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. + */ + +describe('a block with multiple tests', () => { + beforeEach(() => { + console.log('beforeEach'); + throw new Error('The beforeEach hook failed.'); + }); + + test('skipped first test', () => { + console.log('first test'); + }); + + test('skipped second test', () => { + console.log('second test'); + }); +}); diff --git a/e2e/before-each-aborts-tests/__tests__/singleBlock/singleTest.test.js b/e2e/before-each-aborts-tests/__tests__/singleBlock/singleTest.test.js new file mode 100644 index 000000000000..d45286614e44 --- /dev/null +++ b/e2e/before-each-aborts-tests/__tests__/singleBlock/singleTest.test.js @@ -0,0 +1,17 @@ +/** + * 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. + */ + +describe('a block with a single test', () => { + beforeEach(() => { + console.log('beforeEach'); + throw new Error('The beforeEach hook failed.'); + }); + + test('skipped test', () => { + console.log('test'); + }); +}); diff --git a/e2e/before-each-aborts-tests/package.json b/e2e/before-each-aborts-tests/package.json new file mode 100644 index 000000000000..33eac18834b4 --- /dev/null +++ b/e2e/before-each-aborts-tests/package.json @@ -0,0 +1,6 @@ +{ + "jest": { + "testEnvironment": "node", + "verbose": false + } +} diff --git a/packages/jest-jasmine2/src/jasmine/Spec.ts b/packages/jest-jasmine2/src/jasmine/Spec.ts index e22c9f885748..1e77543cee19 100644 --- a/packages/jest-jasmine2/src/jasmine/Spec.ts +++ b/packages/jest-jasmine2/src/jasmine/Spec.ts @@ -39,7 +39,10 @@ import expectationResultFactory, { Options as ExpectationResultFactoryOptions, } from '../expectationResultFactory'; import assertionErrorMessage from '../assertionErrorMessage'; -import queueRunner, {QueueableFn} from '../queueRunner'; +import queueRunner, { + QueueableFn, + Options as QueueRunnerOptions, +} from '../queueRunner'; import {AssertionErrorWithStack} from '../types'; export type Attributes = { @@ -187,21 +190,35 @@ export default class Spec { } const fns = this.beforeAndAfterFns(); - const allFns = fns.befores.concat(this.queueableFn).concat(fns.afters); - - this.currentRun = this.queueRunnerFactory({ - queueableFns: allFns, - onException() { - // @ts-ignore - self.onException.apply(self, arguments); - }, - userContext: this.userContext(), - setTimeout, - clearTimeout, - fail: () => {}, - }); - - this.currentRun.then(() => complete(true)); + let hasFailedBeforeHook = false; + + const createQueueRun = ( + queueableFns: QueueRunnerOptions['queueableFns'], + isBeforeHook: boolean = false, + ) => + this.queueRunnerFactory({ + queueableFns, + onException() { + if (isBeforeHook) hasFailedBeforeHook = true; + + // @ts-ignore + self.onException.apply(self, arguments); + }, + userContext: this.userContext(), + setTimeout, + clearTimeout, + fail: () => {}, + }); + + this.currentRun = createQueueRun(fns.befores, true); + + this.currentRun + .then(() => + hasFailedBeforeHook + ? createQueueRun(fns.afters) + : createQueueRun([this.queueableFn].concat(fns.afters)), + ) + .then(() => complete(true)); function complete(enabledAgain: boolean) { self.result.status = self.status(enabledAgain);