Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Jest Circus] Make hooks in empty describe blocks error #6320

Merged
merged 9 commits into from
May 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* `[jest-each]` Support one dimensional array of data ([#6351](https://github.com/facebook/jest/pull/6351))
* `[jest-watch]` create new package `jest-watch` to ease custom watch plugin development ([#6318](https://github.com/facebook/jest/pull/6318))
* `[jest-circus]` Make hooks in empty describe blocks error ([#6320](https://github.com/facebook/jest/pull/6320))
* Add a config/CLI option `errorOnDeprecated` which makes calling deprecated APIs throw hepful error messages.

### Fixes
Expand Down
147 changes: 147 additions & 0 deletions e2e/__tests__/__snapshots__/empty-describe-with-hooks.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`hook in describe with skipped test 1`] = `
Object {
"rest": "",
"summary": "Test Suites: 1 skipped, 0 of 1 total
Tests: 1 skipped, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites matching /hook-in-describe-with-skipped-test.test.js/i.",
}
`;

exports[`hook in empty describe 1`] = `
Object {
"rest": "FAIL __tests__/hook-in-empty-describe.test.js


● Test suite failed to run

Invalid: beforeEach() may not be used in a describe block containing no tests.

7 |
8 | describe('a block', () => {
> 9 | beforeEach(() => {});
| ^
10 | });
11 |
12 | describe('another block with tests', () => {

at __tests__/hook-in-empty-describe.test.js:9:3
at __tests__/hook-in-empty-describe.test.js:8:1

",
"summary": "Test Suites: 1 failed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites matching /hook-in-empty-describe.test.js/i.
",
}
`;

exports[`hook in empty nested describe 1`] = `
Object {
"rest": "FAIL __tests__/hook-in-empty-nested-describe.test.js


● Test suite failed to run

Invalid: beforeEach() may not be used in a describe block containing no tests.

7 |
8 | describe('a block', () => {
> 9 | beforeEach(() => {});
| ^
10 | describe('another block', () => {});
11 | });
12 |

at __tests__/hook-in-empty-nested-describe.test.js:9:3
at __tests__/hook-in-empty-nested-describe.test.js:8:1

",
"summary": "Test Suites: 1 failed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites matching /hook-in-empty-nested-describe.test.js/i.
",
}
`;

exports[`multiple hooks in empty describe 1`] = `
Object {
"rest": "FAIL __tests__/multiple-hooks-in-empty-describe.test.js


● Test suite failed to run

Invalid: beforeEach() may not be used in a describe block containing no tests.

7 |
8 | describe('a block', () => {
> 9 | beforeEach(() => {});
| ^
10 | afterEach(() => {});
11 | afterAll(() => {});
12 | beforeAll(() => {});

at __tests__/multiple-hooks-in-empty-describe.test.js:9:3
at __tests__/multiple-hooks-in-empty-describe.test.js:8:1

● Test suite failed to run

Invalid: afterEach() may not be used in a describe block containing no tests.

8 | describe('a block', () => {
9 | beforeEach(() => {});
> 10 | afterEach(() => {});
| ^
11 | afterAll(() => {});
12 | beforeAll(() => {});
13 | });

at __tests__/multiple-hooks-in-empty-describe.test.js:10:3
at __tests__/multiple-hooks-in-empty-describe.test.js:8:1

● Test suite failed to run

Invalid: afterAll() may not be used in a describe block containing no tests.

9 | beforeEach(() => {});
10 | afterEach(() => {});
> 11 | afterAll(() => {});
| ^
12 | beforeAll(() => {});
13 | });
14 |

at __tests__/multiple-hooks-in-empty-describe.test.js:11:3
at __tests__/multiple-hooks-in-empty-describe.test.js:8:1

● Test suite failed to run

Invalid: beforeAll() may not be used in a describe block containing no tests.

10 | afterEach(() => {});
11 | afterAll(() => {});
> 12 | beforeAll(() => {});
| ^
13 | });
14 |
15 | describe('another block with tests', () => {

at __tests__/multiple-hooks-in-empty-describe.test.js:12:3
at __tests__/multiple-hooks-in-empty-describe.test.js:8:1

",
"summary": "Test Suites: 1 failed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites matching /multiple-hooks-in-empty-describe.test.js/i.
",
}
`;
42 changes: 42 additions & 0 deletions e2e/__tests__/empty-describe-with-hooks.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Copyright (c) 2018-present, Facebook, Inc. 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.
*
* @flow
*/

'use strict';

const path = require('path');
const runJest = require('../runJest');
const {extractSummary} = require('../Utils');
const dir = path.resolve(__dirname, '../empty-describe-with-hooks');
const ConditionalTest = require('../../scripts/ConditionalTest');

ConditionalTest.skipSuiteOnJasmine();

test('hook in empty describe', () => {
const result = runJest(dir, ['hook-in-empty-describe.test.js']);
expect(result.status).toBe(1);
expect(extractSummary(result.stderr)).toMatchSnapshot();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing the snapshots?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops. Got lost in the move to e2e. Added.

});

test('hook in describe with skipped test', () => {
const result = runJest(dir, ['hook-in-describe-with-skipped-test.test.js']);
expect(result.status).toBe(0);
expect(extractSummary(result.stderr)).toMatchSnapshot();
});

test('hook in empty nested describe', () => {
const result = runJest(dir, ['hook-in-empty-nested-describe.test.js']);
expect(result.status).toBe(1);
expect(extractSummary(result.stderr)).toMatchSnapshot();
});

test('multiple hooks in empty describe', () => {
const result = runJest(dir, ['multiple-hooks-in-empty-describe.test.js']);
expect(result.status).toBe(1);
expect(extractSummary(result.stderr)).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright (c) 2018-present, Facebook, Inc. 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', () => {
beforeEach(() => {});
test.skip('skipped test', () => {});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright (c) 2018-present, Facebook, Inc. 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', () => {
beforeEach(() => {});
});

describe('another block with tests', () => {
test('this test prevents us from failing due to zero tests', () => {});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Copyright (c) 2018-present, Facebook, Inc. 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', () => {
beforeEach(() => {});
describe('another block', () => {});
});

describe('another block with tests', () => {
test('this test prevents us from failing due to zero tests', () => {});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Copyright (c) 2018-present, Facebook, Inc. 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', () => {
beforeEach(() => {});
afterEach(() => {});
afterAll(() => {});
beforeAll(() => {});
});

describe('another block with tests', () => {
test('this test prevents us from failing due to zero tests', () => {});
});
5 changes: 5 additions & 0 deletions e2e/empty-describe-with-hooks/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"jest": {
"testEnvironment": "node"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,62 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`describe block _can_ have hooks if a child describe block has tests 1`] = `
"start_describe_definition: describe
add_hook: afterEach
add_hook: beforeEach
add_hook: afterAll
add_hook: beforeAll
start_describe_definition: child describe
add_test: my test
finish_describe_definition: child describe
finish_describe_definition: describe
run_start
run_describe_start: ROOT_DESCRIBE_BLOCK
run_describe_start: describe
hook_start: beforeAll
hook_success: beforeAll
run_describe_start: child describe
test_start: my test
hook_start: beforeEach
hook_success: beforeEach
test_fn_start: my test
test_fn_failure: my test
hook_start: afterEach
hook_success: afterEach
test_done: my test
run_describe_finish: child describe
hook_start: afterAll
hook_success: afterAll
run_describe_finish: describe
run_describe_finish: ROOT_DESCRIBE_BLOCK
run_finish

unhandledErrors: 0
"
`;

exports[`describe block cannot have hooks and no tests 1`] = `
"start_describe_definition: describe
add_hook: afterEach
add_hook: beforeEach
add_hook: afterAll
add_hook: beforeAll
finish_describe_definition: describe
run_start
run_describe_start: ROOT_DESCRIBE_BLOCK
run_describe_start: describe
hook_start: beforeAll
hook_success: beforeAll
hook_start: afterAll
hook_success: afterAll
run_describe_finish: describe
run_describe_finish: ROOT_DESCRIBE_BLOCK
run_finish

unhandledErrors: 4
"
`;

exports[`tests are not marked done until their parent afterAll runs 1`] = `
"start_describe_definition: describe
add_hook: afterAll
Expand Down
30 changes: 30 additions & 0 deletions packages/jest-circus/src/__tests__/after_all-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,33 @@ test('tests are not marked done until their parent afterAll runs', () => {

expect(stdout).toMatchSnapshot();
});

test('describe block cannot have hooks and no tests', () => {
const result = runTest(`
describe('describe', () => {
afterEach(() => {});
beforeEach(() => {});
afterAll(() => {});
beforeAll(() => {});
})
`);

expect(result.stdout).toMatchSnapshot();
});

test('describe block _can_ have hooks if a child describe block has tests', () => {
const result = runTest(`
describe('describe', () => {
afterEach(() => {});
beforeEach(() => {});
afterAll(() => {});
beforeAll(() => {});
describe('child describe', () => {
test('my test', () => {
expect(true).toBe(true);
})
})
})
`);
expect(result.stdout).toMatchSnapshot();
});
11 changes: 11 additions & 0 deletions packages/jest-circus/src/event_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
getTestDuration,
invariant,
makeTest,
describeBlockHasTests,
} from './utils';
import {
injectGlobalErrorHandlers,
Expand Down Expand Up @@ -44,6 +45,16 @@ const handler: EventHandler = (event, state): void => {
case 'finish_describe_definition': {
const {currentDescribeBlock} = state;
invariant(currentDescribeBlock, `currentDescribeBlock must be there`);

if (!describeBlockHasTests(currentDescribeBlock)) {
currentDescribeBlock.hooks.forEach(hook => {
hook.asyncError.message = `Invalid: ${
hook.type
}() may not be used in a describe block containing no tests.`;
state.unhandledErrors.push(hook.asyncError);
});
}

if (currentDescribeBlock.parent) {
state.currentDescribeBlock = currentDescribeBlock.parent;
}
Expand Down
Loading