Skip to content

Commit

Permalink
Add —experimentalProjects to run multiple projects within the same …
Browse files Browse the repository at this point in the history
…jest-cli test run.
  • Loading branch information
cpojer committed Mar 16, 2017
1 parent 9f34b3a commit 7ae7a3d
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 105 deletions.
10 changes: 5 additions & 5 deletions packages/jest-cli/src/TestRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ class TestRunner {
}
});

const config = this._config;
const aggregatedResults = createAggregatedResults(tests.length);
const estimatedTime = Math.ceil(
getEstimatedTime(timings, this._options.maxWorkers) / 1000,
Expand Down Expand Up @@ -120,7 +119,7 @@ class TestRunner {
return;
}
addResult(aggregatedResults, testResult);
this._dispatcher.onTestResult(config, testResult, aggregatedResults);
this._dispatcher.onTestResult(test.config, testResult, aggregatedResults);
this._bailIfNeeded(aggregatedResults, watcher);
};

Expand All @@ -135,10 +134,11 @@ class TestRunner {
test.path,
);
addResult(aggregatedResults, testResult);
this._dispatcher.onTestResult(config, testResult, aggregatedResults);
this._dispatcher.onTestResult(test.config, testResult, aggregatedResults);
};

const updateSnapshotState = () => {
const config = this._config;
const status = snapshot.cleanup(
this._context.hasteFS,
config.updateSnapshot,
Expand All @@ -151,7 +151,7 @@ class TestRunner {
aggregatedResults.snapshot.filesRemoved));
};

this._dispatcher.onRunStart(config, aggregatedResults, {
this._dispatcher.onRunStart(this._config, aggregatedResults, {
estimatedTime,
showStatus: !runInBand,
});
Expand All @@ -169,7 +169,7 @@ class TestRunner {
updateSnapshotState();
aggregatedResults.wasInterrupted = watcher.isInterrupted();

this._dispatcher.onRunComplete(config, aggregatedResults);
this._dispatcher.onRunComplete(this._config, aggregatedResults);

const anyTestFailures = !(aggregatedResults.numFailedTests === 0 &&
aggregatedResults.numRuntimeErrorTestSuites === 0);
Expand Down
14 changes: 8 additions & 6 deletions packages/jest-cli/src/TestSequencer.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,15 @@ class TestSequencer {
}));
}

cacheResults(results: AggregatedResult) {
cacheResults(tests: Tests, results: AggregatedResult) {
const cache = this._cache;
results.testResults.forEach(test => {
if (test && !test.skipped) {
const perf = test.perfStats;
cache[test.testFilePath] = [
test.numFailingTests ? FAIL : SUCCESS,
const map = Object.create(null);
tests.forEach(({path}) => map[path] = true);
results.testResults.forEach(testResult => {
if (testResult && map[testResult.testFilePath] && !testResult.skipped) {
const perf = testResult.perfStats;
cache[testResult.testFilePath] = [
testResult.numFailingTests ? FAIL : SUCCESS,
perf.end - perf.start || 0,
];
}
Expand Down
5 changes: 5 additions & 0 deletions packages/jest-cli/src/cli/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ const options = {
description: 'Use this flag to show full diffs instead of a patch.',
type: 'boolean',
},
experimentalProjects: {
description: 'A list of projects that use Jest to run all tests in a ' +
'single run.',
type: 'array',
},
findRelatedTests: {
description: 'Find related tests for a list of source files that were ' +
'passed in as arguments. Useful for pre-commit hook integration to run ' +
Expand Down
8 changes: 7 additions & 1 deletion packages/jest-cli/src/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ function run(argv?: Object, root?: Path) {
root = pkgDir.sync();
}

getJest(root).runCLI(argv, root, result => {
argv.projects = argv.experimentalProjects;
if (!argv.projects) {
argv.projects = [root];
}

const execute = argv.projects.length === 1 ? getJest(root).runCLI : runCLI;
execute(argv, argv.projects, result => {
const code = !result || result.success ? 0 : 1;
process.on('exit', () => process.exit(code));
if (argv && argv.forceExit) {
Expand Down
68 changes: 41 additions & 27 deletions packages/jest-cli/src/cli/runCLI.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/

import type {AggregatedResult} from 'types/TestResult';
import type {Path} from 'types/Config';
import type {Config, Path} from 'types/Config';

const Runtime = require('jest-runtime');

Expand All @@ -27,9 +27,9 @@ const watch = require('../watch');

const VERSION = require('../../package.json').version;

module.exports = (
module.exports = async (
argv: Object,
root: Path,
roots: Array<Path>,
onComplete: (results: ?AggregatedResult) => void,
) => {
const realFs = require('fs');
Expand All @@ -44,52 +44,66 @@ module.exports = (
return;
}

const _run = async ({config, hasDeprecationWarnings}) => {
const _run = async (
configs: Array<{config: Config, hasDeprecationWarnings: boolean}>,
) => {
if (argv.debug) {
logDebugMessages(config, pipe);
// TODO fix/remove this: there should be a `--show-config` argument.
logDebugMessages(configs[0].config, pipe);
}

createDirectory(config.cacheDirectory);
const hasteMapInstance = Runtime.createHasteMap(config, {
console: new Console(pipe, pipe),
maxWorkers: getMaxWorkers(argv),
resetCache: !config.cache,
watch: config.watch,
});

const hasteMap = await hasteMapInstance.build();
const hasteContext = createHasteContext(config, hasteMap);
if (argv.watch || argv.watchAll) {
const {config} = configs[0];
createDirectory(config.cacheDirectory);
const hasteMapInstance = Runtime.createHasteMap(config, {
console: new Console(pipe, pipe),
maxWorkers: getMaxWorkers(argv),
resetCache: !config.cache,
watch: config.watch,
});

const hasteMap = await hasteMapInstance.build();
const hasteContext = createTestContext(config, hasteMap);
return watch(
config,
pipe,
argv,
hasteMapInstance,
hasteContext,
hasDeprecationWarnings,
// TODO
configs[0].hasDeprecationWarnings,
);
} else {
const contexts = await Promise.all(
configs.map(async ({config}) => {
createDirectory(config.cacheDirectory);
return createTestContext(
config,
await Runtime.createHasteMap(config, {
console: new Console(pipe, pipe),
maxWorkers: getMaxWorkers(argv),
resetCache: !config.cache,
watch: config.watch,
}).build(),
);
}),
);

const startRun = () => {
preRunMessage.print(pipe);
const testWatcher = new TestWatcher({isWatchMode: false});
return runJest(
hasteContext,
config,
argv,
pipe,
testWatcher,
startRun,
onComplete,
);
runJest(contexts, argv, pipe, testWatcher, startRun, onComplete);
};
return startRun();
}
};

readConfig(argv, root).then(_run).catch(error => {
try {
await _run(await Promise.all(roots.map(root => readConfig(argv, root))));
} catch (error) {
clearLine(process.stderr);
clearLine(process.stdout);
console.error(chalk.red(error.stack));
process.exit(1);
});
}
};
132 changes: 78 additions & 54 deletions packages/jest-cli/src/runJest.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
*/
'use strict';

import type {Config} from 'types/Config';
import type {TestContext, Test} from 'types/TestRunner';
import type {PatternInfo} from './SearchSource';
import type TestWatcher from './TestWatcher';

const fs = require('graceful-fs');

Expand Down Expand Up @@ -42,72 +42,81 @@ const getTestSummary = (argv: Object, patternInfo: PatternInfo) => {
chalk.dim('.');
};

const getTestPaths = async (context, patternInfo, argv, pipe) => {
const source = new SearchSource(context, context.config);
let data = await source.getTestPaths(patternInfo);
if (!data.paths.length) {
const localConsole = new Console(pipe, pipe);
if (patternInfo.onlyChanged && data.noSCM) {
if (context.config.watch) {
// Run all the tests
setState(argv, 'watchAll', {
noSCM: true,
});
patternInfo = getTestPathPatternInfo(argv);
data = await source.getTestPaths(patternInfo);
} else {
localConsole.log(
'Jest can only find uncommitted changed files in a git or hg ' +
'repository. If you make your project a git or hg ' +
'repository (`git init` or `hg init`), Jest will be able ' +
'to only run tests related to files changed since the last ' +
'commit.',
);
}
}

localConsole.log(
source.getNoTestsFoundMessage(patternInfo, context.config, data),
);
}

return {
data,
patternInfo,
};
};

const runJest = async (
hasteContext: HasteContext,
config: Config,
contexts: Array<TestContext>,
argv: Object,
pipe: stream$Writable | tty$WriteStream,
testWatcher: any,
testWatcher: TestWatcher,
startRun: () => *,
onComplete: (testResults: any) => void,
) => {
const maxWorkers = getMaxWorkers(argv);
const source = new SearchSource(hasteContext, config);
let patternInfo = getTestPathPatternInfo(argv);

const processTests = data => {
if (!data.paths.length) {
const localConsole = new Console(pipe, pipe);
if (patternInfo.onlyChanged && data.noSCM) {
if (config.watch) {
// Run all the tests
setState(argv, 'watchAll', {
noSCM: true,
});
patternInfo = getTestPathPatternInfo(argv);
return source.getTestPaths(patternInfo);
} else {
localConsole.log(
'Jest can only find uncommitted changed files in a git or hg ' +
'repository. If you make your project a git or hg ' +
'repository (`git init` or `hg init`), Jest will be able ' +
'to only run tests related to files changed since the last ' +
'commit.',
);
}
}

localConsole.log(
source.getNoTestsFoundMessage(patternInfo, config, data),
// TODO
const context = contexts[0];
const testRunData = await Promise.all(
contexts.map(async context => {
const config = context.config;
const {data, patternInfo} = await getTestPaths(
context,
getTestPathPatternInfo(argv),
argv,
pipe,
);
}

if (
data.paths.length === 1 &&
config.silent !== true &&
config.verbose !== false
) {
// $FlowFixMe
config = Object.assign({}, config, {verbose: true});
}

return data;
};
const sequencer = new TestSequencer(config);
const tests = sequencer.sort(data.paths);
return {context, patternInfo, sequencer, tests};
}),
);

const runTests = async tests => new TestRunner(
hasteContext,
config,
context,
context.config,
{
getTestSummary: () => getTestSummary(argv, patternInfo),
getTestSummary: () => getTestSummary(argv, testRunData[0].patternInfo),
maxWorkers,
},
startRun,
).runTests(tests, testWatcher);

const processResults = runResults => {
if (config.testResultsProcessor) {
if (context.config.testResultsProcessor) {
/* $FlowFixMe */
runResults = require(config.testResultsProcessor)(runResults);
runResults = require(context.config.testResultsProcessor)(runResults);
}
if (argv.json) {
if (argv.outputFile) {
Expand All @@ -128,11 +137,26 @@ const runJest = async (
return onComplete && onComplete(runResults);
};

const data = await source.getTestPaths(patternInfo);
processTests(data);
const sequencer = new TestSequencer(config);
const results = await runTests(sequencer.sort(data.paths));
sequencer.cacheResults(results);
const allTests = testRunData
.reduce((tests, testRun) => tests.concat(testRun.tests), [])
.sort((a: Test, b: Test) => {
if (a.duration != null && b.duration != null) {
return a.duration < b.duration ? 1 : -1;
}
return a.duration == null ? 1 : 0;
});

if (
allTests.length === 1 &&
context.config.silent !== true &&
context.config.verbose !== false
) {
context.config = Object.assign({}, context.config, {verbose: true});
}

const results = await runTests(allTests);
testRunData.forEach(({sequencer, tests}) =>
sequencer.cacheResults(tests, results));
return processResults(results);
};

Expand Down
Loading

0 comments on commit 7ae7a3d

Please sign in to comment.