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

fix: print log entries if logging happens after teardown #7731

Merged
merged 16 commits into from
Jan 29, 2019
1 change: 1 addition & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[ignore]
.*/examples/.*
.*/node_modules/metro-bundler/.*
.*/node_modules/metro-config/.*
.*/node_modules/metro/.*
.*/node_modules/module-deps/.*

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- `[jest-config]` Extract setupFilesAfterEnv from preset ([#7724](https://github.com/facebook/jest/pull/7724))
- `[jest-cli]` Do not execute any `globalSetup` or `globalTeardown` if there are no tests to execute ([#7745](https://github.com/facebook/jest/pull/7745))
- `[jest-runtime]` Lock down version of `write-file-atomic` ([#7725](https://github.com/facebook/jest/pull/7725))
- `[jest-cli]` Print log entries when logging happens after test environment is torn down ([#7731](https://github.com/facebook/jest/pull/7731))

### Chore & Maintenance

Expand Down
20 changes: 20 additions & 0 deletions e2e/__tests__/__snapshots__/consoleAfterTeardown.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`console printing 1`] = `
PASS __tests__/console.test.js


● Cannot log after tests are done. Did you forget to wait for something async in your test?
Attempted to log "hello!".

11 | // eslint-disable-next-line prefer-arrow-callback
12 | new Promise(resolve => setTimeout(resolve, 500)).then(function log() {
> 13 | console.log('hello!');
| ^
14 | });
15 | });
16 |

at BufferedConsole.log (../../packages/jest-util/build/BufferedConsole.js:169:10)
at log (__tests__/console.test.js:13:13)
`;
20 changes: 20 additions & 0 deletions e2e/__tests__/consoleAfterTeardown.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* 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.
*
* @flow
*/

import {extractSummary} from '../Utils';
import runJest from '../runJest';
import {wrap} from 'jest-snapshot-serializer-raw';

test('console printing', () => {
const {stderr, status} = runJest('console-after-teardown');
const {rest} = extractSummary(stderr);

expect(status).toBe(0);
expect(wrap(rest)).toMatchSnapshot();
});
15 changes: 11 additions & 4 deletions e2e/__tests__/forceExit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,25 @@ test('exits the process after test are done but before timers complete', () => {
'package.json': JSON.stringify({jest: {testEnvironment: 'node'}}),
});

let output;
let stdout;
let stderr;
({stdout, stderr} = runJest(DIR));
expect(stderr).toMatch(/PASS.*test\.test\.js/);
expect(stdout).toMatch(/TIMER_DONE/);

output = `${stdout}\n${stderr}`;

expect(output).toMatch(/PASS.*test\.test\.js/);
expect(output).toMatch(/TIMER_DONE/);
writeFiles(DIR, {
'package.json': JSON.stringify({
jest: {forceExit: true, testEnvironment: 'node'},
}),
});

({stdout, stderr} = runJest(DIR));
expect(stderr).toMatch(/PASS.*test\.test\.js/);
expect(stdout).not.toMatch(/TIMER_DONE/);

output = `${stdout}\n${stderr}`;

expect(output).toMatch(/PASS.*test\.test\.js/);
expect(output).not.toMatch(/TIMER_DONE/);
});
15 changes: 15 additions & 0 deletions e2e/console-after-teardown/__tests__/console.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* 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.
*/
'use strict';

test('throws error', () => {
// To have the function be named the same in jasmine and circus
// eslint-disable-next-line prefer-arrow-callback
new Promise(resolve => setTimeout(resolve, 500)).then(function log() {
console.log('hello!');
});
});
6 changes: 6 additions & 0 deletions e2e/console-after-teardown/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"jest": {
"testEnvironment": "node",
"verbose": false
}
}
1 change: 1 addition & 0 deletions packages/jest-runner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"license": "MIT",
"main": "build/index.js",
"dependencies": {
"chalk": "^2.4.2",
"exit": "^0.1.2",
"graceful-fs": "^4.1.15",
"jest-config": "^24.0.0",
Expand Down
32 changes: 32 additions & 0 deletions packages/jest-runner/src/runTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,42 @@ import {getTestEnvironment} from 'jest-config';
import * as docblock from 'jest-docblock';
import {formatExecError} from 'jest-message-util';
import sourcemapSupport from 'source-map-support';
import chalk from 'chalk';

type RunTestInternalResult = {
leakDetector: ?LeakDetector,
result: TestResult,
};

function freezeConsole(
testConsole: BufferedConsole | Console | NullConsole,
config: ProjectConfig,
) {
// $FlowFixMe: overwrite it for pretty errors
testConsole._log = function fakeConsolePush(_type, message) {
const error = new ErrorWithStack(
`${chalk.red(
`${chalk.bold(
'Cannot log after tests are done.',
)} Did you forget to wait for something async in your test?`,
)}\nAttempted to log "${message}".`,
fakeConsolePush,
);

const formattedError = formatExecError(
error,
config,
{noStackTrace: false},
undefined,
true,
);

process.stderr.write('\n' + formattedError + '\n');
// TODO: set exit code in Jest 25
// process.exitCode = 1;
};
}

// Keeping the core of "runTest" as a separate function (as "runTestInternal")
// is key to be able to detect memory leaks. Since all variables are local to
// the function, when "runTestInternal" finishes its execution, they can all be
Expand Down Expand Up @@ -197,6 +227,8 @@ async function runTestInternal(
throw err;
}

freezeConsole(testConsole, config);

const testCount =
result.numPassingTests +
result.numFailingTests +
Expand Down