UNPKG

orionsoft-react-scripts

Version:

Orionsoft Configuration and scripts for Create React App.

456 lines (402 loc) 12.9 kB
/** * 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 realFs = require('fs'); const fs = require('graceful-fs'); fs.gracefulify(realFs); const Runtime = require('jest-runtime'); const SearchSource = require('./SearchSource'); const TestRunner = require('./TestRunner');var _require = require('jest-util');const Console = _require.Console;const clearLine = _require.clearLine;var _require2 = require('./cli');const run = _require2.run; const ansiEscapes = require('ansi-escapes'); const chalk = require('chalk'); const formatTestResults = require('./lib/formatTestResults'); const os = require('os'); const path = require('path'); const preRunMessage = require('./preRunMessage'); const readConfig = require('jest-config').readConfig; const sane = require('sane'); const which = require('which'); const TestWatcher = require('./TestWatcher'); const CLEAR = '\x1B[2J\x1B[H'; const VERSION = require('../package.json').version; const WATCHER_DEBOUNCE = 200; const WATCHMAN_BIN = 'watchman'; const KEYS = { A: '61', BACKSPACE: process.platform === 'win32' ? '08' : '7f', CONTROL_C: '03', CONTROL_D: '04', ENTER: '0d', ESCAPE: '1b', O: '6f', P: '70', Q: '71', U: '75' }; 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); } }; const buildTestPathPatternInfo = argv => { const defaultPattern = { input: '', testPathPattern: '', shouldTreatInputAsPattern: false }; const validatePattern = patternInfo => {const testPathPattern = patternInfo.testPathPattern; if (testPathPattern) { try { /* eslint-disable no-new */ new RegExp(testPathPattern); /* eslint-enable no-new */ } catch (error) { clearLine(process.stdout); console.log(chalk.red( 'Invalid testPattern ' + String(testPathPattern) + ' supplied. ' + 'Running all tests instead.')); return defaultPattern; } } return patternInfo; }; if (argv.onlyChanged) { return { input: '', lastCommit: argv.lastCommit, onlyChanged: true, watch: argv.watch }; } if (argv.testPathPattern) { return validatePattern({ input: argv.testPathPattern, testPathPattern: argv.testPathPattern, shouldTreatInputAsPattern: true }); } if (argv._ && argv._.length) { return validatePattern({ input: argv._.join(' '), findRelatedTests: argv.findRelatedTests, paths: argv._, testPathPattern: argv._.join('|'), shouldTreatInputAsPattern: false }); } return defaultPattern; }; const getTestSummary = ( argv, patternInfo) => { const testPathPattern = SearchSource.getTestPathPattern(patternInfo); const testInfo = patternInfo.onlyChanged ? chalk.dim(' related to changed files') : patternInfo.input !== '' ? chalk.dim(' matching ') + testPathPattern : ''; const nameInfo = argv.testNamePattern ? chalk.dim(' with tests matching ') + `"${ argv.testNamePattern }"` : ''; return ( chalk.dim('Ran all test suites') + testInfo + nameInfo + chalk.dim('.')); }; const getWatcher = ( config, packageRoot, callback, options) => { which(WATCHMAN_BIN, (err, resolvedPath) => { const watchman = !err && options.useWatchman && resolvedPath; const glob = config.moduleFileExtensions.map(ext => '**/*' + ext); const watcher = sane(packageRoot, { glob, watchman }); callback(watcher); }); }; const runJest = (config, argv, pipe, testWatcher, onComplete) => { const maxWorkers = getMaxWorkers(argv); const localConsole = new Console(pipe, pipe); let patternInfo = buildTestPathPatternInfo(argv); return Runtime.createHasteContext(config, { console: localConsole, maxWorkers }). then(hasteMap => { const source = new SearchSource(hasteMap, config); return source.getTestPaths(patternInfo). then(data => { if (!data.paths.length) { if (patternInfo.onlyChanged && data.noSCM) { if (config.watch) { // Run all the tests setWatchMode(argv, 'watchAll', { noSCM: true }); patternInfo = buildTestPathPatternInfo(argv); return source.getTestPaths(patternInfo); } else { localConsole.log( 'Jest can only find uncommitted changed files in a git or hg ' + 'repository. If you make your project a git or hg repository ' + '(`git init` or `hg init`), Jest will be able to only ' + 'run tests related to files changed since the last commit.'); } } localConsole.log( source.getNoTestsFoundMessage(patternInfo, config, data)); } return data; }).then(data => { if (data.paths.length === 1 && config.verbose !== false) { config = Object.assign({}, config, { verbose: true }); } return new TestRunner( hasteMap, config, { maxWorkers, getTestSummary: () => getTestSummary(argv, patternInfo) }). runTests(data.paths, testWatcher); }). then(runResults => { if (config.testResultsProcessor) { /* $FlowFixMe */ const processor = require(config.testResultsProcessor); processor(runResults); } if (argv.json) { if (argv.jsonOutputFile) { const outputFile = path.resolve(process.cwd(), argv.jsonOutputFile); fs.writeFileSync( outputFile, JSON.stringify(formatTestResults(runResults, config))); process.stdout.write( `Test results written to: ` + `${ path.relative(process.cwd(), outputFile) }\n`); } else { process.stdout.write( JSON.stringify(formatTestResults(runResults, config))); } } return onComplete && onComplete(runResults); }).catch(error => { throw error; }); }); }; const setWatchMode = (argv, mode, options) => { if (mode === 'watch') { argv.watch = true; argv.watchAll = false; } else if (mode === 'watchAll') { argv.watch = false; argv.watchAll = true; } // Reset before setting these to the new values argv._ = options && options.pattern || ''; argv.onlyChanged = false; argv.onlyChanged = buildTestPathPatternInfo(argv).input === '' && !argv.watchAll; if (options && options.noSCM) { argv.noSCM = true; } }; const runCLI = ( argv, root, onComplete) => { const pipe = argv.json ? process.stderr : process.stdout; argv = argv || {}; if (argv.version) { pipe.write(`v${ VERSION }\n`); onComplete && onComplete(); return; } readConfig(argv, root). then(config => { if (argv.debug) { /* $FlowFixMe */ const testFramework = require(config.testRunner); pipe.write('jest version = ' + VERSION + '\n'); pipe.write('test framework = ' + testFramework.name + '\n'); pipe.write('config = ' + JSON.stringify(config, null, ' ') + '\n'); } if (argv.watch || argv.watchAll) { setWatchMode(argv, argv.watch ? 'watch' : 'watchAll', { pattern: argv._ }); let isRunning = false; let isEnteringPattern = false; let currentPattern = ''; let timer; let testWatcher; const writeCurrentPattern = () => { clearLine(pipe); pipe.write(chalk.dim(' pattern \u203A ') + currentPattern); }; const startRun = function () {let overrideConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (isRunning) { return null; } testWatcher = new TestWatcher({ isWatchMode: true }); pipe.write(CLEAR); preRunMessage.print(pipe); isRunning = true; return runJest( Object.freeze(Object.assign({}, config, overrideConfig)), argv, pipe, testWatcher, results => { isRunning = false; /* eslint-disable max-len */ const messages = [ '\n' + chalk.bold('Watch Usage'), argv.watch ? chalk.dim(' \u203A Press ') + 'a' + chalk.dim(' to run all tests.') : null, (argv.watchAll || argv._) && !argv.noSCM ? chalk.dim(' \u203A Press ') + 'o' + chalk.dim(' to only run tests related to changed files.') : null, results.snapshot.failure ? 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 ') + 'q' + chalk.dim(' to quit watch mode.'), chalk.dim(' \u203A Press ') + 'Enter' + chalk.dim(' to trigger a test run.')]; /* eslint-enable max-len */ console.log(messages.filter(message => !!message).join('\n')); }). then( () => {}, error => console.error(chalk.red(error.stack))); }; const onKeypress = key => { if (key === KEYS.CONTROL_C || key === KEYS.CONTROL_D) { process.exit(0); return; } if (isEnteringPattern) { switch (key) { case KEYS.ENTER: isEnteringPattern = false; setWatchMode(argv, 'watch', { pattern: [currentPattern] }); startRun(); break; case KEYS.ESCAPE: isEnteringPattern = false; pipe.write(ansiEscapes.eraseLines(2)); currentPattern = argv._[0]; break; default: const char = new Buffer(key, 'hex').toString(); currentPattern = key === KEYS.BACKSPACE ? currentPattern.slice(0, -1) : currentPattern + char; writeCurrentPattern(); break;} return; } // Abort test run if ( isRunning && testWatcher && [KEYS.Q, KEYS.ENTER, KEYS.A, KEYS.O, KEYS.P].includes(key)) { testWatcher.setState({ interrupted: true }); return; } switch (key) { case KEYS.Q: process.exit(0); return; case KEYS.ENTER: startRun(); break; case KEYS.U: startRun({ updateSnapshot: true }); break; case KEYS.A: setWatchMode(argv, 'watchAll'); startRun(); break; case KEYS.O: setWatchMode(argv, 'watch'); startRun(); break; case KEYS.P: isEnteringPattern = true; currentPattern = ''; pipe.write('\n'); writeCurrentPattern(); break;} }; const onFileChange = (_, filePath) => { filePath = path.join(root, filePath); const coverageDirectory = config.coverageDirectory || path.resolve(config.rootDir, 'coverage'); const isValidPath = config.testPathDirs.some(dir => filePath.startsWith(dir)) && !filePath.includes(coverageDirectory); if (!isValidPath) { return; } if (timer) { clearTimeout(timer); timer = null; } if (testWatcher && testWatcher.isInterrupted()) { return; } timer = setTimeout(startRun, WATCHER_DEBOUNCE); }; if (typeof process.stdin.setRawMode === 'function') { process.stdin.setRawMode(true); process.stdin.resume(); process.stdin.setEncoding('hex'); process.stdin.on('data', onKeypress); } const callback = watcher => { watcher.on('error', error => { watcher.close(); getWatcher(config, root, callback, { useWatchman: false }); }); watcher.on('all', onFileChange); }; getWatcher(config, root, callback, { useWatchman: true }); startRun(); return Promise.resolve(); } else { preRunMessage.print(pipe); const testWatcher = new TestWatcher({ isWatchMode: false }); return runJest(config, argv, pipe, testWatcher, onComplete); } }). catch(error => { clearLine(process.stderr); clearLine(process.stdout); console.error(chalk.red(error.stack)); process.exit(1); }); }; module.exports = { getVersion: () => VERSION, run, runCLI, SearchSource, TestRunner };