Skip to content

Commit

Permalink
feat: add long test time threshold option (#9366)
Browse files Browse the repository at this point in the history
  • Loading branch information
Draco-Umbratilis committed Jul 29, 2020
1 parent 0d1c09c commit 93cde55
Show file tree
Hide file tree
Showing 21 changed files with 90 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,7 @@

### Features

- `[jest-config, jest-reporter, jest-runner, jest-test-sequencer]` Add `slowTestThreshold` configuration option ([#9366](https://github.com/facebook/jest/pull/9366))
- `[jest-worker]` Added support for workers to send custom messages to parent in jest-worker ([#10293](https://github.com/facebook/jest/pull/10293))
- `[pretty-format]` Added support for serializing custom elements (web components) ([#10217](https://github.com/facebook/jest/pull/10237))

Expand Down
1 change: 1 addition & 0 deletions TestUtils.ts
Expand Up @@ -102,6 +102,7 @@ const DEFAULT_PROJECT_CONFIG: Config.ProjectConfig = {
setupFilesAfterEnv: [],
skipFilter: false,
skipNodeResolution: false,
slowTestThreshold: 5,
snapshotResolver: undefined,
snapshotSerializers: [],
testEnvironment: 'node',
Expand Down
6 changes: 6 additions & 0 deletions docs/Configuration.md
Expand Up @@ -800,6 +800,12 @@ Example `jest.setup.js` file
jest.setTimeout(10000); // in milliseconds
```

### `slowTestThreshold` [number]

Default: `5`

The number of seconds after which a test is considered as slow and reported as such in the results.

### `snapshotResolver` [string]

Default: `undefined`
Expand Down
1 change: 1 addition & 0 deletions e2e/__tests__/__snapshots__/showConfig.test.ts.snap
Expand Up @@ -48,6 +48,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
"setupFiles": [],
"setupFilesAfterEnv": [],
"skipFilter": false,
"slowTestThreshold": 5,
"snapshotSerializers": [],
"testEnvironment": "<<REPLACED_JEST_PACKAGES_DIR>>/jest-environment-jsdom/build/index.js",
"testEnvironmentOptions": {},
Expand Down
Expand Up @@ -176,6 +176,9 @@ module.exports = {
// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/Defaults.ts
Expand Up @@ -50,6 +50,7 @@ const defaultOptions: Config.DefaultOptions = {
setupFiles: [],
setupFilesAfterEnv: [],
skipFilter: false,
slowTestThreshold: 5,
snapshotSerializers: [],
testEnvironment: 'jest-environment-jsdom',
testEnvironmentOptions: {},
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-config/src/Descriptions.ts
Expand Up @@ -67,6 +67,8 @@ const descriptions: {[key in keyof Config.InitialOptions]: string} = {
'The paths to modules that run some code to configure or set up the testing environment before each test',
setupFilesAfterEnv:
'A list of paths to modules that run some code to configure or set up the testing framework before each test',
slowTestThreshold:
'The number of seconds after which a test is considered as slow and reported as such in the results.',
snapshotSerializers:
'A list of paths to snapshot serializer modules Jest should use for snapshot testing',
testEnvironment: 'The test environment that will be used for testing',
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/ValidConfig.ts
Expand Up @@ -97,6 +97,7 @@ const initialOptions: Config.InitialOptions = {
silent: true,
skipFilter: false,
skipNodeResolution: false,
slowTestThreshold: 5,
snapshotResolver: '<rootDir>/snapshotResolver.js',
snapshotSerializers: ['my-serializer-module'],
testEnvironment: 'jest-environment-jsdom',
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/index.ts
Expand Up @@ -205,6 +205,7 @@ const groupOptions = (
setupFilesAfterEnv: options.setupFilesAfterEnv,
skipFilter: options.skipFilter,
skipNodeResolution: options.skipNodeResolution,
slowTestThreshold: options.slowTestThreshold,
snapshotResolver: options.snapshotResolver,
snapshotSerializers: options.snapshotSerializers,
testEnvironment: options.testEnvironment,
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/normalize.ts
Expand Up @@ -907,6 +907,7 @@ export default function normalize(
case 'silent':
case 'skipFilter':
case 'skipNodeResolution':
case 'slowTestThreshold':
case 'testEnvironment':
case 'testEnvironmentOptions':
case 'testFailureExitCode':
Expand Down
Expand Up @@ -38,6 +38,7 @@ exports[`prints the config object 1`] = `
"setupFilesAfterEnv": [],
"skipFilter": false,
"skipNodeResolution": false,
"slowTestThreshold": 5,
"snapshotSerializers": [],
"testEnvironment": "node",
"testEnvironmentOptions": {},
Expand Down
33 changes: 33 additions & 0 deletions packages/jest-reporters/src/__tests__/get_result_header.test.js
Expand Up @@ -11,9 +11,30 @@ const terminalLink = require('terminal-link');

jest.mock('terminal-link', () => jest.fn(() => 'wannabehyperlink'));

const endTime = 1577717671160;
const testTime = 5500;

const testResult = {
testFilePath: '/foo',
};
const testResultSlow = {
perfStats: {
end: endTime,
runtime: testTime,
slow: true,
start: endTime - testTime,
},
testFilePath: '/foo',
};
const testResultFast = {
perfStats: {
end: endTime,
runtime: testTime,
slow: false,
start: endTime - testTime,
},
testFilePath: '/foo',
};

const globalConfig = makeGlobalConfig();

Expand All @@ -36,3 +57,15 @@ test('should render the terminal link', () => {

expect(result).toContain('wannabehyperlink');
});

test('should display test time for slow test', () => {
const result = getResultHeader(testResultSlow, globalConfig);

expect(result).toContain(`${testTime / 1000} s`);
});

test('should not display test time for fast test ', () => {
const result = getResultHeader(testResultFast, globalConfig);

expect(result).not.toContain(`${testTime / 1000} s`);
});
9 changes: 4 additions & 5 deletions packages/jest-reporters/src/get_result_header.ts
Expand Up @@ -42,12 +42,11 @@ export default (
const status =
result.numFailingTests > 0 || result.testExecError ? FAIL : PASS;

const runTime = result.perfStats
? (result.perfStats.end - result.perfStats.start) / 1000
: null;

const testDetail = [];
if (runTime !== null && runTime > 5) {

if (result.perfStats?.slow) {
const runTime = result.perfStats.runtime / 1000;

testDetail.push(LONG_TEST_COLOR(formatTime(runTime, 0)));
}

Expand Down
9 changes: 8 additions & 1 deletion packages/jest-runner/src/runTest.ts
Expand Up @@ -266,7 +266,14 @@ async function runTestInternal(
result.numPendingTests +
result.numTodoTests;

result.perfStats = {end: Date.now(), start};
const end = Date.now();
const testRuntime = end - start;
result.perfStats = {
end,
runtime: testRuntime,
slow: testRuntime / 1000 > config.slowTestThreshold,
start,
};
result.testFilePath = path;
result.console = testConsole.getBuffer();
result.skipped = testCount === result.numPendingTests;
Expand Down
Expand Up @@ -19,7 +19,7 @@ describe('formatTestResults', () => {
testResults: [
{
numFailingTests: 0,
perfStats: {end: 2, start: 1},
perfStats: {end: 2, runtime: 1, slow: false, start: 1},
// @ts-expect-error
testResults: [assertion],
},
Expand Down
4 changes: 4 additions & 0 deletions packages/jest-test-result/src/helpers.ts
Expand Up @@ -58,6 +58,8 @@ export const buildFailureTestResult = (
openHandles: [],
perfStats: {
end: 0,
runtime: 0,
slow: false,
start: 0,
},
skipped: false,
Expand Down Expand Up @@ -155,6 +157,8 @@ export const createEmptyTestResult = (): TestResult => ({
openHandles: [],
perfStats: {
end: 0,
runtime: 0,
slow: false,
start: 0,
},
skipped: false,
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-test-result/src/types.ts
Expand Up @@ -92,6 +92,8 @@ export type TestResult = {
openHandles: Array<Error>;
perfStats: {
end: Milliseconds;
runtime: Milliseconds;
slow: boolean;
start: Milliseconds;
};
skipped: boolean;
Expand Down
24 changes: 12 additions & 12 deletions packages/jest-test-sequencer/src/__tests__/test_sequencer.test.js
Expand Up @@ -134,23 +134,23 @@ test('writes the cache based on results without existing cache', () => {
testResults: [
{
numFailingTests: 0,
perfStats: {end: 2, start: 1},
perfStats: {end: 2, runtime: 1, start: 1},
testFilePath: '/test-a.js',
},
{
numFailingTests: 0,
perfStats: {end: 0, start: 0},
perfStats: {end: 0, runtime: 0, start: 0},
skipped: true,
testFilePath: '/test-b.js',
},
{
numFailingTests: 1,
perfStats: {end: 4, start: 1},
perfStats: {end: 4, runtime: 3, start: 1},
testFilePath: '/test-c.js',
},
{
numFailingTests: 1,
perfStats: {end: 2, start: 1},
perfStats: {end: 2, runtime: 1, start: 1},
testFilePath: '/test-x.js',
},
],
Expand All @@ -177,23 +177,23 @@ test('writes the cache based on the results', () => {
testResults: [
{
numFailingTests: 0,
perfStats: {end: 2, start: 1},
perfStats: {end: 2, runtime: 1, start: 1},
testFilePath: '/test-a.js',
},
{
numFailingTests: 0,
perfStats: {end: 0, start: 0},
perfStats: {end: 0, runtime: 0, start: 0},
skipped: true,
testFilePath: '/test-b.js',
},
{
numFailingTests: 1,
perfStats: {end: 4, start: 1},
perfStats: {end: 4, runtime: 3, start: 1},
testFilePath: '/test-c.js',
},
{
numFailingTests: 1,
perfStats: {end: 2, start: 1},
perfStats: {end: 2, runtime: 1, start: 1},
testFilePath: '/test-x.js',
},
],
Expand Down Expand Up @@ -228,23 +228,23 @@ test('works with multiple contexts', () => {
testResults: [
{
numFailingTests: 0,
perfStats: {end: 2, start: 1},
perfStats: {end: 2, runtime: 1, start: 1},
testFilePath: '/test-a.js',
},
{
numFailingTests: 0,
perfStats: {end: 0, start: 0},
perfStats: {end: 0, runtime: 1, start: 0},
skipped: true,
testFilePath: '/test-b.js',
},
{
numFailingTests: 0,
perfStats: {end: 4, start: 1},
perfStats: {end: 4, runtime: 3, start: 1},
testFilePath: '/test-c.js',
},
{
numFailingTests: 1,
perfStats: {end: 2, start: 1},
perfStats: {end: 2, runtime: 1, start: 1},
testFilePath: '/test-x.js',
},
],
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-test-sequencer/src/index.ts
Expand Up @@ -118,7 +118,7 @@ export default class TestSequencer {
const perf = testResult.perfStats;
cache[testResult.testFilePath] = [
testResult.numFailingTests ? FAIL : SUCCESS,
perf.end - perf.start || 0,
perf.runtime || 0,
];
}
});
Expand Down
Expand Up @@ -41,6 +41,7 @@ Object {
"setupFilesAfterEnv": Array [],
"skipFilter": false,
"skipNodeResolution": false,
"slowTestThreshold": 5,
"snapshotResolver": undefined,
"snapshotSerializers": Array [],
"testEnvironment": "node",
Expand Down Expand Up @@ -229,7 +230,7 @@ exports[`ScriptTransformer uses multiple preprocessors 1`] = `
const TRANSFORMED = {
filename: '/fruits/banana.js',
script: 'module.exports = "banana";',
config: '{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extraGlobals":[],"forceCoverageMatch":[],"globals":{},"haste":{},"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleLoader":"/test_module_loader_path","moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-jasmine2","testURL":"http://localhost","timers":"real","transform":[["^.+\\\\.js$","test_preprocessor"],["^.+\\\\.css$","css-preprocessor"]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}',
config: '{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extraGlobals":[],"forceCoverageMatch":[],"globals":{},"haste":{},"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleLoader":"/test_module_loader_path","moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-jasmine2","testURL":"http://localhost","timers":"real","transform":[["^.+\\\\.js$","test_preprocessor"],["^.+\\\\.css$","css-preprocessor"]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}',
};
`;

Expand All @@ -246,7 +247,7 @@ exports[`ScriptTransformer uses the supplied preprocessor 1`] = `
const TRANSFORMED = {
filename: '/fruits/banana.js',
script: 'module.exports = "banana";',
config: '{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extraGlobals":[],"forceCoverageMatch":[],"globals":{},"haste":{},"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleLoader":"/test_module_loader_path","moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-jasmine2","testURL":"http://localhost","timers":"real","transform":[["^.+\\\\.js$","test_preprocessor"]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}',
config: '{"automock":false,"cache":true,"cacheDirectory":"/cache/","clearMocks":false,"coveragePathIgnorePatterns":[],"cwd":"/test_root_dir/","detectLeaks":false,"detectOpenHandles":false,"errorOnDeprecated":false,"extraGlobals":[],"forceCoverageMatch":[],"globals":{},"haste":{},"moduleDirectories":[],"moduleFileExtensions":["js"],"moduleLoader":"/test_module_loader_path","moduleNameMapper":[],"modulePathIgnorePatterns":[],"modulePaths":[],"name":"test","prettierPath":"prettier","resetMocks":false,"resetModules":false,"restoreMocks":false,"rootDir":"/","roots":[],"runner":"jest-runner","setupFiles":[],"setupFilesAfterEnv":[],"skipFilter":false,"skipNodeResolution":false,"slowTestThreshold":5,"snapshotSerializers":[],"testEnvironment":"node","testEnvironmentOptions":{},"testLocationInResults":false,"testMatch":[],"testPathIgnorePatterns":[],"testRegex":["\\\\.test\\\\.js$"],"testRunner":"jest-jasmine2","testURL":"http://localhost","timers":"real","transform":[["^.+\\\\.js$","test_preprocessor"]],"transformIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":[]}',
};
`;
Expand Down
3 changes: 3 additions & 0 deletions packages/jest-types/src/Config.ts
Expand Up @@ -65,6 +65,7 @@ export type DefaultOptions = {
setupFiles: Array<Path>;
setupFilesAfterEnv: Array<Path>;
skipFilter: boolean;
slowTestThreshold: number;
snapshotSerializers: Array<Path>;
testEnvironment: string;
testEnvironmentOptions: Record<string, any>;
Expand Down Expand Up @@ -171,6 +172,7 @@ export type InitialOptions = Partial<{
silent: boolean;
skipFilter: boolean;
skipNodeResolution: boolean;
slowTestThreshold: number;
snapshotResolver: Path;
snapshotSerializers: Array<Path>;
errorOnDeprecated: boolean;
Expand Down Expand Up @@ -332,6 +334,7 @@ export type ProjectConfig = {
setupFilesAfterEnv: Array<Path>;
skipFilter: boolean;
skipNodeResolution?: boolean;
slowTestThreshold: number;
snapshotResolver?: Path;
snapshotSerializers: Array<Path>;
testEnvironment: string;
Expand Down

0 comments on commit 93cde55

Please sign in to comment.