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

Add option testSequencer allow user use custom sequencer. #8223

Merged
merged 30 commits into from
Apr 2, 2019
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
cac8a66
move testSequencer to individual package
WeiAnAn Mar 26, 2019
27b7eba
add testSequencer option to let user use custom sequencer
WeiAnAn Mar 26, 2019
4b12436
giving testSequencer own normalize function
WeiAnAn Mar 26, 2019
aeea6ad
lint
WeiAnAn Mar 26, 2019
5093f46
remove test comment
WeiAnAn Mar 27, 2019
b94e545
keep export default
WeiAnAn Mar 27, 2019
ca3305e
use interopRequireDefault to import package
WeiAnAn Mar 27, 2019
b5c593a
correct `testSequencer` default package name
WeiAnAn Mar 27, 2019
9223489
add runInBand arg to assure running test in sequence
WeiAnAn Mar 27, 2019
ec029bb
update changelog
WeiAnAn Mar 27, 2019
02f14fa
just only implement sort function in test
WeiAnAn Mar 27, 2019
46ef8f0
add a dependency on @jest/test-scheduler to jest-config so it works i…
WeiAnAn Mar 27, 2019
30ac7e5
remove wrong dependency
WeiAnAn Mar 27, 2019
4bc5a01
let tests easier
WeiAnAn Mar 27, 2019
409a9ba
update docs
WeiAnAn Mar 27, 2019
abc58e2
fix wrong option name
WeiAnAn Mar 27, 2019
934f77c
lint
WeiAnAn Mar 27, 2019
1b3f0ef
add Test type in configuration
WeiAnAn Mar 28, 2019
35b2177
Merge branch 'master' into custom-sequencer
WeiAnAn Mar 29, 2019
f8b9b17
Update docs/CLI.md
jeysal Mar 30, 2019
4efe85c
keep example as js instead of ts
WeiAnAn Mar 30, 2019
20910a9
update changelog which affect multiple packages to one line.
WeiAnAn Mar 30, 2019
2e8fe7b
add @jest/test-sequencer to dependency
WeiAnAn Mar 30, 2019
7d58433
merge master
WeiAnAn Mar 30, 2019
9662a12
update changelog
WeiAnAn Mar 30, 2019
7e8d15a
move @jest/test-sequencer to dev dependency
WeiAnAn Mar 30, 2019
0866aba
Update @jest/core package.json
WeiAnAn Apr 2, 2019
5ffb812
merge version 24.6
WeiAnAn Apr 2, 2019
745cad3
update version to 24.6.0
WeiAnAn Apr 2, 2019
301a5cd
sort
SimenB Apr 2, 2019
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
- `[jest-runner]` Support default exports for test environments ([#8163](https://github.com/facebook/jest/pull/8163))
- `[pretty-format]` Support React.Suspense ([#8180](https://github.com/facebook/jest/pull/8180))
- `[jest-snapshot]` Indent inline snapshots ([#8198](https://github.com/facebook/jest/pull/8198))
- `[@jest/core]` Move `testSequencer` to individual package `@jest/test-sequencer` ([#8223](https://github.com/facebook/jest/pull/8223))
WeiAnAn marked this conversation as resolved.
Show resolved Hide resolved
- `[@jest/test-sequencer]` Move `testSequencer` to individual package `@jest/test-sequencer` ([#8223](https://github.com/facebook/jest/pull/8223))
- `[@jest/core]` Add option `testSequencer` allow user use custom sequencer. ([#8223](https://github.com/facebook/jest/pull/8223))
- `[jest-config]` Add option `testSequencer` allow user use custom sequencer. ([#8223](https://github.com/facebook/jest/pull/8223))
- `[jest-cli]` Add option `testSequencer` allow user use custom sequencer. ([#8223](https://github.com/facebook/jest/pull/8223))

### Fixes

Expand Down
1 change: 1 addition & 0 deletions e2e/__tests__/__snapshots__/showConfig.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ exports[`--showConfig outputs config info and exits 1`] = `
"testFailureExitCode": 1,
"testPathPattern": "",
"testResultsProcessor": null,
"testSequencer": "@jest/test-sequencer",
"updateSnapshot": "all",
"useStderr": false,
"verbose": null,
Expand Down
42 changes: 42 additions & 0 deletions e2e/__tests__/customTestSequencers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* 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 runJest from '../runJest';
import {extractSummary} from '../Utils';
const dir = path.resolve(__dirname, '../custom-test-sequencer');

expect.extend({
toBeIn(received, arr) {
WeiAnAn marked this conversation as resolved.
Show resolved Hide resolved
const isIn = arr.includes(received);
if (isIn)
return {
message: `expect ${received} not to be in [${arr.join(', ')}]`,
pass: true,
};
else
return {
message: `expect ${received} to be in [${arr.join(', ')}]`,
pass: false,
};
},
});

test('run prioritySequence first', () => {
const result = runJest(dir, ['-i']);
expect(result.status).toBe(0);
const sequence = extractSummary(result.stderr)
.rest.replace(/PASS /g, '')
.split('\n');
expect(sequence).toEqual([
'./d.test.js',
'./b.test.js',
'./c.test.js',
expect.toBeIn(['./a.test.js', './e.test.js']),
expect.toBeIn(['./a.test.js', './e.test.js']),
]);
});
7 changes: 7 additions & 0 deletions e2e/custom-test-sequencer/a.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* 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.
*/
test('a', () => {});
7 changes: 7 additions & 0 deletions e2e/custom-test-sequencer/b.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* 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.
*/
test('b', () => {});
7 changes: 7 additions & 0 deletions e2e/custom-test-sequencer/c.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* 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.
*/
test('c', () => {});
7 changes: 7 additions & 0 deletions e2e/custom-test-sequencer/d.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* 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.
*/
test('d', () => {});
7 changes: 7 additions & 0 deletions e2e/custom-test-sequencer/e.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* 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.
*/
test('e', () => {});
6 changes: 6 additions & 0 deletions e2e/custom-test-sequencer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"jest": {
"testEnvironment": "node",
"testSequencer": "<rootDir>/testSequencer.js"
}
}
107 changes: 107 additions & 0 deletions e2e/custom-test-sequencer/testSequencer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* 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.
*/

const fs = require('fs');
WeiAnAn marked this conversation as resolved.
Show resolved Hide resolved
const path = require('path');
const {getCacheFilePath} = require('../../packages/jest-haste-map/build');
WeiAnAn marked this conversation as resolved.
Show resolved Hide resolved

const priorityOrder = [
path.resolve('./d.test.js'),
path.resolve('./b.test.js'),
path.resolve('./c.test.js'),
];
const FAIL = 0;
const SUCCESS = 1;

class TestSequencer {
constructor() {
this._cache = new Map();
}
_getCachePath(context) {
const {config} = context;
return getCacheFilePath(config.cacheDirectory, 'perf-cache-' + config.name);
}

_getCache(test) {
const {context} = test;
if (!this._cache.has(context) && context.config.cache) {
const cachePath = this._getCachePath(context);
if (fs.existsSync(cachePath)) {
try {
this._cache.set(
context,
JSON.parse(fs.readFileSync(cachePath, 'utf8'))
);
} catch (e) {}
}
}

let cache = this._cache.get(context);
if (!cache) {
cache = {};
this._cache.set(context, cache);
}

return cache;
}

sort(tests) {
SimenB marked this conversation as resolved.
Show resolved Hide resolved
WeiAnAn marked this conversation as resolved.
Show resolved Hide resolved
const stats = {};
const fileSize = ({path, context: {hasteFS}}) =>
stats[path] || (stats[path] = hasteFS.getSize(path) || 0);
const hasFailed = (cache, test) =>
cache[test.path] && cache[test.path][0] === FAIL;
const time = (cache, test) => cache[test.path] && cache[test.path][1];

tests.forEach(test => (test.duration = time(this._getCache(test), test)));
return tests.sort((testA, testB) => {
WeiAnAn marked this conversation as resolved.
Show resolved Hide resolved
const cacheA = this._getCache(testA);
const cacheB = this._getCache(testB);
const failedA = hasFailed(cacheA, testA);
const failedB = hasFailed(cacheB, testB);
const hasTimeA = testA.duration != null;
const indexA = priorityOrder.indexOf(testA.path);
const indexB = priorityOrder.indexOf(testB.path);

if (indexA !== indexB) {
if (indexA === -1) return 1;
if (indexB === -1) return -1;
return indexA < indexB ? -1 : 1;
} else if (failedA !== failedB) {
return failedA ? -1 : 1;
} else if (hasTimeA != (testB.duration != null)) {
// If only one of two tests has timing information, run it last
return hasTimeA ? 1 : -1;
} else if (testA.duration != null && testB.duration != null) {
return testA.duration < testB.duration ? 1 : -1;
} else {
return fileSize(testA) < fileSize(testB) ? 1 : -1;
}
});
}

cacheResults(tests, results) {
const map = Object.create(null);
tests.forEach(test => (map[test.path] = test));
results.testResults.forEach(testResult => {
if (testResult && map[testResult.testFilePath] && !testResult.skipped) {
const cache = this._getCache(map[testResult.testFilePath]);
const perf = testResult.perfStats;
cache[testResult.testFilePath] = [
testResult.numFailingTests ? FAIL : SUCCESS,
perf.end - perf.start || 0,
];
}
});

this._cache.forEach((cache, context) =>
fs.writeFileSync(this._getCachePath(context), JSON.stringify(cache))
);
}
}

module.exports = TestSequencer;
7 changes: 7 additions & 0 deletions packages/jest-cli/src/cli/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,13 @@ export const options = {
'`<rootDir>/path/to/testRunner.js`.',
type: 'string' as 'string',
},
testSequencer: {
thymikee marked this conversation as resolved.
Show resolved Hide resolved
description:
'Allows to specify a custom test sequencer. The default is ' +
'`@jest/test-sequencer`. A path to a custom test sequencer can be ' +
'provided: `<rootDir>/path/to/testSequencer.js`',
type: 'string' as 'string',
},
testURL: {
description: 'This option sets the URL for the jsdom environment.',
type: 'string' as 'string',
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/Defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const defaultOptions: Config.DefaultOptions = {
testRegex: [],
testResultsProcessor: null,
testRunner: 'jasmine2',
testSequencer: '@jest/test-sequencer',
Copy link
Contributor

Choose a reason for hiding this comment

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

This value doesn't get fully resolved unless explicitly set, so it cannot work with PnP. It should be done like here: https://github.com/WeiAnAn/jest/blob/301a5cda50bf82617fe776938ee3fbd1c24b4a7c/packages/jest-config/src/normalize.ts#L477-L479

Copy link
Member

Choose a reason for hiding this comment

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

We resolve it in normalize already don't we?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm checking, but I think it only get resolved when the testSequence option is explicitly set - otherwise it uses the default value as-is.

testURL: 'http://localhost',
timers: 'real',
transform: null,
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/ValidConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ const initialOptions: Config.InitialOptions = {
),
testResultsProcessor: 'processor-node-module',
testRunner: 'jasmine2',
testSequencer: '@jest/test-sequencer',
testURL: 'http://localhost',
timers: 'real',
transform: {
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ const groupOptions = (
testNamePattern: options.testNamePattern,
testPathPattern: options.testPathPattern,
testResultsProcessor: options.testResultsProcessor,
testSequencer: options.testSequencer,
updateSnapshot: options.updateSnapshot,
useStderr: options.useStderr,
verbose: options.verbose,
Expand Down
12 changes: 12 additions & 0 deletions packages/jest-config/src/normalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
getRunner,
getWatchPlugin,
resolve,
getSequencer,
} from './utils';
import {DEFAULT_JS_PATTERN, DEFAULT_REPORTER_LABEL} from './constants';
import {validateReporters} from './ReporterValidationErrors';
Expand Down Expand Up @@ -594,6 +595,17 @@ export default function normalize(
});
}
break;
case 'testSequencer':
{
const option = oldOptions[key];
value =
option &&
getSequencer(newOptions.resolver, {
WeiAnAn marked this conversation as resolved.
Show resolved Hide resolved
filePath: option,
rootDir: options.rootDir,
});
}
break;
case 'prettierPath':
{
// We only want this to throw if "prettierPath" is explicitly passed
Expand Down
12 changes: 12 additions & 0 deletions packages/jest-config/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,15 @@ export const isJSONString = (text?: JSONString | string): text is JSONString =>
typeof text === 'string' &&
text.startsWith('{') &&
text.endsWith('}');

export const getSequencer = (
resolver: string | undefined | null,
{filePath, rootDir}: {filePath: string; rootDir: Config.Path},
) =>
resolveWithPrefix(resolver, {
filePath,
humanOptionName: 'Jest Sequencer',
optionName: 'sequencer',
prefix: 'jest-sequencer-',
rootDir,
});
1 change: 1 addition & 0 deletions packages/jest-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"@jest/console": "^24.3.0",
"@jest/reporters": "^24.5.0",
"@jest/test-result": "^24.5.0",
"@jest/test-sequencer": "^24.5.0",
WeiAnAn marked this conversation as resolved.
Show resolved Hide resolved
"@jest/transform": "^24.5.0",
"@jest/types": "^24.5.0",
"ansi-escapes": "^3.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-core/src/__tests__/run_jest.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('runJest', () => {
await runJest({
changedFilesPromise: Promise.resolve({repos: {git: {size: 0}}}),
contexts: [],
globalConfig: {watch: true},
globalConfig: {testSequencer: '@jest/test-sequencer', watch: true},
onComplete: () => null,
outputStream: {},
startRun: {},
Expand Down
9 changes: 6 additions & 3 deletions packages/jest-core/src/runJest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import path from 'path';
import chalk from 'chalk';
import {sync as realpath} from 'realpath-native';
import {CustomConsole} from '@jest/console';
import {formatTestResults} from 'jest-util';
import {formatTestResults, interopRequireDefault} from 'jest-util';
import exit from 'exit';
import fs from 'graceful-fs';
import {JestHook, JestHookEmitter} from 'jest-watcher';
Expand All @@ -20,12 +20,12 @@ import {
AggregatedResult,
makeEmptyAggregatedTestResult,
} from '@jest/test-result';
import TestSequencer from '@jest/test-sequencer';
import {ChangedFiles, ChangedFilesPromise} from 'jest-changed-files';
import getNoTestsFoundMessage from './getNoTestsFoundMessage';
import runGlobalHook from './runGlobalHook';
import SearchSource from './SearchSource';
import TestScheduler, {TestSchedulerContext} from './TestScheduler';
import TestSequencer from './TestSequencer';
import FailedTestsCache from './FailedTestsCache';
import collectNodeHandles from './collectHandles';
import TestWatcher from './TestWatcher';
Expand Down Expand Up @@ -143,7 +143,10 @@ export default (async function runJest({
failedTestsCache?: FailedTestsCache;
filter?: Filter;
}) {
const sequencer = new TestSequencer();
const Sequencer: typeof TestSequencer = interopRequireDefault(
require(globalConfig.testSequencer),
).default;
const sequencer = new Sequencer();
let allTests: Array<Test> = [];

if (changedFilesPromise && globalConfig.watch) {
Expand Down
1 change: 1 addition & 0 deletions packages/jest-core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
{"path": "../jest-runtime"},
{"path": "../jest-snapshot"},
{"path": "../jest-test-result"},
{"path": "../jest-test-sequencer"},
{"path": "../jest-types"},
{"path": "../jest-transform"},
{"path": "../jest-util"},
Expand Down
3 changes: 3 additions & 0 deletions packages/jest-test-sequencer/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**/__mocks__/**
**/__tests__/**
src
25 changes: 25 additions & 0 deletions packages/jest-test-sequencer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@jest/test-sequencer",
"version": "24.5.0",
"repository": {
"type": "git",
"url": "https://github.com/facebook/jest.git",
"directory": "packages/test-sequencer"
},
"license": "MIT",
"main": "build/index.js",
"types": "build/index.d.ts",
"dependencies": {
"@jest/test-result": "^24.5.0",
"jest-haste-map": "^24.5.0",
"jest-runtime": "^24.5.0",
"jest-runner": "^24.5.0"
},
"engines": {
"node": ">= 6"
},
"publishConfig": {
"access": "public"
},
"gitHead": "800533020f5b2f153615c821ed7cb12fd868fa6f"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
'use strict';

import TestSequencer from '../TestSequencer';
import TestSequencer from '../index';

jest.mock('fs');

Expand Down
Loading