123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- 'use strict';
- const path = require('path');
- const del = require('del');
- const updateNotifier = require('update-notifier');
- const figures = require('figures');
- const arrify = require('arrify');
- const meow = require('meow');
- const Promise = require('bluebird');
- const isCi = require('is-ci');
- const loadConf = require('./load-config');
- // Bluebird specific
- Promise.longStackTraces();
- function exit(message) {
- console.error(`\n${require('./chalk').get().red(figures.cross)} ${message}`);
- process.exit(1); // eslint-disable-line unicorn/no-process-exit
- }
- exports.run = () => { // eslint-disable-line complexity
- let conf = {};
- let confError = null;
- try {
- conf = loadConf();
- } catch (err) {
- confError = err;
- }
- const cli = meow(`
- Usage
- ava [<file|directory|glob> ...]
- Options
- --watch, -w Re-run tests when tests and source files change
- --match, -m Only run tests with matching title (Can be repeated)
- --update-snapshots, -u Update snapshots
- --fail-fast Stop after first test failure
- --timeout, -T Set global timeout
- --serial, -s Run tests serially
- --concurrency, -c Max number of test files running at the same time (Default: CPU cores)
- --verbose, -v Enable verbose output
- --tap, -t Generate TAP output
- --color Force color output
- --no-color Disable color output
- --reset-cache Reset AVA's compilation cache and exit
- Examples
- ava
- ava test.js test2.js
- ava test-*.js
- ava test
- Default patterns when no arguments:
- test.js test-*.js test/**/*.js **/__tests__/**/*.js **/*.test.js
- `, {
- flags: {
- watch: {
- type: 'boolean',
- alias: 'w'
- },
- match: {
- type: 'string',
- alias: 'm',
- default: conf.match
- },
- 'update-snapshots': {
- type: 'boolean',
- alias: 'u'
- },
- 'fail-fast': {
- type: 'boolean',
- default: conf.failFast
- },
- timeout: {
- type: 'string',
- alias: 'T',
- default: conf.timeout
- },
- serial: {
- type: 'boolean',
- alias: 's',
- default: conf.serial
- },
- concurrency: {
- type: 'string',
- alias: 'c',
- default: conf.concurrency
- },
- verbose: {
- type: 'boolean',
- alias: 'v',
- default: conf.verbose
- },
- tap: {
- type: 'boolean',
- alias: 't',
- default: conf.tap
- },
- color: {
- type: 'boolean',
- default: 'color' in conf ? conf.color : require('supports-color').stdout !== false
- },
- 'reset-cache': {
- type: 'boolean',
- default: false
- },
- '--': {
- type: 'string'
- }
- }
- });
- updateNotifier({pkg: cli.pkg}).notify();
- const chalk = require('./chalk').set({enabled: cli.flags.color});
- if (confError) {
- if (confError.parent) {
- exit(`${confError.message}\n\n${chalk.gray((confError.parent && confError.parent.stack) || confError.parent)}`);
- } else {
- exit(confError.message);
- }
- }
- const {projectDir} = conf;
- if (cli.flags.resetCache) {
- const cacheDir = path.join(projectDir, 'node_modules', '.cache', 'ava');
- del('*', {
- cwd: cacheDir,
- nodir: true
- }).then(() => {
- console.error(`\n${chalk.green(figures.tick)} Removed AVA cache files in ${cacheDir}`);
- process.exit(0); // eslint-disable-line unicorn/no-process-exit
- }, err => {
- exit(`Error removing AVA cache files in ${cacheDir}\n\n${chalk.gray((err && err.stack) || err)}`);
- });
- return;
- }
- if (cli.flags.watch && cli.flags.tap && !conf.tap) {
- exit('The TAP reporter is not available when using watch mode.');
- }
- if (cli.flags.watch && isCi) {
- exit('Watch mode is not available in CI, as it prevents AVA from terminating.');
- }
- if (
- cli.flags.concurrency === '' ||
- (cli.flags.concurrency && (!Number.isInteger(Number.parseFloat(cli.flags.concurrency)) || parseInt(cli.flags.concurrency, 10) < 0))
- ) {
- exit('The --concurrency or -c flag must be provided with a nonnegative integer.');
- }
- if ('source' in conf) {
- exit('The \'source\' option has been renamed. Use \'sources\' instead.');
- }
- const Api = require('../api');
- const VerboseReporter = require('./reporters/verbose');
- const MiniReporter = require('./reporters/mini');
- const TapReporter = require('./reporters/tap');
- const Watcher = require('./watcher');
- const babelPipeline = require('./babel-pipeline');
- const normalizeExtensions = require('./extensions');
- let babelConfig = null;
- try {
- babelConfig = babelPipeline.validate(conf.babel);
- } catch (err) {
- exit(err.message);
- }
- let extensions;
- try {
- extensions = normalizeExtensions(conf.extensions || [], babelConfig);
- } catch (err) {
- exit(err.message);
- }
- // Copy resultant cli.flags into conf for use with Api and elsewhere
- Object.assign(conf, cli.flags);
- const match = arrify(conf.match);
- const api = new Api({
- failFast: conf.failFast,
- failWithoutAssertions: conf.failWithoutAssertions !== false,
- serial: conf.serial,
- require: arrify(conf.require),
- cacheEnabled: conf.cache !== false,
- compileEnhancements: conf.compileEnhancements !== false,
- extensions,
- match,
- babelConfig,
- resolveTestsFrom: cli.input.length === 0 ? projectDir : process.cwd(),
- projectDir,
- timeout: conf.timeout,
- concurrency: conf.concurrency ? parseInt(conf.concurrency, 10) : 0,
- updateSnapshots: conf.updateSnapshots,
- snapshotDir: conf.snapshotDir ? path.resolve(projectDir, conf.snapshotDir) : null,
- color: conf.color,
- workerArgv: cli.flags['--']
- });
- let reporter;
- if (conf.tap && !conf.watch) {
- reporter = new TapReporter({
- reportStream: process.stdout,
- stdStream: process.stderr
- });
- } else if (conf.verbose || isCi) {
- reporter = new VerboseReporter({
- reportStream: process.stdout,
- stdStream: process.stderr,
- watching: conf.watch
- });
- } else {
- reporter = new MiniReporter({
- reportStream: process.stdout,
- stdStream: process.stderr,
- watching: conf.watch
- });
- }
- api.on('run', plan => reporter.startRun(plan));
- const files = cli.input.length ? cli.input : arrify(conf.files);
- if (conf.watch) {
- const watcher = new Watcher(reporter, api, files, arrify(conf.sources));
- watcher.observeStdin(process.stdin);
- } else {
- api.run(files).then(runStatus => {
- process.exitCode = runStatus.suggestExitCode({matching: match.length > 0});
- reporter.endRun();
- });
- }
- };
|