Added logging, changed some directory structure

This commit is contained in:
2018-01-13 21:33:40 -05:00
parent f079a5f067
commit 8e72ffb917
73656 changed files with 35284 additions and 53718 deletions

View File

@@ -0,0 +1,4 @@
**/__mocks__/**
**/__tests__/**
src
yarn.lock

View File

@@ -0,0 +1,11 @@
# Jest
🃏 Delightful JavaScript Testing
- **👩🏻‍💻 Easy Setup**: Jest is a complete and easy to set up JavaScript testing solution. In fact, Jest works out of the box for any React project.
- **🏃🏽 Instant Feedback**: Failed tests run first. Fast interactive mode can switch between running all tests or only test files related to changed files.
- **📸 Snapshot Testing**: Jest can [capture snapshots](http://facebook.github.io/jest/docs/snapshot-testing.html) of React trees or other serializable values to simplify UI testing.
Read More: http://facebook.github.io/jest/

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env node
/**
* Copyright (c) 2014, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
if (process.env.NODE_ENV == null) {
process.env.NODE_ENV = 'test';
}
require('../build/cli').run();

View File

@@ -0,0 +1,60 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
'use strict';
const chalk = require('chalk');
const ansiEscapes = require('ansi-escapes');
const Prompt = require('./lib/Prompt');
const usage = entity =>
`\n${chalk.bold('Pattern Mode Usage')}\n` +
` ${chalk.dim('\u203A Press')} Esc ${chalk.dim('to exit pattern mode.')}\n` +
` ${chalk.dim('\u203A Press')} Enter ` +
`${chalk.dim(`to apply pattern to all ${entity}.`)}\n` +
`\n`;
const usageRows = usage('').split('\n').length;
module.exports = class PatternPrompt {
constructor(pipe, prompt) {
this._pipe = pipe;
this._prompt = prompt;
this._currentUsageRows = usageRows;
}
run(onSuccess, onCancel, options) {
this._pipe.write(ansiEscapes.cursorHide);
this._pipe.write(ansiEscapes.clearScreen);
if (options && options.header) {
this._pipe.write(options.header + '\n');
this._currentUsageRows = usageRows + options.header.split('\n').length;
} else {
this._currentUsageRows = usageRows;
}
this._pipe.write(usage(this._entityName));
this._pipe.write(ansiEscapes.cursorShow);
this._prompt.enter(this._onChange.bind(this), onSuccess, onCancel);
}
_onChange(pattern, options) {
this._pipe.write(ansiEscapes.eraseLine);
this._pipe.write(ansiEscapes.cursorLeft);
}};

View File

@@ -0,0 +1,84 @@
'use strict';function _asyncToGenerator(fn) {return function () {var gen = fn.apply(this, arguments);return new Promise(function (resolve, reject) {function step(key, arg) {try {var info = gen[key](arg);var value = info.value;} catch (error) {reject(error);return;}if (info.done) {resolve(value);} else {return Promise.resolve(value).then(function (value) {step("next", value);}, function (err) {step("throw", err);});}}return step("next");});};}
class ReporterDispatcher {
constructor() {
this._reporters = [];
}
register(reporter) {
this._reporters.push(reporter);
}
unregister(ReporterClass) {
this._reporters = this._reporters.filter(
reporter => !(reporter instanceof ReporterClass));
}
onTestResult(test, testResult, results) {
this._reporters.forEach(
reporter =>
reporter.onTestResult &&
reporter.onTestResult(test, testResult, results));
}
onTestStart(test) {
this._reporters.forEach(
reporter => reporter.onTestStart && reporter.onTestStart(test));
}
onRunStart(results, options) {
this._reporters.forEach(
reporter => reporter.onRunStart && reporter.onRunStart(results, options));
}
onRunComplete(contexts, results) {var _this = this;return _asyncToGenerator(function* () {
for (const reporter of _this._reporters) {
reporter.onRunComplete && (
yield reporter.onRunComplete(contexts, results));
}})();
}
// Return a list of last errors for every reporter
getErrors() {
return this._reporters.reduce((list, reporter) => {
const error = reporter.getLastError && reporter.getLastError();
return error ? list.concat(error) : list;
}, []);
}
hasErrors() {
return this.getErrors().length !== 0;
}} /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/module.exports = ReporterDispatcher;

View File

@@ -0,0 +1,234 @@
'use strict';var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}(); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const path = require('path');
const micromatch = require('micromatch');
const DependencyResolver = require('jest-resolve-dependencies');
const changedFiles = require('jest-changed-files');var _require =
require('jest-regex-util');const escapePathForRegex = _require.escapePathForRegex,replacePathSepForRegex = _require.replacePathSepForRegex;
const git = changedFiles.git;
const hg = changedFiles.hg;
const determineSCM = path =>
Promise.all([git.isGitRepository(path), hg.isHGRepository(path)]);
const pathToRegex = p => replacePathSepForRegex(p);
const globsToMatcher = globs => {
if (globs == null || globs.length === 0) {
return () => true;
}
const matchers = globs.map(each => micromatch.matcher(each, { dot: true }));
return path => matchers.some(each => each(path));
};
const regexToMatcher = testRegex => {
if (!testRegex) {
return () => true;
}
const regex = new RegExp(pathToRegex(testRegex));
return path => regex.test(path);
};
const toTests = (context, tests) =>
tests.map(path => ({
context,
duration: undefined,
path }));
class SearchSource {
constructor(context, options) {const
config = context.config;
this._context = context;
this._options = options || {
skipNodeResolution: false };
this._rootPattern = new RegExp(
config.roots.map(dir => escapePathForRegex(dir)).join('|'));
const ignorePattern = config.testPathIgnorePatterns;
this._testIgnorePattern = ignorePattern.length ?
new RegExp(ignorePattern.join('|')) :
null;
this._testPathCases = {
roots: path => this._rootPattern.test(path),
testMatch: globsToMatcher(config.testMatch),
testPathIgnorePatterns: path =>
!this._testIgnorePattern || !this._testIgnorePattern.test(path),
testRegex: regexToMatcher(config.testRegex) };
}
_filterTestPathsWithStats(
allPaths,
testPathPattern)
{
const data = {
stats: {},
tests: [],
total: allPaths.length };
const testCases = Object.assign({}, this._testPathCases);
if (testPathPattern) {
const regex = new RegExp(testPathPattern, 'i');
testCases.testPathPattern = path => regex.test(path);
}
const testCasesKeys = Object.keys(testCases);
data.tests = allPaths.filter(test => {
return testCasesKeys.reduce((flag, key) => {
if (testCases[key](test.path)) {
data.stats[key] = ++data.stats[key] || 1;
return flag && true;
}
data.stats[key] = data.stats[key] || 0;
return false;
}, true);
});
return data;
}
_getAllTestPaths(testPathPattern) {
return this._filterTestPathsWithStats(
toTests(this._context, this._context.hasteFS.getAllFiles()),
testPathPattern);
}
isTestFilePath(path) {
return Object.keys(this._testPathCases).every(key =>
this._testPathCases[key](path));
}
findMatchingTests(testPathPattern) {
return this._getAllTestPaths(testPathPattern);
}
findRelatedTests(allPaths) {
const dependencyResolver = new DependencyResolver(
this._context.resolver,
this._context.hasteFS);
return {
tests: toTests(
this._context,
dependencyResolver.resolveInverse(
allPaths,
this.isTestFilePath.bind(this),
{
skipNodeResolution: this._options.skipNodeResolution })) };
}
findRelatedTestsFromPattern(paths) {
if (Array.isArray(paths) && paths.length) {
const resolvedPaths = paths.map(p => path.resolve(process.cwd(), p));
return this.findRelatedTests(new Set(resolvedPaths));
}
return { tests: [] };
}
findChangedTests(options) {
return Promise.all(
this._context.config.roots.map(determineSCM)).
then(repos => {
if (!repos.every((_ref) => {var _ref2 = _slicedToArray(_ref, 2);let gitRepo = _ref2[0],hgRepo = _ref2[1];return gitRepo || hgRepo;})) {
return {
noSCM: true,
tests: [] };
}
return Promise.all(
repos.map((_ref3) => {var _ref4 = _slicedToArray(_ref3, 2);let gitRepo = _ref4[0],hgRepo = _ref4[1];
if (gitRepo) {
return git.findChangedFiles(gitRepo, options);
}
if (hgRepo) {
return hg.findChangedFiles(hgRepo, options);
}
return [];
})).
then(changedPathSets =>
this.findRelatedTests(
new Set(Array.prototype.concat.apply([], changedPathSets))));
});
}
getTestPaths(pattern) {
if (pattern.onlyChanged) {
return this.findChangedTests({ lastCommit: pattern.lastCommit });
} else if (pattern.findRelatedTests && pattern.paths) {
return Promise.resolve(this.findRelatedTestsFromPattern(pattern.paths));
} else if (pattern.testPathPattern != null) {
return Promise.resolve(this.findMatchingTests(pattern.testPathPattern));
} else {
return Promise.resolve({ tests: [] });
}
}}
module.exports = SearchSource;

View File

@@ -0,0 +1,104 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const scroll = require('./lib/scrollList');var _require =
require('./lib/terminalUtils');const getTerminalWidth = _require.getTerminalWidth;
const Prompt = require('./lib/Prompt');
const formatTestNameByPattern = require('./lib/formatTestNameByPattern');var _require2 =
require('./lib/patternModeHelpers');const formatTypeaheadSelection = _require2.formatTypeaheadSelection,printMore = _require2.printMore,printPatternCaret = _require2.printPatternCaret,printPatternMatches = _require2.printPatternMatches,printRestoredPatternCaret = _require2.printRestoredPatternCaret,printStartTyping = _require2.printStartTyping,printTypeaheadItem = _require2.printTypeaheadItem;
const PatternPrompt = require('./PatternPrompt');
module.exports = class TestNamePatternPrompt extends PatternPrompt {
constructor(pipe, prompt) {
super(pipe, prompt);
this._entityName = 'tests';
this._cachedTestResults = [];
}
_onChange(pattern, options) {
super._onChange(pattern, options);
this._printTypeahead(pattern, options);
}
_printTypeahead(pattern, options) {
const matchedTests = this._getMatchedTests(pattern);
const total = matchedTests.length;
const pipe = this._pipe;
const prompt = this._prompt;
printPatternCaret(pattern, pipe);
if (pattern) {
printPatternMatches(
total,
'test',
pipe,
` from ${require('chalk').yellow('cached')} test suites`);
const width = getTerminalWidth();var _scroll =
scroll(total, options);const start = _scroll.start,end = _scroll.end,index = _scroll.index;
prompt.setTypeaheadLength(total);
matchedTests.
slice(start, end).
map(name => formatTestNameByPattern(name, pattern, width - 4)).
map((item, i) => formatTypeaheadSelection(item, i, index, prompt)).
forEach(item => printTypeaheadItem(item, pipe));
if (total > end) {
printMore('test', pipe, total - end);
}
} else {
printStartTyping('test name', pipe);
}
printRestoredPatternCaret(pattern, this._currentUsageRows, pipe);
}
_getMatchedTests(pattern) {
let regex;
try {
regex = new RegExp(pattern, 'i');
} catch (e) {
return [];
}
const matchedTests = [];
this._cachedTestResults.forEach((_ref) => {let testResults = _ref.testResults;return (
testResults.forEach((_ref2) => {let title = _ref2.title;
if (regex.test(title)) {
matchedTests.push(title);
}
}));});
return matchedTests;
}
updateCachedTestResults() {let testResults = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
this._cachedTestResults = testResults;
}};

View File

@@ -0,0 +1,114 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const chalk = require('chalk'); // eslint-disable-next-line import/default
const stringLength = require('string-length');
const scroll = require('./lib/scrollList');var _require =
require('./lib/terminalUtils');const getTerminalWidth = _require.getTerminalWidth;
const highlight = require('./lib/highlight');var _require2 =
require('./reporters/utils');const trimAndFormatPath = _require2.trimAndFormatPath;
const Prompt = require('./lib/Prompt');var _require3 =
require('./lib/patternModeHelpers');const formatTypeaheadSelection = _require3.formatTypeaheadSelection,printMore = _require3.printMore,printPatternCaret = _require3.printPatternCaret,printPatternMatches = _require3.printPatternMatches,printRestoredPatternCaret = _require3.printRestoredPatternCaret,printStartTyping = _require3.printStartTyping,printTypeaheadItem = _require3.printTypeaheadItem;
const PatternPrompt = require('./PatternPrompt');
module.exports = class TestPathPatternPrompt extends PatternPrompt {
constructor(pipe, prompt) {
super(pipe, prompt);
this._entityName = 'filenames';
}
_onChange(pattern, options) {
super._onChange(pattern, options);
this._printTypeahead(pattern, options);
}
_printTypeahead(pattern, options) {
const matchedTests = this._getMatchedTests(pattern);
const total = matchedTests.length;
const pipe = this._pipe;
const prompt = this._prompt;
printPatternCaret(pattern, pipe);
if (pattern) {
printPatternMatches(total, 'file', pipe);
const prefix = ` ${chalk.dim('\u203A')} `;
const padding = stringLength(prefix) + 2;
const width = getTerminalWidth();var _scroll =
scroll(total, options);const start = _scroll.start,end = _scroll.end,index = _scroll.index;
prompt.setTypeaheadLength(total);
matchedTests.
slice(start, end).
map((_ref) => {let path = _ref.path,context = _ref.context;
const filePath = trimAndFormatPath(
padding,
context.config,
path,
width);
return highlight(path, filePath, pattern, context.config.rootDir);
}).
map((item, i) => formatTypeaheadSelection(item, i, index, prompt)).
forEach(item => printTypeaheadItem(item, pipe));
if (total > end) {
printMore('file', pipe, total - end);
}
} else {
printStartTyping('filename', pipe);
}
printRestoredPatternCaret(pattern, this._currentUsageRows, pipe);
}
_getMatchedTests(pattern) {
let regex;
try {
regex = new RegExp(pattern, 'i');
} catch (e) {}
let tests = [];
if (regex) {
this._searchSources.forEach((_ref2) => {let searchSource = _ref2.searchSource,context = _ref2.context;
tests = tests.concat(searchSource.findMatchingTests(pattern).tests);
});
}
return tests;
}
updateSearchSources(searchSources) {
this._searchSources = searchSources;
}};

View File

@@ -0,0 +1,514 @@
'use strict';var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();function _asyncToGenerator(fn) {return function () {var gen = fn.apply(this, arguments);return new Promise(function (resolve, reject) {function step(key, arg) {try {var info = gen[key](arg);var value = info.value;} catch (error) {reject(error);return;}if (info.done) {resolve(value);} else {return Promise.resolve(value).then(function (value) {step("next", value);}, function (err) {step("throw", err);});}}return step("next");});};}var _require =
require('jest-message-util');const formatExecError = _require.formatExecError; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/const snapshot = require('jest-snapshot');const pify = require('pify');const throat = require('throat');const workerFarm = require('worker-farm');const DefaultReporter = require('./reporters/DefaultReporter');const NotifyReporter = require('./reporters/NotifyReporter');const SummaryReporter = require('./reporters/SummaryReporter');
const VerboseReporter = require('./reporters/VerboseReporter');
const runTest = require('./runTest');
const TestWatcher = require('./TestWatcher');
const ReporterDispatcher = require('./ReporterDispatcher');
const SLOW_TEST_TIME = 3000;
class CancelRun extends Error {
constructor(message) {
super(message);
this.name = 'CancelRun';
}}
const TEST_WORKER_PATH = require.resolve('./TestWorker');
class TestRunner {
constructor(globalConfig, options) {
this._globalConfig = globalConfig;
this._dispatcher = new ReporterDispatcher();
this._options = options;
this._setupReporters();
}
addReporter(reporter) {
this._dispatcher.register(reporter);
}
removeReporter(ReporterClass) {
this._dispatcher.unregister(ReporterClass);
}
runTests(tests, watcher) {var _this = this;return _asyncToGenerator(function* () {
const timings = [];
const contexts = new Set();
tests.forEach(function (test) {
contexts.add(test.context);
if (test.duration) {
timings.push(test.duration);
}
});
const aggregatedResults = createAggregatedResults(tests.length);
const estimatedTime = Math.ceil(
getEstimatedTime(timings, _this._options.maxWorkers) / 1000);
// Run in band if we only have one test or one worker available.
// If we are confident from previous runs that the tests will finish quickly
// we also run in band to reduce the overhead of spawning workers.
const runInBand =
_this._options.maxWorkers <= 1 ||
tests.length <= 1 ||
tests.length <= 20 &&
timings.length > 0 &&
timings.every(function (timing) {return timing < SLOW_TEST_TIME;});
const onResult = function (test, testResult) {
if (watcher.isInterrupted()) {
return Promise.resolve();
}
if (testResult.testResults.length === 0) {
const message = 'Your test suite must contain at least one test.';
onFailure(test, {
message,
stack: new Error(message).stack });
return Promise.resolve();
}
addResult(aggregatedResults, testResult);
_this._dispatcher.onTestResult(test, testResult, aggregatedResults);
return _this._bailIfNeeded(contexts, aggregatedResults, watcher);
};
const onFailure = function (test, error) {
if (watcher.isInterrupted()) {
return;
}
const testResult = buildFailureTestResult(test.path, error);
testResult.failureMessage = formatExecError(
testResult,
test.context.config,
_this._globalConfig,
test.path);
addResult(aggregatedResults, testResult);
_this._dispatcher.onTestResult(test, testResult, aggregatedResults);
};
const updateSnapshotState = function () {
contexts.forEach(function (context) {
const status = snapshot.cleanup(
context.hasteFS,
_this._globalConfig.updateSnapshot);
aggregatedResults.snapshot.filesRemoved += status.filesRemoved;
});
const updateAll = _this._globalConfig.updateSnapshot === 'all';
aggregatedResults.snapshot.didUpdate = updateAll;
aggregatedResults.snapshot.failure = !!(!updateAll && (
aggregatedResults.snapshot.unchecked ||
aggregatedResults.snapshot.unmatched ||
aggregatedResults.snapshot.filesRemoved));
};
_this._dispatcher.onRunStart(aggregatedResults, {
estimatedTime,
showStatus: !runInBand });
try {
yield runInBand ?
_this._createInBandTestRun(tests, watcher, onResult, onFailure) :
_this._createParallelTestRun(tests, watcher, onResult, onFailure);
} catch (error) {
if (!watcher.isInterrupted()) {
throw error;
}
}
updateSnapshotState();
aggregatedResults.wasInterrupted = watcher.isInterrupted();
yield _this._dispatcher.onRunComplete(contexts, aggregatedResults);
const anyTestFailures = !(aggregatedResults.numFailedTests === 0 &&
aggregatedResults.numRuntimeErrorTestSuites === 0);
const anyReporterErrors = _this._dispatcher.hasErrors();
aggregatedResults.success = !(anyTestFailures ||
aggregatedResults.snapshot.failure ||
anyReporterErrors);
return aggregatedResults;})();
}
_createInBandTestRun(
tests,
watcher,
onResult,
onFailure)
{
const mutex = throat(1);
return tests.reduce(
(promise, test) =>
mutex(() =>
promise.
then(() => {
if (watcher.isInterrupted()) {
throw new CancelRun();
}
this._dispatcher.onTestStart(test);
return runTest(
test.path,
this._globalConfig,
test.context.config,
test.context.resolver);
}).
then(result => onResult(test, result)).
catch(err => onFailure(test, err))),
Promise.resolve());
}
_createParallelTestRun(
tests,
watcher,
onResult,
onFailure)
{
const farm = workerFarm(
{
autoStart: true,
maxConcurrentCallsPerWorker: 1,
maxConcurrentWorkers: this._options.maxWorkers,
maxRetries: 2 },
TEST_WORKER_PATH);
const mutex = throat(this._options.maxWorkers);
const worker = pify(farm);
// Send test suites to workers continuously instead of all at once to track
// the start time of individual tests.
const runTestInWorker = test =>
mutex(() => {
if (watcher.isInterrupted()) {
return Promise.reject();
}
this._dispatcher.onTestStart(test);
return worker({
config: test.context.config,
globalConfig: this._globalConfig,
path: test.path,
rawModuleMap: watcher.isWatchMode() ?
test.context.moduleMap.getRawModuleMap() :
null });
});
const onError = (err, test) => {
onFailure(test, err);
if (err.type === 'ProcessTerminatedError') {
console.error(
'A worker process has quit unexpectedly! ' +
'Most likely this is an initialization error.');
process.exit(1);
}
};
const onInterrupt = new Promise((_, reject) => {
watcher.on('change', state => {
if (state.interrupted) {
reject(new CancelRun());
}
});
});
const runAllTests = Promise.all(
tests.map(test =>
runTestInWorker(test).
then(testResult => onResult(test, testResult)).
catch(error => onError(error, test))));
const cleanup = () => workerFarm.end(farm);
return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup);
}
_shouldAddDefaultReporters(reporters) {
return (
!reporters ||
!!reporters.find(reporterConfig => reporterConfig[0] === 'default'));
}
_setupReporters() {var _globalConfig =
this._globalConfig;const collectCoverage = _globalConfig.collectCoverage,notify = _globalConfig.notify,reporters = _globalConfig.reporters;
const isDefault = this._shouldAddDefaultReporters(reporters);
if (isDefault) {
this._setupDefaultReporters();
}
if (reporters && Array.isArray(reporters)) {
this._addCustomReporters(reporters);
}
if (collectCoverage) {
// coverage reporter dependency graph is pretty big and we don't
// want to require it if we're not in the `--coverage` mode
const CoverageReporter = require('./reporters/CoverageReporter');
this.addReporter(
new CoverageReporter(this._globalConfig, {
maxWorkers: this._options.maxWorkers }));
}
if (notify) {
this.addReporter(new NotifyReporter(this._options.startRun));
}
}
_setupDefaultReporters() {
this.addReporter(
this._globalConfig.verbose ?
new VerboseReporter(this._globalConfig) :
new DefaultReporter(this._globalConfig));
this.addReporter(
new SummaryReporter(this._globalConfig, {
pattern: this._options.pattern,
testNamePattern: this._options.testNamePattern,
testPathPattern: this._options.testPathPattern }));
}
_addCustomReporters(reporters) {
const customReporters = reporters.filter(
reporterConfig => reporterConfig[0] !== 'default');
customReporters.forEach((reporter, index) => {var _getReporterProps =
this._getReporterProps(reporter);const options = _getReporterProps.options,path = _getReporterProps.path;
try {
const Reporter = require(path);
this.addReporter(new Reporter(this._globalConfig, options));
} catch (error) {
throw new Error(
'An error occurred while adding the reporter at path "' +
path +
'".' +
error.message);
}
});
}
/**
* Get properties of a reporter in an object
* to make dealing with them less painful.
*/
_getReporterProps(
reporter)
{
if (typeof reporter === 'string') {
return { path: reporter };
} else if (Array.isArray(reporter)) {var _reporter = _slicedToArray(
reporter, 2);const path = _reporter[0],options = _reporter[1];
return { options, path };
}
throw new Error('Reproter should be either a string or an array');
}
_bailIfNeeded(
contexts,
aggregatedResults,
watcher)
{
if (this._globalConfig.bail && aggregatedResults.numFailedTests !== 0) {
if (watcher.isWatchMode()) {
watcher.setState({ interrupted: true });
} else {
const exit = () => process.exit(1);
return this._dispatcher.
onRunComplete(contexts, aggregatedResults).
then(exit).
catch(exit);
}
}
return Promise.resolve();
}}
const createAggregatedResults = numTotalTestSuites => {
return {
numFailedTestSuites: 0,
numFailedTests: 0,
numPassedTestSuites: 0,
numPassedTests: 0,
numPendingTestSuites: 0,
numPendingTests: 0,
numRuntimeErrorTestSuites: 0,
numTotalTestSuites,
numTotalTests: 0,
snapshot: {
added: 0,
didUpdate: false, // is set only after the full run
failure: false,
filesAdded: 0,
// combines individual test results + results after full run
filesRemoved: 0,
filesUnmatched: 0,
filesUpdated: 0,
matched: 0,
total: 0,
unchecked: 0,
unmatched: 0,
updated: 0 },
startTime: Date.now(),
success: false,
testResults: [],
wasInterrupted: false };
};
const addResult = (
aggregatedResults,
testResult) =>
{
aggregatedResults.testResults.push(testResult);
aggregatedResults.numTotalTests +=
testResult.numPassingTests +
testResult.numFailingTests +
testResult.numPendingTests;
aggregatedResults.numFailedTests += testResult.numFailingTests;
aggregatedResults.numPassedTests += testResult.numPassingTests;
aggregatedResults.numPendingTests += testResult.numPendingTests;
if (testResult.testExecError) {
aggregatedResults.numRuntimeErrorTestSuites++;
}
if (testResult.skipped) {
aggregatedResults.numPendingTestSuites++;
} else if (testResult.numFailingTests > 0 || testResult.testExecError) {
aggregatedResults.numFailedTestSuites++;
} else {
aggregatedResults.numPassedTestSuites++;
}
// Snapshot data
if (testResult.snapshot.added) {
aggregatedResults.snapshot.filesAdded++;
}
if (testResult.snapshot.fileDeleted) {
aggregatedResults.snapshot.filesRemoved++;
}
if (testResult.snapshot.unmatched) {
aggregatedResults.snapshot.filesUnmatched++;
}
if (testResult.snapshot.updated) {
aggregatedResults.snapshot.filesUpdated++;
}
aggregatedResults.snapshot.added += testResult.snapshot.added;
aggregatedResults.snapshot.matched += testResult.snapshot.matched;
aggregatedResults.snapshot.unchecked += testResult.snapshot.unchecked;
aggregatedResults.snapshot.unmatched += testResult.snapshot.unmatched;
aggregatedResults.snapshot.updated += testResult.snapshot.updated;
aggregatedResults.snapshot.total +=
testResult.snapshot.added +
testResult.snapshot.matched +
testResult.snapshot.unmatched +
testResult.snapshot.updated;
};
const buildFailureTestResult = (
testPath,
err) =>
{
return {
console: null,
failureMessage: null,
numFailingTests: 0,
numPassingTests: 0,
numPendingTests: 0,
perfStats: {
end: 0,
start: 0 },
skipped: false,
snapshot: {
added: 0,
fileDeleted: false,
matched: 0,
unchecked: 0,
unmatched: 0,
updated: 0 },
sourceMaps: {},
testExecError: err,
testFilePath: testPath,
testResults: [] };
};
const getEstimatedTime = (timings, workers) => {
if (!timings.length) {
return 0;
}
const max = Math.max.apply(null, timings);
return timings.length <= workers ?
max :
Math.max(timings.reduce((sum, time) => sum + time) / workers, max);
};
module.exports = TestRunner;

View File

@@ -0,0 +1,116 @@
'use strict';
const fs = require('fs'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/const getCacheFilePath = require('jest-haste-map').getCacheFilePath;const FAIL = 0;const SUCCESS = 1;
class TestSequencer {
constructor() {
this._cache = new Map();
}
_getCachePath(context) {const
config = context.config;
return getCacheFilePath(config.cacheDirectory, 'perf-cache-' + config.name);
}
_getCache(test) {const
context = test.context;
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;
}
// When running more tests than we have workers available, sort the tests
// by size - big test files usually take longer to complete, so we run
// them first in an effort to minimize worker idle time at the end of a
// long test run.
//
// After a test run we store the time it took to run a test and on
// subsequent runs we use that to run the slowest tests first, yielding the
// fastest results.
sort(tests) {
const stats = {};
const fileSize = test =>
stats[test.path] || (stats[test.path] = fs.statSync(test.path).size);
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) => {
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;
if (failedA !== failedB) {
return failedA ? -1 : 1;
} else if (hasTimeA != (testB.duration != null)) {
// Check if only one of two tests has timing information
return hasTimeA != null ? 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;

View File

@@ -0,0 +1,41 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require =
require('events');const EventEmitter = _require.EventEmitter;
class TestWatcher extends EventEmitter {
constructor(_ref) {let isWatchMode = _ref.isWatchMode;
super();
this.state = { interrupted: false };
this._isWatchMode = isWatchMode;
}
setState(state) {
Object.assign(this.state, state);
this.emit('change', this.state);
}
isInterrupted() {
return this.state.interrupted;
}
isWatchMode() {
return this._isWatchMode;
}}
module.exports = TestWatcher;

View File

@@ -0,0 +1,104 @@
'use strict';
// Make sure uncaught errors are logged before we exit.
process.on('uncaughtException', err => {
console.error(err.stack);
process.exit(1);
}); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require = require('jest-haste-map');const ModuleMap = _require.ModuleMap;var _require2 = require('jest-message-util');const separateMessageFromStack = _require2.separateMessageFromStack;const Runtime = require('jest-runtime');const runTest = require('./runTest');
const formatError = error => {
if (typeof error === 'string') {var _separateMessageFromS =
separateMessageFromStack(error);const message = _separateMessageFromS.message,stack = _separateMessageFromS.stack;
return {
message,
stack,
type: 'Error' };
}
return {
message: error.message,
stack: error.stack,
type: 'Error' };
};
const resolvers = Object.create(null);
const getResolver = (config, rawModuleMap) => {
// In watch mode, the raw module map with all haste modules is passed from
// the test runner to the watch command. This is because jest-haste-map's
// watch mode does not persist the haste map on disk after every file change.
// To make this fast and consistent, we pass it from the TestRunner.
if (rawModuleMap) {
return Runtime.createResolver(
config,
new ModuleMap(rawModuleMap.map, rawModuleMap.mocks));
} else {
const name = config.name;
if (!resolvers[name]) {
resolvers[name] = Runtime.createResolver(
config,
Runtime.createHasteMap(config).readModuleMap());
}
return resolvers[name];
}
};
module.exports = (_ref,
callback) =>
{let config = _ref.config,globalConfig = _ref.globalConfig,path = _ref.path,rawModuleMap = _ref.rawModuleMap;
let parentExited = false;
const disconnectCallback = () => parentExited = true;
const removeListener = () =>
process.removeListener('disconnect', disconnectCallback);
process.on('disconnect', disconnectCallback);
try {
runTest(path, globalConfig, config, getResolver(config, rawModuleMap)).then(
result => {
removeListener();
if (!parentExited) {
callback(null, result);
}
},
error => {
removeListener();
if (!parentExited) {
callback(formatError(error));
}
});
} catch (error) {
callback(formatError(error));
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,478 @@
'use strict';
const isCI = require('is-ci'); /**
* Copyright (c) 2014, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/const check = argv => {if (argv.runInBand && argv.hasOwnProperty('maxWorkers')) {throw new Error('Both --runInBand and --maxWorkers were specified, but these two ' + 'options do not make sense together. Which is it?');}
if (argv.onlyChanged && argv._.length > 0) {
throw new Error(
'Both --onlyChanged and a path pattern were specified, but these ' +
'two options do not make sense together. Which is it? Do you want ' +
'to run tests for changed files? Or for a specific set of files?');
}
if (argv.onlyChanged && argv.watchAll) {
throw new Error(
'Both --onlyChanged and --watchAll were specified, but these two ' +
'options do not make sense together. Try the --watch option which ' +
'reruns only tests related to changed files.');
}
if (argv.findRelatedTests && argv._.length === 0) {
throw new Error(
'The --findRelatedTests option requires file paths to be specified.\n' +
'Example usage: jest --findRelatedTests ./src/source.js ' +
'./src/index.js.');
}
return true;
};
const usage = 'Usage: $0 [--config=<pathToConfigFile>] [TestPathPattern]';
const docs = 'Documentation: https://facebook.github.io/jest/';
const options = {
automock: {
default: undefined,
description: 'Automock all files by default.',
type: 'boolean' },
bail: {
alias: 'b',
default: undefined,
description: 'Exit the test suite immediately upon the first failing test.',
type: 'boolean' },
browser: {
default: undefined,
description: 'Respect the "browser" field in package.json ' +
'when resolving modules. Some packages export different versions ' +
'based on whether they are operating in node.js or a browser.',
type: 'boolean' },
cache: {
default: undefined,
description: 'Whether to use the transform cache. Disable the cache ' +
'using --no-cache.',
type: 'boolean' },
cacheDirectory: {
description: 'The directory where Jest should store its cached ' +
' dependency information.',
type: 'string' },
ci: {
default: isCI,
description: 'Whether to run Jest in continuous integration (CI) mode. ' +
'This option is on by default in most popular CI environments. It will ' +
' prevent snapshots from being written unless explicitly requested.',
type: 'boolean' },
clearMocks: {
default: undefined,
description: 'Automatically clear mock calls and instances between every ' +
'test. Equivalent to calling jest.clearAllMocks() between each test.',
type: 'boolean' },
collectCoverage: {
default: undefined,
description: 'Alias for --coverage.',
type: 'boolean' },
collectCoverageFrom: {
description: 'relative to <rootDir> glob pattern matching the files ' +
'that coverage info needs to be collected from.',
type: 'string' },
collectCoverageOnlyFrom: {
description: 'Explicit list of paths coverage will be restricted to.',
type: 'array' },
color: {
default: undefined,
description: 'Forces test results output color highlighting (even if ' +
'stdout is not a TTY). Set to false if you would like to have no colors.',
type: 'boolean' },
colors: {
default: undefined,
description: 'Alias for `--color`.',
type: 'boolean' },
config: {
alias: 'c',
description: 'The path to a jest config file specifying how to find ' +
'and execute tests. If no rootDir is set in the config, the current ' +
'directory is assumed to be the rootDir for the project. This can also ' +
'be a JSON encoded value which Jest will use as configuration.',
type: 'string' },
coverage: {
default: undefined,
description: 'Indicates that test coverage information should be ' +
'collected and reported in the output.',
type: 'boolean' },
coverageDirectory: {
description: 'The directory where Jest should output its coverage files.',
type: 'string' },
coveragePathIgnorePatterns: {
description: 'An array of regexp pattern strings that are matched ' +
'against all file paths before executing the test. If the file path' +
'matches any of the patterns, coverage information will be skipped.',
type: 'array' },
coverageReporters: {
description: 'A list of reporter names that Jest uses when writing ' +
'coverage reports. Any istanbul reporter can be used.',
type: 'array' },
coverageThreshold: {
description: 'A JSON string with which will be used to configure ' +
'minimum threshold enforcement for coverage results',
type: 'string' },
debug: {
default: undefined,
description: 'Print debugging info about your jest config.',
type: 'boolean' },
env: {
description: 'The test environment used for all tests. This can point to ' +
'any file or node module. Examples: `jsdom`, `node` or ' +
'`path/to/my-environment.js`',
type: 'string' },
expand: {
alias: 'e',
default: undefined,
description: 'Use this flag to show full diffs instead of a patch.',
type: 'boolean' },
findRelatedTests: {
default: undefined,
description: 'Find related tests for a list of source files that were ' +
'passed in as arguments. Useful for pre-commit hook integration to run ' +
'the minimal amount of tests necessary.',
type: 'boolean' },
forceExit: {
default: undefined,
description: 'Force Jest to exit after all tests have completed running. ' +
'This is useful when resources set up by test code cannot be ' +
'adequately cleaned up.',
type: 'boolean' },
globals: {
description: 'A JSON string with map of global variables that need ' +
'to be available in all test environments.',
type: 'string' },
haste: {
description: 'A JSON string with map of variables for the haste ' +
' module system',
type: 'string' },
json: {
default: undefined,
description: 'Prints the test results in JSON. This mode will send all ' +
'other test output and user messages to stderr.',
type: 'boolean' },
lastCommit: {
default: undefined,
description: 'Will run all tests affected by file changes in the last ' +
'commit made.',
type: 'boolean' },
listTests: {
default: false,
description: 'Lists all tests Jest will run given the arguments and ' +
'exits. Most useful in a CI system together with `--findRelatedTests` ' +
'to determine the tests Jest will run based on specific files',
type: 'boolean' },
logHeapUsage: {
default: undefined,
description: 'Logs the heap usage after every test. Useful to debug ' +
'memory leaks. Use together with `--runInBand` and `--expose-gc` in ' +
'node.',
type: 'boolean' },
mapCoverage: {
default: undefined,
description: 'Maps code coverage reports against original source code ' +
'when transformers supply source maps.',
type: 'boolean' },
maxWorkers: {
alias: 'w',
description: 'Specifies the maximum number of workers the worker-pool ' +
'will spawn for running tests. This defaults to the number of the ' +
'cores available on your machine. (its usually best not to override ' +
'this default)',
type: 'number' },
moduleDirectories: {
description: 'An array of directory names to be searched recursively ' +
"up from the requiring module's location.",
type: 'array' },
moduleFileExtensions: {
description: 'An array of file extensions your modules use. If you ' +
'require modules without specifying a file extension, these are the ' +
'extensions Jest will look for. ',
type: 'array' },
moduleNameMapper: {
description: 'A JSON string with a map from regular expressions to ' +
'module names that allow to stub out resources, like images or ' +
'styles with a single module',
type: 'string' },
modulePathIgnorePatterns: {
description: 'An array of regexp pattern strings that are matched ' +
'against all module paths before those paths are to be considered ' +
'"visible" to the module loader.',
type: 'array' },
modulePaths: {
description: 'An alternative API to setting the NODE_PATH env variable, ' +
'modulePaths is an array of absolute paths to additional locations to ' +
'search when resolving modules.',
type: 'array' },
noStackTrace: {
default: undefined,
description: 'Disables stack trace in test results output',
type: 'boolean' },
notify: {
default: undefined,
description: 'Activates notifications for test results.',
type: 'boolean' },
onlyChanged: {
alias: 'o',
default: undefined,
description: 'Attempts to identify which tests to run based on which ' +
"files have changed in the current repository. Only works if you're " +
'running tests in a git repository at the moment.',
type: 'boolean' },
outputFile: {
description: 'Write test results to a file when the --json option is ' +
'also specified.',
type: 'string' },
preset: {
description: "A preset that is used as a base for Jest's configuration.",
type: 'string' },
projects: {
description: 'A list of projects that use Jest to run all tests of all ' +
'projects in a single instance of Jest.',
type: 'array' },
reporters: {
description: 'A list of custom reporters for the test suite.',
type: 'array' },
resetMocks: {
default: undefined,
description: 'Automatically reset mock state between every test. ' +
'Equivalent to calling jest.resetAllMocks() between each test.',
type: 'boolean' },
resetModules: {
default: undefined,
description: 'If enabled, the module registry for every test file will ' +
'be reset before running each individual test.',
type: 'boolean' },
resolver: {
description: 'A JSON string which allows the use of a custom resolver.',
type: 'string' },
rootDir: {
description: 'The root directory that Jest should scan for tests and ' +
'modules within.',
type: 'string' },
roots: {
description: 'A list of paths to directories that Jest should use to ' +
'search for files in.',
type: 'array' },
runInBand: {
alias: 'i',
default: undefined,
description: 'Run all tests serially in the current process (rather than ' +
'creating a worker pool of child processes that run tests). This ' +
'is sometimes useful for debugging, but such use cases are pretty ' +
'rare.',
type: 'boolean' },
setupFiles: {
description: 'The paths to modules that run some code to configure or ' +
'set up the testing environment before each test. ',
type: 'array' },
setupTestFrameworkScriptFile: {
description: 'The path to a module that runs some code to configure or ' +
'set up the testing framework before each test.',
type: 'string' },
showConfig: {
default: undefined,
description: 'Print your jest config and then exits.',
type: 'boolean' },
silent: {
default: undefined,
description: 'Prevent tests from printing messages through the console.',
type: 'boolean' },
snapshotSerializers: {
description: 'A list of paths to snapshot serializer modules Jest should ' +
'use for snapshot testing.',
type: 'array' },
testEnvironment: {
description: 'Alias for --env',
type: 'string' },
testMatch: {
description: 'The glob patterns Jest uses to detect test files.',
type: 'array' },
testNamePattern: {
alias: 't',
description: 'Run only tests with a name that matches the regex pattern.',
type: 'string' },
testPathIgnorePatterns: {
description: 'An array of regexp pattern strings that are matched ' +
'against all test paths before executing the test. If the test path ' +
'matches any of the patterns, it will be skipped.',
type: 'array' },
testPathPattern: {
description: 'A regexp pattern string that is matched against all tests ' +
'paths before executing the test.',
type: 'string' },
testRegex: {
description: 'The regexp pattern Jest uses to detect test files.',
type: 'string' },
testResultsProcessor: {
description: 'Allows the use of a custom results processor. ' +
'This processor must be a node module that exports ' +
'a function expecting as the first argument the result object',
type: 'string' },
testRunner: {
description: 'Allows to specify a custom test runner. The default is ' +
' `jasmine2`. A path to a custom test runner can be provided: ' +
'`<rootDir>/path/to/testRunner.js`.',
type: 'string' },
testURL: {
description: 'This option sets the URL for the jsdom environment.',
type: 'string' },
timers: {
description: 'Setting this value to fake allows the use of fake timers ' +
'for functions such as setTimeout.',
type: 'string' },
transform: {
description: 'A JSON string which maps from regular expressions to paths ' +
'to transformers.',
type: 'string' },
transformIgnorePatterns: {
description: 'An array of regexp pattern strings that are matched ' +
'against all source file paths before transformation.',
type: 'array' },
unmockedModulePathPatterns: {
description: 'An array of regexp pattern strings that are matched ' +
'against all modules before the module loader will automatically ' +
'return a mock for them.',
type: 'array' },
updateSnapshot: {
alias: 'u',
default: undefined,
description: 'Use this flag to re-record snapshots. ' +
'Can be used together with a test suite pattern or with ' +
'`--testNamePattern` to re-record snapshot for test matching ' +
'the pattern',
type: 'boolean' },
useStderr: {
default: undefined,
description: 'Divert all output to stderr.',
type: 'boolean' },
verbose: {
default: undefined,
description: 'Display individual test results with the test suite ' +
'hierarchy.',
type: 'boolean' },
version: {
alias: 'v',
default: undefined,
description: 'Print the version and exit',
type: 'boolean' },
watch: {
default: undefined,
description: 'Watch files for changes and rerun tests related to ' +
'changed files. If you want to re-run all tests when a file has ' +
'changed, use the `--watchAll` option.',
type: 'boolean' },
watchAll: {
default: undefined,
description: 'Watch files for changes and rerun all tests. If you want ' +
'to re-run only the tests related to the changed files, use the ' +
'`--watch` option.',
type: 'boolean' },
watchman: {
default: undefined,
description: 'Whether to use watchman for file crawling. Disable using ' +
'--no-watchman.',
type: 'boolean' } };
module.exports = {
check,
docs,
options,
usage };

View File

@@ -0,0 +1,49 @@
'use strict';
const path = require('path'); /**
* Copyright (c) 2014, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/const chalk = require('chalk');const fs = require('graceful-fs');function getJest(packageRoot) {const packageJSONPath = path.join(packageRoot, 'package.json');const binPath = path.join(packageRoot, 'node_modules/jest-cli');if (fs.existsSync(binPath)) {/* $FlowFixMe */
return require(binPath);
} else {
const jest = require('../jest');
// Check if Jest is specified in `package.json` but not installed.
if (fs.existsSync(packageJSONPath)) {
/* $FlowFixMe */
const packageJSON = require(packageJSONPath);
const dependencies = packageJSON.dependencies;
const devDependencies = packageJSON.devDependencies;
if (
dependencies && dependencies['jest-cli'] ||
devDependencies && devDependencies['jest-cli'])
{
process.on('exit', () =>
console.log(
chalk.red(
'Please run `npm install` to use the version of Jest intended ' +
'for this project.')));
}
}
return jest;
}
}
module.exports = getJest;

View File

@@ -0,0 +1,50 @@
'use strict'; /**
* Copyright (c) 2014, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require =
require('jest-util');const validateCLIOptions = _require.validateCLIOptions;
const yargs = require('yargs');
const args = require('./args');
const getJest = require('./getJest');
const runCLI = require('./runCLI');
function run(argv, project) {
argv = yargs(argv || process.argv.slice(2)).
usage(args.usage).
help().
alias('help', 'h').
options(args.options).
epilogue(args.docs).
check(args.check).argv;
validateCLIOptions(argv, args.options);
if (!project) {
project = process.cwd();
}
if (!argv.projects) {
argv.projects = [project];
}
const execute = argv.projects.length === 1 ? getJest(project).runCLI : runCLI;
execute(argv, argv.projects, result => {
const code = !result || result.success ? 0 : 1;
process.on('exit', () => process.exit(code));
if (argv && argv.forceExit) {
process.exit(code);
}
});
}
exports.run = run;
exports.runCLI = runCLI;

View File

@@ -0,0 +1,139 @@
'use strict';function _asyncToGenerator(fn) {return function () {var gen = fn.apply(this, arguments);return new Promise(function (resolve, reject) {function step(key, arg) {try {var info = gen[key](arg);var value = info.value;} catch (error) {reject(error);return;}if (info.done) {resolve(value);} else {return Promise.resolve(value).then(function (value) {step("next", value);}, function (err) {step("throw", err);});}}return step("next");});};}
const Runtime = require('jest-runtime'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require = require('jest-util');const Console = _require.Console,clearLine = _require.clearLine;var _require2 = require('jest-util');const createDirectory = _require2.createDirectory;var _require3 = require('jest-config');const readConfig = _require3.readConfig;const chalk = require('chalk');const createContext = require('../lib/createContext');const getMaxWorkers = require('../lib/getMaxWorkers');const handleDeprecationWarnings = require('../lib/handleDeprecationWarnings');
const logDebugMessages = require('../lib/logDebugMessages');
const preRunMessage = require('../preRunMessage');
const runJest = require('../runJest');
const TestWatcher = require('../TestWatcher');
const watch = require('../watch');
const VERSION = require('../../package.json').version;
module.exports = (() => {var _ref = _asyncToGenerator(function* (
argv,
projects,
onComplete)
{
const realFs = require('fs');
const fs = require('graceful-fs');
fs.gracefulify(realFs);
const pipe = argv.json ? process.stderr : process.stdout;
if (argv.version) {
pipe.write(`v${VERSION}\n`);
onComplete && onComplete();
return;
}
const _run = (() => {var _ref2 = _asyncToGenerator(function* (globalConfig, configs) {
const hasteMapInstances = Array(configs.length);
const contexts = yield Promise.all(
configs.map((() => {var _ref4 = _asyncToGenerator(function* (_ref3, index) {let config = _ref3.config;
createDirectory(config.cacheDirectory);
const hasteMapInstance = Runtime.createHasteMap(config, {
console: new Console(pipe, pipe),
maxWorkers: getMaxWorkers(argv),
resetCache: !config.cache,
watch: globalConfig.watch,
watchman: globalConfig.watchman });
hasteMapInstances[index] = hasteMapInstance;
return createContext(config, (yield hasteMapInstance.build()));
});return function (_x6, _x7) {return _ref4.apply(this, arguments);};})()));
if (argv.watch || argv.watchAll) {
if (configs.some(function (_ref5) {let hasDeprecationWarnings = _ref5.hasDeprecationWarnings;return hasDeprecationWarnings;})) {
try {
yield handleDeprecationWarnings(pipe, process.stdin);
return watch(globalConfig, contexts, argv, pipe, hasteMapInstances);
} catch (e) {
process.exit(0);
}
}
return watch(globalConfig, contexts, argv, pipe, hasteMapInstances);
} else {
const startRun = function () {
if (!argv.listTests) {
preRunMessage.print(pipe);
}
runJest(
globalConfig,
contexts,
argv,
pipe,
new TestWatcher({ isWatchMode: false }),
startRun,
onComplete);
};
return startRun();
}
});return function _run(_x4, _x5) {return _ref2.apply(this, arguments);};})();
try {
let globalConfig;
let hasDeprecationWarnings;
let configs = [];
let config;
if (projects.length === 1) {var _readConfig =
readConfig(
argv,
projects[0]);config = _readConfig.config;globalConfig = _readConfig.globalConfig;hasDeprecationWarnings = _readConfig.hasDeprecationWarnings;
configs = [{ config, globalConfig, hasDeprecationWarnings }];
if (globalConfig.projects && globalConfig.projects.length) {
projects = globalConfig.projects;
}
}
if (projects.length > 1) {
configs = projects.map(function (root) {return readConfig(argv, root);});
// If no config was passed initially, use the one from the first project
if (!globalConfig && !config) {
globalConfig = configs[0].globalConfig;
config = configs[0].config;
}
}
if (!config || !globalConfig || !configs.length) {
throw new Error('jest: No configuration found for any project.');
}
if (argv.debug || argv.showConfig) {
logDebugMessages(globalConfig, config, pipe);
}
if (argv.showConfig) {
process.exit(0);
}
yield _run(globalConfig, configs);
} catch (error) {
clearLine(process.stderr);
clearLine(process.stdout);
console.error(chalk.red(error.stack));
process.exit(1);
}
});return function (_x, _x2, _x3) {return _ref.apply(this, arguments);};})();

View File

@@ -0,0 +1,42 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const isWindows = process.platform === 'win32';
const CLEAR = isWindows ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H';
const KEYS = {
A: '61',
ARROW_DOWN: '1b5b42',
ARROW_LEFT: '1b5b44',
ARROW_RIGHT: '1b5b43',
ARROW_UP: '1b5b41',
BACKSPACE: isWindows ? '08' : '7f',
C: '63',
CONTROL_C: '03',
CONTROL_D: '04',
ENTER: '0d',
ESCAPE: '1b',
O: '6f',
P: '70',
Q: '71',
QUESTION_MARK: '3f',
T: '74',
U: '75',
W: '77' };
const ICONS = {
failed: isWindows ? '\u00D7' : '\u2715',
pending: '\u25CB',
success: isWindows ? '\u221A' : '\u2713' };
module.exports = { CLEAR, ICONS, KEYS };

View File

@@ -0,0 +1,29 @@
// Copyright 2004-present Facebook. All Rights Reserved.
// Instrumentation Header
{
var <%= instrumented.names.statement %>;
var <%= instrumented.names.expression %>;
var <%= instrumented.names.block %>;
var nodes = <%= coverageStorageVar %>.nodes = {};
var blocks = <%= coverageStorageVar %>.blocks = {};
<%= instrumented.names.statement %> = function(i) {
var node = nodes[i] = (nodes[i] || {index: i, count:0})
node.count++;
};
<%= instrumented.names.expression %> = function(i) {
var node = nodes[i] = (nodes[i] || {index: i, count:0})
node.count++;
};
<%= instrumented.names.block %> = function(i) {
var block = blocks[i] = (blocks[i] || {index: i, count:0})
block.count++;
};
};
////////////////////////
// Instrumented Code
<%= source %>

View File

@@ -0,0 +1,47 @@
'use strict';
const IstanbulInstrument = require('istanbul-lib-instrument'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require = require('jest-runtime');const ScriptTransformer = _require.ScriptTransformer,shouldInstrument = _require.shouldInstrument;module.exports = function (source, filename, globalConfig, config)
{
const coverageOptions = {
collectCoverage: globalConfig.collectCoverage,
collectCoverageFrom: globalConfig.collectCoverageFrom,
collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom,
mapCoverage: globalConfig.mapCoverage };
if (shouldInstrument(filename, coverageOptions, config)) {
// Transform file without instrumentation first, to make sure produced
// source code is ES6 (no flowtypes etc.) and can be instrumented
const transformResult = new ScriptTransformer(config).transformSource(
filename,
source,
false,
globalConfig.mapCoverage);
const instrumenter = IstanbulInstrument.createInstrumenter();
instrumenter.instrumentSync(transformResult.code, filename);
return {
coverage: instrumenter.fileCoverage,
sourceMapPath: transformResult.sourceMapPath };
} else {
return null;
}
};

View File

@@ -0,0 +1,25 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const VERSION = require('../package.json').version;
const SearchSource = require('./SearchSource');
const TestRunner = require('./TestRunner');
const TestWatcher = require('./TestWatcher');var _require =
require('./cli');const run = _require.run,runCLI = _require.runCLI;
module.exports = {
SearchSource,
TestRunner,
TestWatcher,
getVersion: () => VERSION,
run,
runCLI };

View File

@@ -0,0 +1,60 @@
'use strict';var _require =
require('console');const Console = _require.Console; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require2 = require('util');const format = _require2.format;const callsites = require('callsites');class BufferedConsole extends Console {constructor() {
const buffer = [];
super({ write: message => BufferedConsole.write(buffer, 'log', message) });
this._buffer = buffer;
}
static write(
buffer,
type,
message,
level)
{
const call = callsites()[level != null ? level : 2];
const origin = call.getFileName() + ':' + call.getLineNumber();
buffer.push({ message, origin, type });
return buffer;
}
log() {
BufferedConsole.write(this._buffer, 'log', format.apply(null, arguments));
}
info() {
BufferedConsole.write(this._buffer, 'info', format.apply(null, arguments));
}
warn() {
BufferedConsole.write(this._buffer, 'warn', format.apply(null, arguments));
}
error() {
BufferedConsole.write(this._buffer, 'error', format.apply(null, arguments));
}
getBuffer() {
return this._buffer;
}}
module.exports = BufferedConsole;

View File

@@ -0,0 +1,114 @@
'use strict';var _require =
require('../constants');const KEYS = _require.KEYS; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/class Prompt {
constructor() {
this._onResize = this._onResize.bind(this);
}
_onResize() {
this._onChange(this._value);
}
enter(
onChange,
onSuccess,
onCancel)
{
this._entering = true;
this._value = '';
this._onSuccess = onSuccess;
this._onCancel = onCancel;
this._typeaheadSelection = null;
this._typeaheadOffset = -1;
this._typeaheadLength = 0;
this._onChange = () =>
onChange(this._value, {
max: 10,
offset: this._typeaheadOffset });
this._onChange();
process.stdout.on('resize', this._onResize);
}
setTypeaheadLength(length) {
this._typeaheadLength = length;
}
setTypheadheadSelection(selected) {
this._typeaheadSelection = selected;
}
put(key) {
switch (key) {
case KEYS.ENTER:
this._entering = false;
this._onSuccess(this._typeaheadSelection || this._value);
this.abort();
break;
case KEYS.ESCAPE:
this._entering = false;
this._onCancel(this._value);
this.abort();
break;
case KEYS.ARROW_DOWN:
this._typeaheadOffset = Math.min(
this._typeaheadOffset + 1,
this._typeaheadLength - 1);
this._onChange();
break;
case KEYS.ARROW_UP:
this._typeaheadOffset = Math.max(this._typeaheadOffset - 1, -1);
this._onChange();
break;
case KEYS.ARROW_LEFT:
case KEYS.ARROW_RIGHT:
break;
default:
const char = new Buffer(key, 'hex').toString();
this._value = key === KEYS.BACKSPACE ?
this._value.slice(0, -1) :
this._value + char;
this._typeaheadOffset = -1;
this._typeaheadSelection = null;
this._onChange();
break;}
}
abort() {
this._entering = false;
this._value = '';
process.stdout.removeListener('resize', this._onResize);
}
isEntering() {
return this._entering;
}}
module.exports = Prompt;

View File

@@ -0,0 +1,16 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const chalk = require('chalk');
module.exports = (str, start, end) =>
chalk.dim(str.slice(0, start)) +
chalk.reset(str.slice(start, end)) +
chalk.dim(str.slice(end));

View File

@@ -0,0 +1,24 @@
'use strict';
const Runtime = require('jest-runtime'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/module.exports = (config, _ref) => {let hasteFS = _ref.hasteFS,moduleMap = _ref.moduleMap;return { config, hasteFS, moduleMap,
resolver: Runtime.createResolver(config, moduleMap) };};

View File

@@ -0,0 +1,61 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const chalk = require('chalk');
const colorize = require('./colorize');
const DOTS = '...';
const ENTER = '⏎';
module.exports = (testName, pattern, width) => {
const inlineTestName = testName.replace(/(\r\n|\n|\r)/gm, ENTER);
let regexp;
try {
regexp = new RegExp(pattern, 'i');
} catch (e) {
return chalk.dim(inlineTestName);
}
const match = inlineTestName.match(regexp);
if (!match) {
return chalk.dim(inlineTestName);
}
// $FlowFixMe
const startPatternIndex = Math.max(match.index, 0);
const endPatternIndex = startPatternIndex + match[0].length;
if (inlineTestName.length <= width) {
return colorize(inlineTestName, startPatternIndex, endPatternIndex);
}
const slicedTestName = inlineTestName.slice(0, width - DOTS.length);
if (startPatternIndex < slicedTestName.length) {
if (endPatternIndex > slicedTestName.length) {
return colorize(
slicedTestName + DOTS,
startPatternIndex,
slicedTestName.length + DOTS.length);
} else {
return colorize(
slicedTestName + DOTS,
Math.min(startPatternIndex, slicedTestName.length),
endPatternIndex);
}
}
return `${chalk.dim(slicedTestName)}${chalk.reset(DOTS)}`;
};

View File

@@ -0,0 +1,26 @@
'use strict';
const os = require('os'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/const getMaxWorkers = argv => {if (argv.runInBand) {return 1;} else if (argv.maxWorkers) {return parseInt(argv.maxWorkers, 10);} else {const cpus = os.cpus().length;
return Math.max(argv.watch ? Math.floor(cpus / 2) : cpus - 1, 1);
}
};
module.exports = getMaxWorkers;

View File

@@ -0,0 +1,74 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require =
require('jest-util');const clearLine = _require.clearLine;
const chalk = require('chalk');
const validatePattern = require('./validatePattern');
const DEFAULT_PATTERN_INFO = {
input: '',
shouldTreatInputAsPattern: false,
testPathPattern: '' };
const showTestPathPatternError = testPathPattern => {
clearLine(process.stdout);
console.log(
chalk.red(
` Invalid testPattern ${testPathPattern} supplied. ` +
`Running all tests instead.`));
};
module.exports = argv => {
if (argv.onlyChanged) {
return {
input: '',
lastCommit: argv.lastCommit,
onlyChanged: true,
watch: argv.watch };
}
if (argv.testPathPattern) {
if (validatePattern(argv.testPathPattern)) {
return {
input: argv.testPathPattern,
shouldTreatInputAsPattern: true,
testPathPattern: argv.testPathPattern };
} else {
showTestPathPatternError(argv.testPathPattern);
}
}
if (argv._ && argv._.length) {
const testPathPattern = argv._.join('|');
if (validatePattern(testPathPattern)) {
return {
findRelatedTests: argv.findRelatedTests,
input: argv._.join(' '),
paths: argv._,
shouldTreatInputAsPattern: false,
testPathPattern };
} else {
showTestPathPatternError(testPathPattern);
}
}
return DEFAULT_PATTERN_INFO;
};

View File

@@ -0,0 +1,45 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const chalk = require('chalk');var _require =
require('../constants');const KEYS = _require.KEYS;
module.exports = function (
pipe)
{let stdin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : process.stdin;
return new Promise((resolve, reject) => {
if (typeof stdin.setRawMode === 'function') {
const messages = [
chalk.red('There are deprecation warnings.\n'),
chalk.dim(' \u203A Press ') + 'Enter' + chalk.dim(' to continue.'),
chalk.dim(' \u203A Press ') + 'Esc' + chalk.dim(' to exit.')];
pipe.write(messages.join('\n'));
// $FlowFixMe
stdin.setRawMode(true);
stdin.resume();
stdin.setEncoding('hex');
stdin.on('data', key => {
if (key === KEYS.ENTER) {
resolve();
} else if (
[KEYS.ESCAPE, KEYS.CONTROL_C, KEYS.CONTROL_D].indexOf(key) !== -1)
{
reject();
}
});
} else {
resolve();
}
});
};

View File

@@ -0,0 +1,59 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const path = require('path');
const chalk = require('chalk');
const colorize = require('./colorize');
const trim = '...';
const relativePathHead = './';
const highlight = (
rawPath,
filePath,
pattern,
rootDir) =>
{
let regexp;
try {
regexp = new RegExp(pattern, 'i');
} catch (e) {
return chalk.dim(filePath);
}
rawPath = chalk.stripColor(rawPath);
filePath = chalk.stripColor(filePath);
const match = rawPath.match(regexp);
if (!match) {
return chalk.dim(filePath);
}
let offset;
let trimLength;
if (filePath.startsWith(trim)) {
offset = rawPath.length - filePath.length;
trimLength = trim.length;
} else if (filePath.startsWith(relativePathHead)) {
offset = rawPath.length - filePath.length;
trimLength = relativePathHead.length;
} else {
offset = rootDir.length + path.sep.length;
trimLength = 0;
}
const start = match.index - offset;
const end = start + match[0].length;
return colorize(filePath, Math.max(start, 0), Math.max(end, trimLength));
};
module.exports = highlight;

View File

@@ -0,0 +1,31 @@
'use strict';
const path = require('path'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/const SNAPSHOT_EXTENSION = 'snap';function isValidPath(globalConfig, config, filePath) {
const coverageDirectory =
globalConfig.coverageDirectory || path.resolve(config.rootDir, 'coverage');
return (
!filePath.includes(coverageDirectory) &&
!filePath.endsWith(`.${SNAPSHOT_EXTENSION}`));
}
module.exports = isValidPath;

View File

@@ -0,0 +1,32 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const VERSION = require('../../package.json').version;
const logDebugMessages = (
globalConfig,
config,
pipe) =>
{
/* $FlowFixMe */
const testFramework = require(config.testRunner);
const output = {
config,
framework: testFramework.name,
globalConfig,
version: VERSION };
pipe.write(JSON.stringify(output, null, ' ') + '\n');
};
module.exports = logDebugMessages;

View File

@@ -0,0 +1,103 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
'use strict';
const chalk = require('chalk');
const ansiEscapes = require('ansi-escapes');
const stringLength = require('string-length');
const Prompt = require('./Prompt');
const pluralize = (count, text) =>
count === 1 ? text : text + 's';
const printPatternMatches = function (
count,
entity,
pipe)
{let extraText = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';
const pluralized = pluralize(count, entity);
const result = count ?
`\n\n Pattern matches ${count} ${pluralized}` :
`\n\n Pattern matches no ${pluralized}`;
pipe.write(result + extraText);
};
const printPatternCaret = (
pattern,
pipe) =>
{
const inputText = `${chalk.dim(' pattern \u203A')} ${pattern}`;
pipe.write(ansiEscapes.eraseDown);
pipe.write(inputText);
pipe.write(ansiEscapes.cursorSavePosition);
};
const printRestoredPatternCaret = (
pattern,
currentUsageRows,
pipe) =>
{
const inputText = `${chalk.dim(' pattern \u203A')} ${pattern}`;
pipe.write(
ansiEscapes.cursorTo(stringLength(inputText), currentUsageRows - 1));
pipe.write(ansiEscapes.cursorRestorePosition);
};
const printStartTyping = (
entity,
pipe) =>
{
pipe.write(
`\n\n ${chalk.italic.yellow(`Start typing to filter by a ${entity} regex pattern.`)}`);
};
const printMore = (
entity,
pipe,
more) =>
{
pipe.write(
`\n ${chalk.dim(`...and ${more} more ${pluralize(more, entity)}`)}`);
};
const printTypeaheadItem = (
item,
pipe) =>
pipe.write(`\n ${chalk.dim('\u203A')} ${item}`);
const formatTypeaheadSelection = (
item,
index,
activeIndex,
prompt) =>
{
if (index === activeIndex) {
prompt.setTypheadheadSelection(chalk.stripColor(item));
return chalk.black.bgYellow(chalk.stripColor(item));
}
return item;
};
module.exports = {
formatTypeaheadSelection,
printMore,
printPatternCaret,
printPatternMatches,
printRestoredPatternCaret,
printStartTyping,
printTypeaheadItem };

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
'use strict';
const scroll = (size, _ref) => {let offset = _ref.offset,max = _ref.max;
let start = 0;
let index = Math.min(offset, size);
const halfScreen = max / 2;
if (index <= halfScreen) {
start = 0;
} else {
if (size >= max) {
start = Math.min(index - halfScreen - 1, size - max);
}
index = Math.min(index - start, size);
}
return {
end: Math.min(size, start + max),
index,
start };
};
module.exports = scroll;

View File

@@ -0,0 +1,15 @@
"use strict"; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
/* $FlowFixMe */
const getTerminalWidth = () => process.stdout.columns;
module.exports = {
getTerminalWidth };

View File

@@ -0,0 +1,52 @@
'use strict';
const getTestPathPattern = require('./getTestPathPattern'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/module.exports = (argv, mode, options) => {
if (mode === 'watch') {
argv.watch = true;
argv.watchAll = false;
} else if (mode === 'watchAll') {
argv.watch = false;
argv.watchAll = true;
}
if (options.testPathPattern) {
argv.testPathPattern = options.testPathPattern;
} else if (options.testPathPattern === '') {
delete argv.testPathPattern;
delete argv._;
}
if (options.testNamePattern) {
argv.testNamePattern = options.testNamePattern;
} else if (options.testNamePattern === '') {
delete argv.testNamePattern;
}
argv.onlyChanged = false;
argv.onlyChanged =
getTestPathPattern(argv).input === '' &&
!argv.watchAll &&
!argv.testNamePattern;
if (options.noSCM) {
argv.noSCM = true;
}
};

View File

@@ -0,0 +1,24 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const validatePattern = pattern => {
if (pattern) {
try {
// eslint-disable-next-line no-new
new RegExp(pattern, 'i');
} catch (e) {
return false;
}
}
return true;
};
module.exports = validatePattern;

View File

@@ -0,0 +1,29 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require =
require('jest-util');const clearLine = _require.clearLine;
const chalk = require('chalk');
const isCI = require('is-ci');
const print = stream => {
if (process.stdout.isTTY && !isCI) {
stream.write(chalk.bold.dim('Determining test suites to run...'));
}
};
const remove = stream => {
if (stream.isTTY && !isCI) {
clearLine(stream);
}
};
module.exports = {
print,
remove };

View File

@@ -0,0 +1,49 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const preRunMessage = require('../preRunMessage');
class BaseReporter {
log(message) {
process.stderr.write(message + '\n');
}
onRunStart(results, options) {
preRunMessage.remove(process.stderr);
}
onTestResult(test, testResult, results) {}
onTestStart(test) {}
onRunComplete(
contexts,
aggregatedResults)
{}
_setError(error) {
this._error = error;
}
// Return an error that occurred during reporting. This error will
// define whether the test run was successful or failed.
getLastError() {
return this._error;
}}
module.exports = BaseReporter;

View File

@@ -0,0 +1,252 @@
'use strict';function _asyncToGenerator(fn) {return function () {var gen = fn.apply(this, arguments);return new Promise(function (resolve, reject) {function step(key, arg) {try {var info = gen[key](arg);var value = info.value;} catch (error) {reject(error);return;}if (info.done) {resolve(value);} else {return Promise.resolve(value).then(function (value) {step("next", value);}, function (err) {step("throw", err);});}}return step("next");});};}var _require =
require('jest-util');const clearLine = _require.clearLine; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require2 = require('istanbul-api');const createReporter = _require2.createReporter;const chalk = require('chalk');const isCI = require('is-ci');const istanbulCoverage = require('istanbul-lib-coverage');const libSourceMaps = require('istanbul-lib-source-maps');const pify = require('pify');const workerFarm = require('worker-farm');
const BaseReporter = require('./BaseReporter');
const FAIL_COLOR = chalk.bold.red;
const RUNNING_TEST_COLOR = chalk.bold.dim;
const isInteractive = process.stdout.isTTY && !isCI;
class CoverageReporter extends BaseReporter {
constructor(globalConfig, options) {
super(globalConfig);
this._coverageMap = istanbulCoverage.createCoverageMap({});
this._globalConfig = globalConfig;
this._sourceMapStore = libSourceMaps.createSourceMapStore();
this._maxWorkers = options.maxWorkers;
}
onTestResult(
test,
testResult,
aggregatedResults)
{
if (testResult.coverage) {
this._coverageMap.merge(testResult.coverage);
// Remove coverage data to free up some memory.
delete testResult.coverage;
Object.keys(testResult.sourceMaps).forEach(sourcePath => {
this._sourceMapStore.registerURL(
sourcePath,
testResult.sourceMaps[sourcePath]);
});
}
}
onRunComplete(
contexts,
aggregatedResults)
{var _this = this;return _asyncToGenerator(function* () {
yield _this._addUntestedFiles(_this._globalConfig, contexts);
let map = _this._coverageMap;
let sourceFinder;
if (_this._globalConfig.mapCoverage) {var _sourceMapStore$trans =
_this._sourceMapStore.transformCoverage(map);map = _sourceMapStore$trans.map;sourceFinder = _sourceMapStore$trans.sourceFinder;
}
const reporter = createReporter();
try {
if (_this._globalConfig.coverageDirectory) {
reporter.dir = _this._globalConfig.coverageDirectory;
}
let coverageReporters = _this._globalConfig.coverageReporters || [];
if (
!_this._globalConfig.useStderr &&
coverageReporters.length &&
coverageReporters.indexOf('text') === -1)
{
coverageReporters = coverageReporters.concat(['text-summary']);
}
reporter.addAll(coverageReporters);
reporter.write(map, sourceFinder && { sourceFinder });
aggregatedResults.coverageMap = map;
} catch (e) {
console.error(
chalk.red(`
Failed to write coverage reports:
ERROR: ${e.toString()}
STACK: ${e.stack}
`));
}
_this._checkThreshold(_this._globalConfig, map);})();
}
_addUntestedFiles(globalConfig, contexts) {
const files = [];
contexts.forEach(context => {
const config = context.config;
if (
globalConfig.collectCoverageFrom &&
globalConfig.collectCoverageFrom.length)
{
context.hasteFS.
matchFilesWithGlob(globalConfig.collectCoverageFrom, config.rootDir).
forEach(filePath =>
files.push({
config,
path: filePath }));
}
});
if (!files.length) {
return Promise.resolve();
}
if (isInteractive) {
process.stderr.write(
RUNNING_TEST_COLOR('Running coverage on untested files...'));
}
let worker;
let farm;
if (this._maxWorkers <= 1) {
worker = pify(require('./CoverageWorker'));
} else {
farm = workerFarm(
{
autoStart: true,
maxConcurrentCallsPerWorker: 1,
maxConcurrentWorkers: this._maxWorkers,
maxRetries: 2 },
require.resolve('./CoverageWorker'));
worker = pify(farm);
}
const instrumentation = [];
files.forEach(fileObj => {
const filename = fileObj.path;
const config = fileObj.config;
if (!this._coverageMap.data[filename]) {
const promise = worker({
config,
globalConfig,
path: filename }).
then(result => {
if (result) {
this._coverageMap.addFileCoverage(result.coverage);
if (result.sourceMapPath) {
this._sourceMapStore.registerURL(
filename,
result.sourceMapPath);
}
}
}).
catch(error => {
console.error(chalk.red(error.message));
});
instrumentation.push(promise);
}
});
const cleanup = () => {
if (isInteractive) {
clearLine(process.stderr);
}
if (farm) {
workerFarm.end(farm);
}
};
return Promise.all(instrumentation).then(cleanup).catch(cleanup);
}
_checkThreshold(globalConfig, map) {
if (globalConfig.coverageThreshold) {
const results = map.getCoverageSummary().toJSON();
function check(name, thresholds, actuals) {
return [
'statements',
'branches',
'lines',
'functions'].
reduce((errors, key) => {
const actual = actuals[key].pct;
const actualUncovered = actuals[key].total - actuals[key].covered;
const threshold = thresholds[key];
if (threshold != null) {
if (threshold < 0) {
if (threshold * -1 < actualUncovered) {
errors.push(
`Jest: Uncovered count for ${key} (${actualUncovered})` +
`exceeds ${name} threshold (${-1 * threshold})`);
}
} else if (actual < threshold) {
errors.push(
`Jest: Coverage for ${key} (${actual}` +
`%) does not meet ${name} threshold (${threshold}%)`);
}
}
return errors;
}, []);
}
const errors = check(
'global',
globalConfig.coverageThreshold.global,
results);
if (errors.length > 0) {
this.log(`${FAIL_COLOR(errors.join('\n'))}`);
this._setError(new Error(errors.join('\n')));
}
}
}
// Only exposed for the internal runner. Should not be used
getCoverageMap() {
return this._coverageMap;
}}
module.exports = CoverageReporter;

View File

@@ -0,0 +1,56 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const fs = require('fs');
const generateEmptyCoverage = require('../generateEmptyCoverage');
function formatCoverageError(error, filename) {
const message = `
Failed to collect coverage from ${filename}
ERROR: ${error}
STACK: ${error.stack}
`;
return {
message,
stack: error.stack,
type: 'ERROR' };
}
// Make sure uncaught errors are logged before we exit.
process.on('uncaughtException', err => {
console.error(err.stack);
process.exit(1);
});
module.exports = (_ref,
callback) =>
{let config = _ref.config,globalConfig = _ref.globalConfig,path = _ref.path;
try {
const source = fs.readFileSync(path, 'utf8');
const result = generateEmptyCoverage(source, path, globalConfig, config);
callback(null, result);
} catch (error) {
callback(formatCoverageError(error, path), undefined);
}
};

View File

@@ -0,0 +1,174 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
/* global stream$Writable, tty$WriteStream */var _require =
require('jest-util');const clearLine = _require.clearLine;
const chalk = require('chalk');
const isCI = require('is-ci');
const BaseReporter = require('./BaseReporter');
const Status = require('./Status');
const getConsoleOutput = require('./getConsoleOutput');
const getResultHeader = require('./getResultHeader');
const TITLE_BULLET = chalk.bold('\u25cf ');
const isInteractive = process.stdin.isTTY && !isCI;
class DefaultReporter extends BaseReporter {
// ANSI clear sequence for the last printed status
constructor(globalConfig) {
super();
this._globalConfig = globalConfig;
this._clear = '';
this._out = process.stdout.write.bind(process.stdout);
this._err = process.stderr.write.bind(process.stderr);
this._status = new Status();
this._wrapStdio(process.stdout);
this._wrapStdio(process.stderr);
this._status.onChange(() => {
this._clearStatus();
this._printStatus();
});
}
_wrapStdio(stream) {
const originalWrite = stream.write;
let buffer = [];
let timeout = null;
const doFlush = () => {
const string = buffer.join('');
buffer = [];
// This is to avoid conflicts between random output and status text
this._clearStatus();
originalWrite.call(stream, string);
this._printStatus();
};
const flush = () => {
// If the process blows up no errors would be printed.
// There should be a smart way to buffer stderr, but for now
// we just won't buffer it.
if (stream === process.stderr) {
doFlush();
} else {
if (!timeout) {
timeout = setTimeout(() => {
doFlush();
timeout = null;
}, 100);
}
}
};
// $FlowFixMe
stream.write = chunk => {
buffer.push(chunk);
flush();
return true;
};
}
_clearStatus() {
if (isInteractive) {
this._out(this._clear);
}
}
_printStatus() {var _status$get =
this._status.get();const content = _status$get.content,clear = _status$get.clear;
this._clear = clear;
if (isInteractive) {
this._out(content);
}
}
onRunStart(
aggregatedResults,
options)
{
this._status.runStarted(aggregatedResults, options);
}
onTestStart(test) {
this._status.testStarted(test.path, test.context.config);
}
onRunComplete() {
this._status.runFinished();
// $FlowFixMe
process.stdout.write = this._out;
// $FlowFixMe
process.stderr.write = this._err;
clearLine(process.stderr);
}
onTestResult(
test,
testResult,
aggregatedResults)
{
this._status.testFinished(
test.context.config,
testResult,
aggregatedResults);
this._printTestFileSummary(
testResult.testFilePath,
test.context.config,
testResult);
}
_printTestFileSummary(
testPath,
config,
result)
{
if (!result.skipped) {
this.log(getResultHeader(result, config));
const consoleBuffer = result.console;
if (consoleBuffer && consoleBuffer.length) {
this.log(
' ' +
TITLE_BULLET +
'Console\n\n' +
getConsoleOutput(
config.rootDir,
!!this._globalConfig.verbose,
consoleBuffer));
}
if (result.failureMessage) {
this.log(result.failureMessage);
}
}
}}
module.exports = DefaultReporter;

View File

@@ -0,0 +1,83 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const path = require('path');
const util = require('util');
const notifier = require('node-notifier');
const BaseReporter = require('./BaseReporter');
const isDarwin = process.platform === 'darwin';
const icon = path.resolve(__dirname, '../assets/jest_logo.png');
class NotifyReporter extends BaseReporter {
constructor(startRun) {
super();
this._startRun = startRun;
}
onRunComplete(contexts, result) {
const success =
result.numFailedTests === 0 && result.numRuntimeErrorTestSuites === 0;
if (success) {
const title = util.format('%d%% Passed', 100);
const message = util.format(
(isDarwin ? '\u2705 ' : '') + '%d tests passed',
result.numPassedTests);
notifier.notify({ icon, message, title });
} else {
const failed = result.numFailedTests / result.numTotalTests;
const title = util.format(
'%d%% Failed',
Math.ceil(Number.isNaN(failed) ? 0 : failed * 100));
const message = util.format(
(isDarwin ? '\u26D4\uFE0F ' : '') + '%d of %d tests failed',
result.numFailedTests,
result.numTotalTests);
const restartAnswer = 'Run again';
const quitAnswer = 'Exit tests';
notifier.notify(
{
actions: [restartAnswer, quitAnswer],
closeLabel: 'Close',
icon,
message,
title },
(err, _, metadata) => {
if (err || !metadata) {
return;
}
if (metadata.activationValue === quitAnswer) {
process.exit(0);
return;
}
if (metadata.activationValue === restartAnswer) {
this._startRun();
}
});
}
}}
module.exports = NotifyReporter;

View File

@@ -0,0 +1,198 @@
'use strict';
const chalk = require('chalk'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require = require('./utils');const getSummary = _require.getSummary,trimAndFormatPath = _require.trimAndFormatPath,wrapAnsiString = _require.wrapAnsiString;const RUNNING_TEXT = ' RUNS ';const RUNNING = chalk.reset.inverse.yellow.bold(RUNNING_TEXT) + ' '; /**
* This class is a perf optimization for sorting the list of currently
* running tests. It tries to keep tests in the same positions without
* shifting the whole list.
*/class CurrentTestList {
constructor() {
this._array = [];
}
add(testPath, config) {
const index = this._array.indexOf(null);
const record = { config, testPath };
if (index !== -1) {
this._array[index] = record;
} else {
this._array.push(record);
}
}
delete(testPath) {
const record = this._array.find(
record => record && record.testPath === testPath);
this._array[this._array.indexOf(record || null)] = null;
}
get() {
return this._array;
}}
/**
* A class that generates the CLI status of currently running tests
* and also provides an ANSI escape sequence to remove status lines
* from the terminal.
*/
class Status {
constructor() {
this._cache = null;
this._currentTests = new CurrentTestList();
this._done = false;
this._emitScheduled = false;
this._estimatedTime = 0;
this._height = 0;
this._showStatus = false;
}
onChange(callback) {
this._callback = callback;
}
runStarted(
aggregatedResults,
options)
{
this._estimatedTime = options && options.estimatedTime || 0;
this._showStatus = options && options.showStatus;
this._interval = setInterval(() => this._tick(), 1000);
this._aggregatedResults = aggregatedResults;
this._debouncedEmit();
}
runFinished() {
this._done = true;
clearInterval(this._interval);
this._emit();
}
testStarted(testPath, config) {
this._currentTests.add(testPath, config);
if (!this._showStatus) {
this._emit();
} else {
this._debouncedEmit();
}
}
testFinished(
config,
testResult,
aggregatedResults)
{const
testFilePath = testResult.testFilePath;
this._aggregatedResults = aggregatedResults;
this._currentTests.delete(testFilePath);
this._debouncedEmit();
}
get() {
if (this._cache) {
return this._cache;
}
if (this._done) {
return { clear: '', content: '' };
}
// $FlowFixMe
const width = process.stdout.columns;
let content = '\n';
this._currentTests.get().forEach(record => {
if (record) {const
config = record.config,testPath = record.testPath;
content +=
wrapAnsiString(
RUNNING +
trimAndFormatPath(
RUNNING_TEXT.length + 1,
config,
testPath,
width),
width) +
'\n';
}
});
if (this._showStatus && this._aggregatedResults) {
content +=
'\n' +
getSummary(this._aggregatedResults, {
estimatedTime: this._estimatedTime,
roundTime: true,
width });
}
let height = 0;
for (let i = 0; i < content.length; i++) {
if (content[i] === '\n') {
height++;
}
}
const clear = '\r\x1B[K\r\x1B[1A'.repeat(height);
return this._cache = { clear, content };
}
_emit() {
this._cache = null;
this._lastUpdated = Date.now();
this._callback();
}
_debouncedEmit() {
if (!this._emitScheduled) {
// Perf optimization to avoid two separate renders When
// one test finishes and another test starts executing.
this._emitScheduled = true;
setTimeout(() => {
this._emit();
this._emitScheduled = false;
}, 100);
}
}
_tick() {
this._debouncedEmit();
}}
module.exports = Status;

View File

@@ -0,0 +1,281 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const chalk = require('chalk');
const BaseReporter = require('./BaseReporter');var _require =
require('./utils');const getSummary = _require.getSummary,pluralize = _require.pluralize;
const getResultHeader = require('./getResultHeader');
const ARROW = ' \u203A ';
const FAIL_COLOR = chalk.bold.red;
const SNAPSHOT_ADDED = chalk.bold.green;
const SNAPSHOT_NOTE = chalk.dim;
const SNAPSHOT_REMOVED = chalk.bold.red;
const SNAPSHOT_SUMMARY = chalk.bold;
const SNAPSHOT_UPDATED = chalk.bold.green;
const TEST_SUMMARY_THRESHOLD = 20;
const NPM_EVENTS = new Set([
'prepublish',
'publish',
'postpublish',
'preinstall',
'install',
'postinstall',
'preuninstall',
'uninstall',
'postuninstall',
'preversion',
'version',
'postversion',
'pretest',
'test',
'posttest',
'prestop',
'stop',
'poststop',
'prestart',
'start',
'poststart',
'prerestart',
'restart',
'postrestart']);
class SummaryReporter extends BaseReporter {
constructor(globalConfig, options) {
super(globalConfig);
this._globalConfig = globalConfig;
this._estimatedTime = 0;
this._options = options;
}
// If we write more than one character at a time it is possible that
// Node.js exits in the middle of printing the result. This was first observed
// in Node.js 0.10 and still persists in Node.js 6.7+.
// Let's print the test failure summary character by character which is safer
// when hundreds of tests are failing.
_write(string) {
for (let i = 0; i < string.length; i++) {
process.stderr.write(string.charAt(i));
}
}
onRunStart(
aggregatedResults,
options)
{
super.onRunStart(aggregatedResults, options);
this._estimatedTime = options.estimatedTime;
}
onRunComplete(contexts, aggregatedResults) {const
numTotalTestSuites = aggregatedResults.numTotalTestSuites,testResults = aggregatedResults.testResults,wasInterrupted = aggregatedResults.wasInterrupted;
if (numTotalTestSuites) {
const lastResult = testResults[testResults.length - 1];
// Print a newline if the last test did not fail to line up newlines
// similar to when an error would have been thrown in the test.
if (
!this._globalConfig.verbose &&
lastResult &&
!lastResult.numFailingTests &&
!lastResult.testExecError)
{
this.log('');
}
this._printSummary(aggregatedResults, this._globalConfig);
this._printSnapshotSummary(
aggregatedResults.snapshot,
this._globalConfig);
if (numTotalTestSuites) {
const testSummary = wasInterrupted ?
chalk.bold.red('Test run was interrupted.') :
this._getTestSummary(
contexts,
this._options.pattern,
this._options.testNamePattern,
this._options.testPathPattern);
this.log(
getSummary(aggregatedResults, {
estimatedTime: this._estimatedTime }) +
'\n' +
testSummary);
}
}
}
_printSnapshotSummary(
snapshots,
globalConfig)
{
if (
snapshots.added ||
snapshots.filesRemoved ||
snapshots.unchecked ||
snapshots.unmatched ||
snapshots.updated)
{
let updateCommand;
const event = process.env.npm_lifecycle_event;
const prefix = NPM_EVENTS.has(event) ? '' : 'run ';
const client = typeof process.env.npm_config_user_agent === 'string' &&
process.env.npm_config_user_agent.match('yarn') !== null ?
'yarn' :
'npm';
if (globalConfig.watch) {
updateCommand = 'press `u`';
} else if (event) {
updateCommand = `run with \`${client + ' ' + prefix + event} -- -u\``;
} else {
updateCommand = 're-run with `-u`';
}
this.log(SNAPSHOT_SUMMARY('Snapshot Summary'));
if (snapshots.added) {
this.log(
SNAPSHOT_ADDED(ARROW + pluralize('snapshot', snapshots.added)) +
` written in ${pluralize('test suite', snapshots.filesAdded)}.`);
}
if (snapshots.unmatched) {
this.log(
FAIL_COLOR(ARROW + pluralize('snapshot test', snapshots.unmatched)) +
` failed in ` +
`${pluralize('test suite', snapshots.filesUnmatched)}. ` +
SNAPSHOT_NOTE(
'Inspect your code changes or ' +
updateCommand +
' to update them.'));
}
if (snapshots.updated) {
this.log(
SNAPSHOT_UPDATED(ARROW + pluralize('snapshot', snapshots.updated)) +
` updated in ${pluralize('test suite', snapshots.filesUpdated)}.`);
}
if (snapshots.filesRemoved) {
this.log(
SNAPSHOT_REMOVED(
ARROW + pluralize('obsolete snapshot file', snapshots.filesRemoved)) + (
snapshots.didUpdate ?
' removed.' :
' found, ' +
updateCommand +
' to remove ' + (
snapshots.filesRemoved === 1 ? 'it' : 'them.') +
'.'));
}
if (snapshots.unchecked) {
this.log(
FAIL_COLOR(
ARROW + pluralize('obsolete snapshot', snapshots.unchecked)) + (
snapshots.didUpdate ?
' removed.' :
' found, ' +
updateCommand +
' to remove ' + (
snapshots.filesRemoved === 1 ? 'it' : 'them') +
'.'));
}
this.log(''); // print empty line
}
}
_printSummary(
aggregatedResults,
globalConfig)
{
// If there were any failing tests and there was a large number of tests
// executed, re-print the failing results at the end of execution output.
const failedTests = aggregatedResults.numFailedTests;
const runtimeErrors = aggregatedResults.numRuntimeErrorTestSuites;
if (
failedTests + runtimeErrors > 0 &&
aggregatedResults.numTotalTestSuites > TEST_SUMMARY_THRESHOLD)
{
this.log(chalk.bold('Summary of all failing tests'));
aggregatedResults.testResults.forEach(testResult => {const
failureMessage = testResult.failureMessage;
if (failureMessage) {
this._write(
getResultHeader(testResult, globalConfig) +
'\n' +
failureMessage +
'\n');
}
});
this.log(''); // print empty line
}
}
_getTestSummary(
contexts,
pattern,
testNamePattern,
testPathPattern)
{
const testInfo = pattern.onlyChanged ?
chalk.dim(' related to changed files') :
pattern.input !== '' ? chalk.dim(' matching ') + testPathPattern : '';
const nameInfo = testNamePattern ?
chalk.dim(' with tests matching ') + `"${testNamePattern}"` :
'';
const contextInfo = contexts.size > 1 ?
chalk.dim(' in ') + contexts.size + chalk.dim(' projects') :
'';
return (
chalk.dim('Ran all test suites') +
testInfo +
nameInfo +
contextInfo +
chalk.dim('.'));
}}
module.exports = SummaryReporter;

View File

@@ -0,0 +1,132 @@
'use strict';
const chalk = require('chalk'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/var _require = require('../constants');const ICONS = _require.ICONS;const DefaultReporter = require('./DefaultReporter');class VerboseReporter extends DefaultReporter {constructor(globalConfig) {super(globalConfig);
this._globalConfig = globalConfig;
}
static filterTestResults(testResults) {
return testResults.filter((_ref) => {let status = _ref.status;return status !== 'pending';});
}
static groupTestsBySuites(testResults) {
const root = { suites: [], tests: [], title: '' };
testResults.forEach(testResult => {
let targetSuite = root;
// Find the target suite for this test,
// creating nested suites as necessary.
for (const title of testResult.ancestorTitles) {
let matchingSuite = targetSuite.suites.find(s => s.title === title);
if (!matchingSuite) {
matchingSuite = { suites: [], tests: [], title };
targetSuite.suites.push(matchingSuite);
}
targetSuite = matchingSuite;
}
targetSuite.tests.push(testResult);
});
return root;
}
onTestResult(
test,
result,
aggregatedResults)
{
super.onTestResult(test, result, aggregatedResults);
if (!result.testExecError && !result.skipped) {
this._logTestResults(result.testResults);
}
}
_logTestResults(testResults) {
this._logSuite(VerboseReporter.groupTestsBySuites(testResults), 0);
this._logLine();
}
_logSuite(suite, indentLevel) {
if (suite.title) {
this._logLine(suite.title, indentLevel);
}
this._logTests(suite.tests, indentLevel + 1);
suite.suites.forEach(suite => this._logSuite(suite, indentLevel + 1));
}
_getIcon(status) {
if (status === 'failed') {
return chalk.red(ICONS.failed);
} else if (status === 'pending') {
return chalk.yellow(ICONS.pending);
} else {
return chalk.green(ICONS.success);
}
}
_logTest(test, indentLevel) {
const status = this._getIcon(test.status);
const time = test.duration ? ` (${test.duration.toFixed(0)}ms)` : '';
this._logLine(status + ' ' + chalk.dim(test.title + time), indentLevel);
}
_logTests(tests, indentLevel) {
if (this._globalConfig.expand) {
tests.forEach(test => this._logTest(test, indentLevel));
} else {
const skippedCount = tests.reduce((result, test) => {
if (test.status === 'pending') {
result += 1;
} else {
this._logTest(test, indentLevel);
}
return result;
}, 0);
if (skippedCount > 0) {
this._logSkippedTests(skippedCount, indentLevel);
}
}
}
_logSkippedTests(count, indentLevel) {
const icon = this._getIcon('pending');
const text = chalk.dim(`skipped ${count} test${count === 1 ? '' : 's'}`);
this._logLine(`${icon} ${text}`, indentLevel);
}
_logLine(str, indentLevel) {
const indentation = ' '.repeat(indentLevel || 0);
this.log(indentation + (str || ''));
}}
module.exports = VerboseReporter;

View File

@@ -0,0 +1,44 @@
'use strict';
const path = require('path'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/const chalk = require('chalk');module.exports = (root, verbose, buffer) => {const TITLE_INDENT = verbose ? ' ' : ' ';const CONSOLE_INDENT = TITLE_INDENT + ' ';return buffer.reduce((output, _ref) => {let type = _ref.type,message = _ref.message,origin = _ref.origin;origin = path.relative(root, origin);
message = message.split(/\n/).map(line => CONSOLE_INDENT + line).join('\n');
let typeMessage = 'console.' + type;
if (type === 'warn') {
message = chalk.yellow(message);
typeMessage = chalk.yellow(typeMessage);
} else if (type === 'error') {
message = chalk.red(message);
typeMessage = chalk.red(typeMessage);
}
return (
output +
TITLE_INDENT +
chalk.dim(typeMessage) +
' ' +
chalk.dim(origin) +
'\n' +
message +
'\n');
}, '');
};

View File

@@ -0,0 +1,47 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const chalk = require('chalk');var _require =
require('./utils');const formatTestPath = _require.formatTestPath;
const LONG_TEST_COLOR = chalk.reset.bold.bgRed;
// Explicitly reset for these messages since they can get written out in the
// middle of error logging
const FAIL = chalk.reset.inverse.bold.red(' FAIL ');
const PASS = chalk.reset.inverse.bold.green(' PASS ');
module.exports = (result, config) => {
const testPath = result.testFilePath;
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) {
testDetail.push(LONG_TEST_COLOR(runTime + 's'));
}
if (result.memoryUsage) {
const toMB = bytes => Math.floor(bytes / 1024 / 1024);
testDetail.push(`${toMB(result.memoryUsage)} MB heap size`);
}
return (
`${status} ${formatTestPath(config, testPath)}` + (
testDetail.length ? ` (${testDetail.join(', ')})` : ''));
};

View File

@@ -0,0 +1,239 @@
'use strict';var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}(); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const path = require('path');
const chalk = require('chalk');
const slash = require('slash');
const PROGRESS_BAR_WIDTH = 40;
const trimAndFormatPath = (
pad,
config,
testPath,
columns) =>
{
const maxLength = columns - pad;
const relative = relativePath(config, testPath);const
basename = relative.basename;let
dirname = relative.dirname;
// length is ok
if ((dirname + path.sep + basename).length <= maxLength) {
return slash(chalk.dim(dirname + path.sep) + chalk.bold(basename));
}
// we can fit trimmed dirname and full basename
const basenameLength = basename.length;
if (basenameLength + 4 < maxLength) {
const dirnameLength = maxLength - 4 - basenameLength;
dirname =
'...' + dirname.slice(dirname.length - dirnameLength, dirname.length);
return slash(chalk.dim(dirname + path.sep) + chalk.bold(basename));
}
if (basenameLength + 4 === maxLength) {
return slash(chalk.dim('...' + path.sep) + chalk.bold(basename));
}
// can't fit dirname, but can fit trimmed basename
return slash(
chalk.bold(
'...' + basename.slice(basename.length - maxLength - 4, basename.length)));
};
const formatTestPath = (config, testPath) => {var _relativePath =
relativePath(config, testPath);const dirname = _relativePath.dirname,basename = _relativePath.basename;
return chalk.dim(dirname + path.sep) + chalk.bold(basename);
};
const relativePath = (config, testPath) => {
testPath = path.relative(config.rootDir, testPath);
const dirname = path.dirname(testPath);
const basename = path.basename(testPath);
return { basename, dirname };
};
const pluralize = (word, count) =>
`${count} ${word}${count === 1 ? '' : 's'}`;
const getSummary = (
aggregatedResults,
options) =>
{
let runTime = (Date.now() - aggregatedResults.startTime) / 1000;
if (options && options.roundTime) {
runTime = Math.floor(runTime);
}
const estimatedTime = options && options.estimatedTime || 0;
const snapshotResults = aggregatedResults.snapshot;
const snapshotsAdded = snapshotResults.added;
const snapshotsFailed = snapshotResults.unmatched;
const snapshotsPassed = snapshotResults.matched;
const snapshotsTotal = snapshotResults.total;
const snapshotsUpdated = snapshotResults.updated;
const suitesFailed = aggregatedResults.numFailedTestSuites;
const suitesPassed = aggregatedResults.numPassedTestSuites;
const suitesPending = aggregatedResults.numPendingTestSuites;
const suitesRun = suitesFailed + suitesPassed;
const suitesTotal = aggregatedResults.numTotalTestSuites;
const testsFailed = aggregatedResults.numFailedTests;
const testsPassed = aggregatedResults.numPassedTests;
const testsPending = aggregatedResults.numPendingTests;
const testsTotal = aggregatedResults.numTotalTests;
const width = options && options.width || 0;
const suites =
chalk.bold('Test Suites: ') + (
suitesFailed ? chalk.bold.red(`${suitesFailed} failed`) + ', ' : '') + (
suitesPending ?
chalk.bold.yellow(`${suitesPending} skipped`) + ', ' :
'') + (
suitesPassed ? chalk.bold.green(`${suitesPassed} passed`) + ', ' : '') + (
suitesRun !== suitesTotal ?
suitesRun + ' of ' + suitesTotal :
suitesTotal) +
` total`;
const tests =
chalk.bold('Tests: ') + (
testsFailed ? chalk.bold.red(`${testsFailed} failed`) + ', ' : '') + (
testsPending ? chalk.bold.yellow(`${testsPending} skipped`) + ', ' : '') + (
testsPassed ? chalk.bold.green(`${testsPassed} passed`) + ', ' : '') +
`${testsTotal} total`;
const snapshots =
chalk.bold('Snapshots: ') + (
snapshotsFailed ?
chalk.bold.red(`${snapshotsFailed} failed`) + ', ' :
'') + (
snapshotsUpdated ?
chalk.bold.green(`${snapshotsUpdated} updated`) + ', ' :
'') + (
snapshotsAdded ? chalk.bold.green(`${snapshotsAdded} added`) + ', ' : '') + (
snapshotsPassed ?
chalk.bold.green(`${snapshotsPassed} passed`) + ', ' :
'') +
`${snapshotsTotal} total`;
const time = renderTime(runTime, estimatedTime, width);
return [suites, tests, snapshots, time].join('\n');
};
const renderTime = (runTime, estimatedTime, width) => {
// If we are more than one second over the estimated time, highlight it.
const renderedTime = estimatedTime && runTime >= estimatedTime + 1 ?
chalk.bold.yellow(runTime + 's') :
runTime + 's';
let time = chalk.bold(`Time:`) + ` ${renderedTime}`;
if (runTime < estimatedTime) {
time += `, estimated ${estimatedTime}s`;
}
// Only show a progress bar if the test run is actually going to take
// some time.
if (estimatedTime > 2 && runTime < estimatedTime && width) {
const availableWidth = Math.min(PROGRESS_BAR_WIDTH, width);
const length = Math.min(
Math.floor(runTime / estimatedTime * availableWidth),
availableWidth);
if (availableWidth >= 2) {
time +=
'\n' +
chalk.green('█').repeat(length) +
chalk.white('█').repeat(availableWidth - length);
}
}
return time;
};
// word-wrap a string that contains ANSI escape sequences.
// ANSI escape sequences do not add to the string length.
const wrapAnsiString = (string, terminalWidth) => {
if (terminalWidth === 0) {
// if the terminal width is zero, don't bother word-wrapping
return string;
}
const ANSI_REGEXP = /[\u001b\u009b]\[\d{1,2}m/g;
const tokens = [];
let lastIndex = 0;
let match;
while (match = ANSI_REGEXP.exec(string)) {
const ansi = match[0];
const index = match['index'];
if (index != lastIndex) {
tokens.push(['string', string.slice(lastIndex, index)]);
}
tokens.push(['ansi', ansi]);
lastIndex = index + ansi.length;
}
if (lastIndex != string.length - 1) {
tokens.push(['string', string.slice(lastIndex, string.length)]);
}
let lastLineLength = 0;
return tokens.
reduce(
(lines, _ref) => {var _ref2 = _slicedToArray(_ref, 2);let kind = _ref2[0],token = _ref2[1];
if (kind === 'string') {
if (lastLineLength + token.length > terminalWidth) {
while (token.length) {
const chunk = token.slice(0, terminalWidth - lastLineLength);
const remaining = token.slice(
terminalWidth - lastLineLength,
token.length);
lines[lines.length - 1] += chunk;
lastLineLength += chunk.length;
token = remaining;
if (token.length) {
lines.push('');
lastLineLength = 0;
}
}
} else {
lines[lines.length - 1] += token;
lastLineLength += token.length;
}
} else {
lines[lines.length - 1] += token;
}
return lines;
},
['']).
join('\n');
};
module.exports = {
formatTestPath,
getSummary,
pluralize,
relativePath,
trimAndFormatPath,
wrapAnsiString };

View File

@@ -0,0 +1,219 @@
'use strict';function _asyncToGenerator(fn) {return function () {var gen = fn.apply(this, arguments);return new Promise(function (resolve, reject) {function step(key, arg) {try {var info = gen[key](arg);var value = info.value;} catch (error) {reject(error);return;}if (info.done) {resolve(value);} else {return Promise.resolve(value).then(function (value) {step("next", value);}, function (err) {step("throw", err);});}}return step("next");});};} /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const path = require('path');var _require =
require('jest-util');const Console = _require.Console,formatTestResults = _require.formatTestResults;
const chalk = require('chalk');
const fs = require('graceful-fs');
const getMaxWorkers = require('./lib/getMaxWorkers');
const getTestPathPattern = require('./lib/getTestPathPattern');
const SearchSource = require('./SearchSource');
const updateArgv = require('./lib/updateArgv');
const TestRunner = require('./TestRunner');
const TestSequencer = require('./TestSequencer');
const setConfig = (contexts, newConfig) =>
contexts.forEach(
context =>
context.config = Object.freeze(
Object.assign({}, context.config, newConfig)));
const formatTestPathPattern = pattern => {
const testPattern = pattern.testPathPattern;
const input = pattern.input;
const formattedPattern = `/${testPattern || ''}/`;
const formattedInput = pattern.shouldTreatInputAsPattern ?
`/${input || ''}/` :
`"${input || ''}"`;
return input === testPattern ? formattedInput : formattedPattern;
};
const getNoTestsFoundMessage = (testRunData, pattern) => {
if (pattern.onlyChanged) {
return (
chalk.bold(
'No tests found related to files changed since last commit.\n') +
chalk.dim(
pattern.watch ?
'Press `a` to run all tests, or run Jest with `--watchAll`.' :
'Run Jest without `-o` to run all tests.'));
}
const pluralize = (word, count, ending) =>
`${count} ${word}${count === 1 ? '' : ending}`;
const testPathPattern = formatTestPathPattern(pattern);
const individualResults = testRunData.map(testRun => {
const stats = testRun.matches.stats || {};
const config = testRun.context.config;
const statsMessage = Object.keys(stats).
map(key => {
if (key === 'roots' && config.roots.length === 1) {
return null;
}
const value = config[key];
if (value) {
const matches = pluralize('match', stats[key], 'es');
return ` ${key}: ${chalk.yellow(value)} - ${matches}`;
}
return null;
}).
filter(line => line).
join('\n');
return testRun.matches.total ?
`In ${chalk.bold(config.rootDir)}\n` +
` ${pluralize('file', testRun.matches.total || 0, 's')} checked.\n` +
statsMessage :
`No files found in ${config.rootDir}.\n` +
`Make sure Jest's configuration does not exclude this directory.` +
`\nTo set up Jest, make sure a package.json file exists.\n` +
`Jest Documentation: ` +
`facebook.github.io/jest/docs/configuration.html`;
});
return (
chalk.bold('No tests found') +
'\n' +
individualResults.join('\n') +
'\n' +
`Pattern: ${chalk.yellow(testPathPattern)} - 0 matches`);
};
const getTestPaths = (() => {var _ref = _asyncToGenerator(function* (globalConfig, context, pattern, argv, pipe) {
const source = new SearchSource(context);
let data = yield source.getTestPaths(pattern);
if (!data.tests.length) {
if (pattern.onlyChanged && data.noSCM) {
if (globalConfig.watch) {
// Run all the tests
updateArgv(argv, 'watchAll', { noSCM: true });
pattern = getTestPathPattern(argv);
data = yield source.getTestPaths(pattern);
} else {
new Console(pipe, pipe).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.');
}
}
}
return data;
});return function getTestPaths(_x, _x2, _x3, _x4, _x5) {return _ref.apply(this, arguments);};})();
const processResults = (runResults, options) => {
if (options.testResultsProcessor) {
/* $FlowFixMe */
runResults = require(options.testResultsProcessor)(runResults);
}
if (options.isJSON) {
if (options.outputFile) {
const outputFile = path.resolve(process.cwd(), options.outputFile);
fs.writeFileSync(
outputFile,
JSON.stringify(formatTestResults(runResults)));
process.stdout.write(
`Test results written to: ` +
`${path.relative(process.cwd(), outputFile)}\n`);
} else {
process.stdout.write(JSON.stringify(formatTestResults(runResults)));
}
}
return options.onComplete && options.onComplete(runResults);
};
const runJest = (() => {var _ref2 = _asyncToGenerator(function* (
globalConfig,
contexts,
argv,
pipe,
testWatcher,
startRun,
onComplete)
{
const maxWorkers = getMaxWorkers(argv);
const pattern = getTestPathPattern(argv);
const sequencer = new TestSequencer();
let allTests = [];
const testRunData = yield Promise.all(
contexts.map((() => {var _ref3 = _asyncToGenerator(function* (context) {
const matches = yield getTestPaths(
globalConfig,
context,
pattern,
argv,
pipe);
allTests = allTests.concat(matches.tests);
return { context, matches };
});return function (_x13) {return _ref3.apply(this, arguments);};})()));
allTests = sequencer.sort(allTests);
if (argv.listTests) {
console.log(JSON.stringify(allTests.map(function (test) {return test.path;})));
onComplete && onComplete({ success: true });
return null;
}
if (!allTests.length) {
new Console(pipe, pipe).log(getNoTestsFoundMessage(testRunData, pattern));
} else if (
allTests.length === 1 &&
globalConfig.silent !== true &&
globalConfig.verbose !== false)
{
// $FlowFixMe
globalConfig = Object.freeze(
Object.assign({}, globalConfig, { verbose: true }));
}
// When using more than one context, make all printed paths relative to the
// current cwd. rootDir is only used as a token during normalization and
// has no special meaning afterwards except for printing information to the
// CLI.
setConfig(contexts, { rootDir: process.cwd() });
const results = yield new TestRunner(globalConfig, {
maxWorkers,
pattern,
startRun,
testNamePattern: argv.testNamePattern,
testPathPattern: formatTestPathPattern(pattern) }).
runTests(allTests, testWatcher);
sequencer.cacheResults(allTests, results);
return processResults(results, {
isJSON: argv.json,
onComplete,
outputFile: argv.outputFile,
testResultsProcessor: globalConfig.testResultsProcessor });
});return function runJest(_x6, _x7, _x8, _x9, _x10, _x11, _x12) {return _ref2.apply(this, arguments);};})();
module.exports = runJest;

View File

@@ -0,0 +1,121 @@
'use strict'; /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
const fs = require('fs');var _require =
require('jest-util');const Console = _require.Console,NullConsole = _require.NullConsole,setGlobal = _require.setGlobal;var _require2 =
require('jest-config');const getTestEnvironment = _require2.getTestEnvironment;
const docblock = require('jest-docblock');
const BufferedConsole = require('./lib/BufferedConsole');
const getConsoleOutput = require('./reporters/getConsoleOutput');
function runTest(
path,
globalConfig,
config,
resolver)
{
let testSource;
try {
testSource = fs.readFileSync(path, 'utf8');
} catch (e) {
return Promise.reject(e);
}
const parsedDocblock = docblock.parse(docblock.extract(testSource));
const customEnvironment = parsedDocblock['jest-environment'];
let testEnvironment = config.testEnvironment;
if (customEnvironment) {
testEnvironment = getTestEnvironment(
Object.assign({}, config, {
testEnvironment: customEnvironment }));
}
/* $FlowFixMe */
const TestEnvironment = require(testEnvironment);
/* $FlowFixMe */
const testFramework = require(config.testRunner);
/* $FlowFixMe */
const Runtime = require(config.moduleLoader || 'jest-runtime');
const environment = new TestEnvironment(config);
const TestConsole = globalConfig.verbose ?
Console :
globalConfig.silent ? NullConsole : BufferedConsole;
const testConsole = new TestConsole(
globalConfig.useStderr ? process.stderr : process.stdout,
process.stderr,
(type, message) =>
getConsoleOutput(
config.rootDir,
!!globalConfig.verbose,
// 4 = the console call is buried 4 stack frames deep
BufferedConsole.write([], type, message, 4)));
const cacheFS = { [path]: testSource };
setGlobal(environment.global, 'console', testConsole);
const runtime = new Runtime(config, environment, resolver, cacheFS, {
collectCoverage: globalConfig.collectCoverage,
collectCoverageFrom: globalConfig.collectCoverageFrom,
collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom,
mapCoverage: globalConfig.mapCoverage });
const start = Date.now();
return testFramework(globalConfig, config, environment, runtime, path).
then(result => {
const testCount =
result.numPassingTests +
result.numFailingTests +
result.numPendingTests;
result.perfStats = { end: Date.now(), start };
result.testFilePath = path;
result.coverage = runtime.getAllCoverageInfo();
result.sourceMaps = runtime.getSourceMapInfo();
result.console = testConsole.getBuffer();
result.skipped = testCount === result.numPendingTests;
return result;
}).
then(
result =>
Promise.resolve().then(() => {
environment.dispose();
if (config.logHeapUsage) {
if (global.gc) {
global.gc();
}
result.memoryUsage = process.memoryUsage().heapUsed;
}
// Delay the resolution to allow log messages to be output.
return new Promise(resolve => setImmediate(() => resolve(result)));
}),
err =>
Promise.resolve().then(() => {
environment.dispose();
throw err;
}));
}
module.exports = runTest;

View File

@@ -0,0 +1,325 @@
'use strict';
const ansiEscapes = require('ansi-escapes'); /**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/const chalk = require('chalk');var _require = require('jest-regex-util');const replacePathSepForRegex = _require.replacePathSepForRegex;const HasteMap = require('jest-haste-map');const isCI = require('is-ci');const isValidPath = require('./lib/isValidPath');const preRunMessage = require('./preRunMessage');const createContext = require('./lib/createContext');const runJest = require('./runJest');
const updateArgv = require('./lib/updateArgv');
const SearchSource = require('./SearchSource');
const TestWatcher = require('./TestWatcher');
const Prompt = require('./lib/Prompt');
const TestPathPatternPrompt = require('./TestPathPatternPrompt');
const TestNamePatternPrompt = require('./TestNamePatternPrompt');var _require2 =
require('./constants');const KEYS = _require2.KEYS,CLEAR = _require2.CLEAR;
const isInteractive = process.stdout.isTTY && !isCI;
let hasExitListener = false;
const watch = function (
initialGlobalConfig,
contexts,
argv,
pipe,
hasteMapInstances)
{let stdin = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : process.stdin;
updateArgv(argv, argv.watch ? 'watch' : 'watchAll', {
testNamePattern: argv.testNamePattern,
testPathPattern: argv.testPathPattern || (argv._ || []).join('|') });
const prompt = new Prompt();
const testPathPatternPrompt = new TestPathPatternPrompt(pipe, prompt);
const testNamePatternPrompt = new TestNamePatternPrompt(pipe, prompt);
let searchSources = contexts.map(context => ({
context,
searchSource: new SearchSource(context) }));
let hasSnapshotFailure = false;
let isRunning = false;
let testWatcher;
let shouldDisplayWatchUsage = true;
let isWatchUsageDisplayed = false;
testPathPatternPrompt.updateSearchSources(searchSources);
hasteMapInstances.forEach((hasteMapInstance, index) => {
hasteMapInstance.on('change', (_ref) => {let eventsQueue = _ref.eventsQueue,hasteFS = _ref.hasteFS,moduleMap = _ref.moduleMap;
const validPaths = eventsQueue.filter((_ref2) => {let filePath = _ref2.filePath;
return isValidPath(
initialGlobalConfig,
contexts[index].config,
filePath);
});
if (validPaths.length) {
const context = contexts[index] = createContext(
contexts[index].config,
{
hasteFS,
moduleMap });
prompt.abort();
searchSources = searchSources.slice();
searchSources[index] = {
context,
searchSource: new SearchSource(context) };
testPathPatternPrompt.updateSearchSources(searchSources);
startRun();
}
});
});
if (!hasExitListener) {
hasExitListener = true;
process.on('exit', () => {
if (prompt.isEntering()) {
pipe.write(ansiEscapes.cursorDown());
pipe.write(ansiEscapes.eraseDown);
}
});
}
const startRun = function () {let overrideConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
if (isRunning) {
return null;
}
testWatcher = new TestWatcher({ isWatchMode: true });
isInteractive && pipe.write(CLEAR);
preRunMessage.print(pipe);
isRunning = true;
const globalConfig = Object.freeze(
Object.assign({}, initialGlobalConfig, overrideConfig, {
testNamePattern: argv.testNamePattern,
testPathPattern: argv.testPathPattern }));
return runJest(
// $FlowFixMe
globalConfig,
contexts,
argv,
pipe,
testWatcher,
startRun,
results => {
isRunning = false;
hasSnapshotFailure = !!results.snapshot.failure;
// Create a new testWatcher instance so that re-runs won't be blocked.
// The old instance that was passed to Jest will still be interrupted
// and prevent test runs from the previous run.
testWatcher = new TestWatcher({ isWatchMode: true });
if (shouldDisplayWatchUsage) {
pipe.write(usage(argv, hasSnapshotFailure));
shouldDisplayWatchUsage = false; // hide Watch Usage after first run
isWatchUsageDisplayed = true;
} else {
pipe.write(showToggleUsagePrompt());
shouldDisplayWatchUsage = false;
isWatchUsageDisplayed = false;
}
testNamePatternPrompt.updateCachedTestResults(results.testResults);
}).
catch(error => console.error(chalk.red(error.stack)));
};
const onKeypress = key => {
if (key === KEYS.CONTROL_C || key === KEYS.CONTROL_D) {
process.exit(0);
return;
}
if (prompt.isEntering()) {
prompt.put(key);
return;
}
// Abort test run
if (
isRunning &&
testWatcher &&
[KEYS.Q, KEYS.ENTER, KEYS.A, KEYS.O, KEYS.P, KEYS.T].indexOf(key) !== -1)
{
testWatcher.setState({ interrupted: true });
return;
}
switch (key) {
case KEYS.Q:
process.exit(0);
return;
case KEYS.ENTER:
startRun();
break;
case KEYS.U:
startRun({ updateSnapshot: 'all' });
break;
case KEYS.A:
updateArgv(argv, 'watchAll', {
testNamePattern: '',
testPathPattern: '' });
startRun();
break;
case KEYS.C:
updateArgv(argv, 'watch', {
testNamePattern: '',
testPathPattern: '' });
startRun();
break;
case KEYS.O:
updateArgv(argv, 'watch', {
testNamePattern: '',
testPathPattern: '' });
startRun();
break;
case KEYS.P:
testPathPatternPrompt.run(
testPathPattern => {
updateArgv(argv, 'watch', {
testNamePattern: '',
testPathPattern: replacePathSepForRegex(testPathPattern) });
startRun();
},
onCancelPatternPrompt,
{ header: activeFilters(argv) });
break;
case KEYS.T:
testNamePatternPrompt.run(
testNamePattern => {
updateArgv(argv, 'watch', {
testNamePattern,
testPathPattern: argv.testPathPattern });
startRun();
},
onCancelPatternPrompt,
{ header: activeFilters(argv) });
break;
case KEYS.QUESTION_MARK:
break;
case KEYS.W:
if (!shouldDisplayWatchUsage && !isWatchUsageDisplayed) {
pipe.write(ansiEscapes.cursorUp());
pipe.write(ansiEscapes.eraseDown);
pipe.write(usage(argv, hasSnapshotFailure));
isWatchUsageDisplayed = true;
shouldDisplayWatchUsage = false;
}
break;}
};
const onCancelPatternPrompt = () => {
pipe.write(ansiEscapes.cursorHide);
pipe.write(ansiEscapes.clearScreen);
pipe.write(usage(argv, hasSnapshotFailure));
pipe.write(ansiEscapes.cursorShow);
};
if (typeof stdin.setRawMode === 'function') {
stdin.setRawMode(true);
stdin.resume();
stdin.setEncoding('hex');
stdin.on('data', onKeypress);
}
startRun();
return Promise.resolve();
};
const activeFilters = function (argv) {let delimiter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '\n';const
testNamePattern = argv.testNamePattern,testPathPattern = argv.testPathPattern;
if (testNamePattern || testPathPattern) {
const filters = [
testPathPattern ?
chalk.dim('filename ') + chalk.yellow('/' + testPathPattern + '/') :
null,
testNamePattern ?
chalk.dim('test name ') + chalk.yellow('/' + testNamePattern + '/') :
null].
filter(f => !!f).
join(', ');
const messages = ['\n' + chalk.bold('Active Filters: ') + filters];
return messages.filter(message => !!message).join(delimiter);
}
return '';
};
const usage = function (argv, snapshotFailure) {let delimiter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '\n';
const messages = [
activeFilters(argv),
argv.testPathPattern || argv.testNamePattern ?
chalk.dim(' \u203A Press ') + 'c' + chalk.dim(' to clear filters.') :
null,
'\n' + chalk.bold('Watch Usage'),
argv.watch ?
chalk.dim(' \u203A Press ') + 'a' + chalk.dim(' to run all tests.') :
null,
(argv.watchAll || argv.testPathPattern || argv.testNamePattern) &&
!argv.noSCM ?
chalk.dim(' \u203A Press ') +
'o' +
chalk.dim(' to only run tests related to changed files.') :
null,
snapshotFailure ?
chalk.dim(' \u203A Press ') +
'u' +
chalk.dim(' to update failing snapshots.') :
null,
chalk.dim(' \u203A Press ') +
'p' +
chalk.dim(' to filter by a filename regex pattern.'),
chalk.dim(' \u203A Press ') +
't' +
chalk.dim(' to filter by a test name regex pattern.'),
chalk.dim(' \u203A Press ') + 'q' + chalk.dim(' to quit watch mode.'),
chalk.dim(' \u203A Press ') +
'Enter' +
chalk.dim(' to trigger a test run.')];
return messages.filter(message => !!message).join(delimiter) + '\n';
};
const showToggleUsagePrompt = () =>
'\n' +
chalk.bold('Watch Usage: ') +
chalk.dim('Press ') +
'w' +
chalk.dim(' to show more.');
module.exports = watch;

View File

@@ -0,0 +1,107 @@
{
"_args": [
[
"jest-cli@20.0.4",
"C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\torrent-project"
]
],
"_from": "jest-cli@20.0.4",
"_id": "jest-cli@20.0.4",
"_inBundle": false,
"_integrity": "sha1-5TKxnYiuW8bEF+iwWTpv6VSx3JM=",
"_location": "/react-scripts/jest/jest-cli",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "jest-cli@20.0.4",
"name": "jest-cli",
"escapedName": "jest-cli",
"rawSpec": "20.0.4",
"saveSpec": null,
"fetchSpec": "20.0.4"
},
"_requiredBy": [
"/react-scripts/jest"
],
"_resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-20.0.4.tgz",
"_spec": "20.0.4",
"_where": "C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\torrent-project",
"bin": {
"jest": "./bin/jest.js"
},
"bugs": {
"url": "https://github.com/facebook/jest/issues"
},
"dependencies": {
"ansi-escapes": "^1.4.0",
"callsites": "^2.0.0",
"chalk": "^1.1.3",
"graceful-fs": "^4.1.11",
"is-ci": "^1.0.10",
"istanbul-api": "^1.1.1",
"istanbul-lib-coverage": "^1.0.1",
"istanbul-lib-instrument": "^1.4.2",
"istanbul-lib-source-maps": "^1.1.0",
"jest-changed-files": "^20.0.3",
"jest-config": "^20.0.4",
"jest-docblock": "^20.0.3",
"jest-environment-jsdom": "^20.0.3",
"jest-haste-map": "^20.0.4",
"jest-jasmine2": "^20.0.4",
"jest-message-util": "^20.0.3",
"jest-regex-util": "^20.0.3",
"jest-resolve-dependencies": "^20.0.3",
"jest-runtime": "^20.0.4",
"jest-snapshot": "^20.0.3",
"jest-util": "^20.0.3",
"micromatch": "^2.3.11",
"node-notifier": "^5.0.2",
"pify": "^2.3.0",
"slash": "^1.0.0",
"string-length": "^1.0.1",
"throat": "^3.0.0",
"which": "^1.2.12",
"worker-farm": "^1.3.1",
"yargs": "^7.0.2"
},
"description": "Delightful JavaScript Testing.",
"engines": {
"node": ">= 4"
},
"homepage": "http://facebook.github.io/jest/",
"keywords": [
"ava",
"babel",
"coverage",
"easy",
"expect",
"facebook",
"immersive",
"instant",
"jasmine",
"jest",
"jsdom",
"mocha",
"mocking",
"painless",
"qunit",
"runner",
"sandboxed",
"snapshot",
"tap",
"tape",
"test",
"testing",
"typescript",
"watch"
],
"license": "BSD-3-Clause",
"main": "build/jest.js",
"name": "jest-cli",
"repository": {
"type": "git",
"url": "git+https://github.com/facebook/jest.git"
},
"version": "20.0.4"
}