ava 0.16.0 → 0.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api.js +297 -265
- package/cli.js +15 -179
- package/index.js +5 -98
- package/index.js.flow +201 -0
- package/lib/assert.js +87 -53
- package/lib/ava-error.js +4 -8
- package/lib/ava-files.js +282 -0
- package/lib/babel-config.js +35 -73
- package/lib/beautify-stack.js +17 -16
- package/lib/caching-precompiler.js +72 -87
- package/lib/cli.js +181 -0
- package/lib/code-excerpt.js +57 -0
- package/lib/colors.js +6 -2
- package/lib/concurrent.js +62 -75
- package/lib/enhance-assert.js +57 -49
- package/lib/extract-stack.js +10 -0
- package/lib/fork.js +67 -68
- package/lib/format-assert-error.js +72 -0
- package/lib/globals.js +3 -8
- package/lib/hook.js +15 -20
- package/lib/logger.js +59 -82
- package/lib/main.js +90 -0
- package/lib/prefix-title.js +21 -0
- package/lib/process-adapter.js +108 -0
- package/lib/reporters/mini.js +260 -257
- package/lib/reporters/tap.js +80 -85
- package/lib/reporters/verbose.js +142 -115
- package/lib/run-status.js +110 -152
- package/lib/runner.js +125 -137
- package/lib/sequence.js +68 -84
- package/lib/serialize-error.js +68 -4
- package/lib/snapshot-state.js +30 -0
- package/lib/test-collection.js +144 -156
- package/lib/test-worker.js +45 -95
- package/lib/test.js +289 -318
- package/lib/throws-helper.js +9 -9
- package/lib/validate-test.js +48 -0
- package/lib/watcher.js +258 -297
- package/package.json +63 -53
- package/profile.js +68 -55
- package/readme.md +215 -101
- package/types/generated.d.ts +848 -228
- package/types/make.js +54 -23
- package/lib/send.js +0 -16
package/lib/babel-config.js
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var colors = require('./colors');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const figures = require('figures');
|
|
5
|
+
const convertSourceMap = require('convert-source-map');
|
|
6
|
+
const colors = require('./colors');
|
|
8
7
|
|
|
9
8
|
function validate(conf) {
|
|
10
9
|
if (conf === undefined || conf === null) {
|
|
11
10
|
conf = 'default';
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
//
|
|
15
|
-
|
|
13
|
+
// Check for valid babel config shortcuts (can be either `default` or `inherit`)
|
|
14
|
+
const isValidShortcut = conf === 'default' || conf === 'inherit';
|
|
16
15
|
|
|
17
16
|
if (!conf || (typeof conf === 'string' && !isValidShortcut)) {
|
|
18
|
-
|
|
17
|
+
let message = colors.error(figures.cross);
|
|
19
18
|
message += ' Unexpected Babel configuration for AVA. ';
|
|
20
19
|
message += 'See ' + chalk.underline('https://github.com/avajs/ava#es2015-support') + ' for allowed values.';
|
|
21
20
|
|
|
@@ -25,74 +24,35 @@ function validate(conf) {
|
|
|
25
24
|
return conf;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
function lazy(
|
|
29
|
-
|
|
30
|
-
var value;
|
|
27
|
+
function lazy(buildPreset) {
|
|
28
|
+
let preset;
|
|
31
29
|
|
|
32
|
-
return
|
|
33
|
-
if (!
|
|
34
|
-
|
|
35
|
-
value = initFn();
|
|
30
|
+
return babel => {
|
|
31
|
+
if (!preset) {
|
|
32
|
+
preset = buildPreset(babel);
|
|
36
33
|
}
|
|
37
34
|
|
|
38
|
-
return
|
|
35
|
+
return preset;
|
|
39
36
|
};
|
|
40
37
|
}
|
|
41
38
|
|
|
42
|
-
|
|
43
|
-
return [
|
|
44
|
-
require('babel-preset-stage-2'),
|
|
45
|
-
require('babel-preset-es2015')
|
|
46
|
-
];
|
|
47
|
-
});
|
|
39
|
+
const stage4 = lazy(() => require('@ava/babel-preset-stage-4')());
|
|
48
40
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return wrapListener(rewriteBabelRuntimePaths, 'rewrite-runtime', {
|
|
53
|
-
generated: true,
|
|
54
|
-
require: true,
|
|
55
|
-
import: true
|
|
41
|
+
function makeTransformTestFiles(powerAssert) {
|
|
42
|
+
return lazy(babel => {
|
|
43
|
+
return require('@ava/babel-preset-transform-test-files')(babel, {powerAssert});
|
|
56
44
|
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
function rewriteBabelRuntimePaths(path) {
|
|
60
|
-
var isBabelPath = /^babel-runtime[\\\/]?/.test(path.node.value);
|
|
61
|
-
|
|
62
|
-
if (path.isLiteral() && isBabelPath) {
|
|
63
|
-
path.node.value = require.resolve(path.node.value);
|
|
64
|
-
}
|
|
65
45
|
}
|
|
66
46
|
|
|
67
|
-
|
|
68
|
-
var babel = require('babel-core');
|
|
69
|
-
var createEspowerPlugin = require('babel-plugin-espower/create');
|
|
70
|
-
|
|
71
|
-
// initialize power-assert
|
|
72
|
-
return createEspowerPlugin(babel, {
|
|
73
|
-
embedAst: true,
|
|
74
|
-
patterns: require('./enhance-assert').PATTERNS
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
var defaultPlugins = lazy(function () {
|
|
79
|
-
return [
|
|
80
|
-
espowerPlugin(),
|
|
81
|
-
require('babel-plugin-ava-throws-helper'),
|
|
82
|
-
rewritePlugin(),
|
|
83
|
-
require('babel-plugin-transform-runtime')
|
|
84
|
-
];
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
function build(babelConfig, filePath, code) {
|
|
47
|
+
function build(babelConfig, powerAssert, filePath, code) {
|
|
88
48
|
babelConfig = validate(babelConfig);
|
|
89
49
|
|
|
90
|
-
|
|
50
|
+
let options;
|
|
91
51
|
|
|
92
52
|
if (babelConfig === 'default') {
|
|
93
53
|
options = {
|
|
94
54
|
babelrc: false,
|
|
95
|
-
presets:
|
|
55
|
+
presets: [stage4]
|
|
96
56
|
};
|
|
97
57
|
} else if (babelConfig === 'inherit') {
|
|
98
58
|
options = {
|
|
@@ -103,29 +63,31 @@ function build(babelConfig, filePath, code) {
|
|
|
103
63
|
babelrc: false
|
|
104
64
|
};
|
|
105
65
|
|
|
106
|
-
|
|
66
|
+
Object.assign(options, babelConfig);
|
|
107
67
|
}
|
|
108
68
|
|
|
109
|
-
|
|
69
|
+
const sourceMap = getSourceMap(filePath, code);
|
|
110
70
|
|
|
111
|
-
|
|
71
|
+
Object.assign(options, {
|
|
112
72
|
inputSourceMap: sourceMap,
|
|
113
73
|
filename: filePath,
|
|
114
74
|
sourceMaps: true,
|
|
115
75
|
ast: false
|
|
116
76
|
});
|
|
117
77
|
|
|
118
|
-
|
|
78
|
+
if (!options.presets) {
|
|
79
|
+
options.presets = [];
|
|
80
|
+
}
|
|
81
|
+
options.presets.push(makeTransformTestFiles(powerAssert));
|
|
119
82
|
|
|
120
83
|
return options;
|
|
121
84
|
}
|
|
122
85
|
|
|
123
86
|
function getSourceMap(filePath, code) {
|
|
124
|
-
|
|
87
|
+
let sourceMap = convertSourceMap.fromSource(code);
|
|
125
88
|
|
|
126
89
|
if (!sourceMap) {
|
|
127
|
-
|
|
128
|
-
|
|
90
|
+
const dirPath = path.dirname(filePath);
|
|
129
91
|
sourceMap = convertSourceMap.fromMapFileSource(code, dirPath);
|
|
130
92
|
}
|
|
131
93
|
|
|
@@ -137,10 +99,10 @@ function getSourceMap(filePath, code) {
|
|
|
137
99
|
}
|
|
138
100
|
|
|
139
101
|
module.exports = {
|
|
140
|
-
validate
|
|
141
|
-
build
|
|
142
|
-
|
|
143
|
-
require
|
|
144
|
-
require
|
|
102
|
+
validate,
|
|
103
|
+
build,
|
|
104
|
+
presetHashes: [
|
|
105
|
+
require('@ava/babel-preset-stage-4/package-hash'),
|
|
106
|
+
require('@ava/babel-preset-transform-test-files/package-hash')
|
|
145
107
|
]
|
|
146
108
|
};
|
package/lib/beautify-stack.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const StackUtils = require('stack-utils');
|
|
3
|
+
const cleanStack = require('clean-stack');
|
|
4
|
+
const debug = require('debug')('ava');
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// ignore unimportant stack trace lines
|
|
10
|
-
var ignoreStackLines = [];
|
|
6
|
+
// Ignore unimportant stack trace lines
|
|
7
|
+
let ignoreStackLines = [];
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
const avaInternals = /\/ava\/(?:lib\/)?[\w-]+\.js:\d+:\d+\)?$/;
|
|
10
|
+
const avaDependencies = /\/node_modules\/(?:bluebird|empower-core|(?:ava\/node_modules\/)?(?:babel-runtime|core-js))\//;
|
|
14
11
|
|
|
15
12
|
if (!debug.enabled) {
|
|
16
13
|
ignoreStackLines = StackUtils.nodeInternals();
|
|
@@ -18,19 +15,23 @@ if (!debug.enabled) {
|
|
|
18
15
|
ignoreStackLines.push(avaDependencies);
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
const stackUtils = new StackUtils({internals: ignoreStackLines});
|
|
22
19
|
|
|
23
|
-
module.exports =
|
|
20
|
+
module.exports = stack => {
|
|
24
21
|
if (!stack) {
|
|
25
22
|
return '';
|
|
26
23
|
}
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
// Workaround for https://github.com/tapjs/stack-utils/issues/14
|
|
26
|
+
// TODO: fix it in `stack-utils`
|
|
27
|
+
stack = cleanStack(stack);
|
|
28
|
+
|
|
29
|
+
const title = stack.split('\n')[0];
|
|
30
|
+
const lines = stackUtils
|
|
30
31
|
.clean(stack)
|
|
31
32
|
.split('\n')
|
|
32
|
-
.map(
|
|
33
|
+
.map(x => ` ${x}`)
|
|
33
34
|
.join('\n');
|
|
34
35
|
|
|
35
|
-
return title
|
|
36
|
+
return `${title}\n${lines}`;
|
|
36
37
|
};
|
|
@@ -1,96 +1,81 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const convertSourceMap = require('convert-source-map');
|
|
5
|
+
const cachingTransform = require('caching-transform');
|
|
6
|
+
const packageHash = require('package-hash');
|
|
7
|
+
const stripBomBuf = require('strip-bom-buf');
|
|
8
|
+
const autoBind = require('auto-bind');
|
|
9
|
+
const md5Hex = require('md5-hex');
|
|
10
|
+
const babelConfigHelper = require('./babel-config');
|
|
11
|
+
|
|
12
|
+
class CachingPrecompiler {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
autoBind(this);
|
|
15
|
+
|
|
16
|
+
options = options || {};
|
|
17
|
+
|
|
18
|
+
this.babelConfig = babelConfigHelper.validate(options.babel);
|
|
19
|
+
this.cacheDirPath = options.path;
|
|
20
|
+
this.powerAssert = Boolean(options.powerAssert);
|
|
21
|
+
this.fileHashes = {};
|
|
22
|
+
this.transform = this._createTransform();
|
|
14
23
|
}
|
|
24
|
+
precompileFile(filePath) {
|
|
25
|
+
if (!this.fileHashes[filePath]) {
|
|
26
|
+
const source = stripBomBuf(fs.readFileSync(filePath));
|
|
27
|
+
this.transform(source, filePath);
|
|
28
|
+
}
|
|
15
29
|
|
|
16
|
-
|
|
17
|
-
this.cacheDirPath = cacheDirPath;
|
|
18
|
-
this.fileHashes = {};
|
|
19
|
-
|
|
20
|
-
Object.keys(CachingPrecompiler.prototype).forEach(function (name) {
|
|
21
|
-
this[name] = this[name].bind(this);
|
|
22
|
-
}, this);
|
|
23
|
-
|
|
24
|
-
this.transform = this._createTransform();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = CachingPrecompiler;
|
|
28
|
-
|
|
29
|
-
CachingPrecompiler.prototype.precompileFile = function (filePath) {
|
|
30
|
-
if (!this.fileHashes[filePath]) {
|
|
31
|
-
var source = stripBom(fs.readFileSync(filePath));
|
|
32
|
-
|
|
33
|
-
this.transform(source, filePath);
|
|
30
|
+
return this.fileHashes[filePath];
|
|
34
31
|
}
|
|
32
|
+
// Conditionally called by caching-transform when precompiling is required
|
|
33
|
+
_init() {
|
|
34
|
+
this.babel = require('babel-core');
|
|
35
|
+
return this._transform;
|
|
36
|
+
}
|
|
37
|
+
_transform(code, filePath, hash) {
|
|
38
|
+
code = code.toString();
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// conditionally called by caching-transform when precompiling is required
|
|
40
|
-
CachingPrecompiler.prototype._factory = function () {
|
|
41
|
-
this._init();
|
|
42
|
-
|
|
43
|
-
return this._transform;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
CachingPrecompiler.prototype._init = function () {
|
|
47
|
-
this.babel = require('babel-core');
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
CachingPrecompiler.prototype._transform = function (code, filePath, hash) {
|
|
51
|
-
code = code.toString();
|
|
52
|
-
|
|
53
|
-
var options = babelConfigHelper.build(this.babelConfig, filePath, code);
|
|
54
|
-
var result = this.babel.transform(code, options);
|
|
55
|
-
|
|
56
|
-
// save source map
|
|
57
|
-
var mapPath = path.join(this.cacheDirPath, hash + '.js.map');
|
|
58
|
-
fs.writeFileSync(mapPath, JSON.stringify(result.map));
|
|
59
|
-
|
|
60
|
-
// When loading the test file, test workers intercept the require call and
|
|
61
|
-
// load the cached code instead. Libraries like nyc may also be intercepting
|
|
62
|
-
// require calls, however they won't know that different code was loaded.
|
|
63
|
-
// They may then attempt to resolve a source map from the original file
|
|
64
|
-
// location.
|
|
65
|
-
//
|
|
66
|
-
// Add a source map file comment to the cached code. The file path is
|
|
67
|
-
// relative from the directory of the original file to where the source map
|
|
68
|
-
// is cached. This will allow the source map to be resolved.
|
|
69
|
-
var dirPath = path.dirname(filePath);
|
|
70
|
-
var relativeMapPath = path.relative(dirPath, mapPath);
|
|
71
|
-
var comment = convertSourceMap.generateMapFileComment(relativeMapPath);
|
|
72
|
-
|
|
73
|
-
return result.code + '\n' + comment;
|
|
74
|
-
};
|
|
40
|
+
const options = babelConfigHelper.build(this.babelConfig, this.powerAssert, filePath, code);
|
|
41
|
+
const result = this.babel.transform(code, options);
|
|
75
42
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
JSON.stringify(this.babelConfig)
|
|
80
|
-
);
|
|
43
|
+
// Save source map
|
|
44
|
+
const mapPath = path.join(this.cacheDirPath, `${hash}.js.map`);
|
|
45
|
+
fs.writeFileSync(mapPath, JSON.stringify(result.map));
|
|
81
46
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
ext: '.js'
|
|
88
|
-
});
|
|
89
|
-
};
|
|
47
|
+
// Append source map comment to transformed code
|
|
48
|
+
// So that other libraries (like nyc) can find the source map
|
|
49
|
+
const dirPath = path.dirname(filePath);
|
|
50
|
+
const relativeMapPath = path.relative(dirPath, mapPath);
|
|
51
|
+
const comment = convertSourceMap.generateMapFileComment(relativeMapPath);
|
|
90
52
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
53
|
+
return `${result.code}\n${comment}`;
|
|
54
|
+
}
|
|
55
|
+
_createTransform() {
|
|
56
|
+
const salt = packageHash.sync([
|
|
57
|
+
require.resolve('../package.json'),
|
|
58
|
+
require.resolve('babel-core/package.json')
|
|
59
|
+
], {
|
|
60
|
+
babelConfig: this.babelConfig,
|
|
61
|
+
majorNodeVersion: process.version.split('.')[0],
|
|
62
|
+
powerAssert: this.powerAssert,
|
|
63
|
+
presetHashes: babelConfigHelper.presetHashes
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return cachingTransform({
|
|
67
|
+
factory: this._init,
|
|
68
|
+
cacheDir: this.cacheDirPath,
|
|
69
|
+
hash: this._generateHash,
|
|
70
|
+
salt,
|
|
71
|
+
ext: '.js'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
_generateHash(code, filePath, salt) {
|
|
75
|
+
const hash = md5Hex([code, filePath, salt]);
|
|
76
|
+
this.fileHashes[filePath] = hash;
|
|
77
|
+
return hash;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
94
80
|
|
|
95
|
-
|
|
96
|
-
};
|
|
81
|
+
module.exports = CachingPrecompiler;
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const updateNotifier = require('update-notifier');
|
|
4
|
+
const figures = require('figures');
|
|
5
|
+
const arrify = require('arrify');
|
|
6
|
+
const meow = require('meow');
|
|
7
|
+
const Promise = require('bluebird');
|
|
8
|
+
const pkgConf = require('pkg-conf');
|
|
9
|
+
const isCi = require('is-ci');
|
|
10
|
+
const hasFlag = require('has-flag');
|
|
11
|
+
const Api = require('../api');
|
|
12
|
+
const colors = require('./colors');
|
|
13
|
+
const VerboseReporter = require('./reporters/verbose');
|
|
14
|
+
const MiniReporter = require('./reporters/mini');
|
|
15
|
+
const TapReporter = require('./reporters/tap');
|
|
16
|
+
const Logger = require('./logger');
|
|
17
|
+
const Watcher = require('./watcher');
|
|
18
|
+
const babelConfig = require('./babel-config');
|
|
19
|
+
|
|
20
|
+
// Bluebird specific
|
|
21
|
+
Promise.longStackTraces();
|
|
22
|
+
|
|
23
|
+
exports.run = () => {
|
|
24
|
+
const conf = pkgConf.sync('ava');
|
|
25
|
+
|
|
26
|
+
const filepath = pkgConf.filepath(conf);
|
|
27
|
+
const projectDir = filepath === null ? process.cwd() : path.dirname(filepath);
|
|
28
|
+
|
|
29
|
+
const cli = meow(`
|
|
30
|
+
Usage
|
|
31
|
+
ava [<file|directory|glob> ...]
|
|
32
|
+
|
|
33
|
+
Options
|
|
34
|
+
--init Add AVA to your project
|
|
35
|
+
--fail-fast Stop after first test failure
|
|
36
|
+
--serial, -s Run tests serially
|
|
37
|
+
--tap, -t Generate TAP output
|
|
38
|
+
--verbose, -v Enable verbose output
|
|
39
|
+
--no-cache Disable the transpiler cache
|
|
40
|
+
--no-power-assert Disable Power Assert
|
|
41
|
+
--no-color Disable color output
|
|
42
|
+
--match, -m Only run tests with matching title (Can be repeated)
|
|
43
|
+
--watch, -w Re-run tests when tests and source files change
|
|
44
|
+
--timeout, -T Set global timeout
|
|
45
|
+
--concurrency, -c Maximum number of test files running at the same time (EXPERIMENTAL)
|
|
46
|
+
--update-snapshots, -u Update snapshots
|
|
47
|
+
|
|
48
|
+
Examples
|
|
49
|
+
ava
|
|
50
|
+
ava test.js test2.js
|
|
51
|
+
ava test-*.js
|
|
52
|
+
ava test
|
|
53
|
+
ava --init
|
|
54
|
+
ava --init foo.js
|
|
55
|
+
|
|
56
|
+
Default patterns when no arguments:
|
|
57
|
+
test.js test-*.js test/**/*.js **/__tests__/**/*.js **/*.test.js
|
|
58
|
+
`, {
|
|
59
|
+
string: [
|
|
60
|
+
'_',
|
|
61
|
+
'match',
|
|
62
|
+
'timeout',
|
|
63
|
+
'concurrency'
|
|
64
|
+
],
|
|
65
|
+
boolean: [
|
|
66
|
+
'init',
|
|
67
|
+
'fail-fast',
|
|
68
|
+
'serial',
|
|
69
|
+
'tap',
|
|
70
|
+
'verbose',
|
|
71
|
+
'watch',
|
|
72
|
+
'update-snapshots',
|
|
73
|
+
'color'
|
|
74
|
+
],
|
|
75
|
+
default: Object.assign({color: true}, conf),
|
|
76
|
+
alias: {
|
|
77
|
+
t: 'tap',
|
|
78
|
+
v: 'verbose',
|
|
79
|
+
s: 'serial',
|
|
80
|
+
m: 'match',
|
|
81
|
+
w: 'watch',
|
|
82
|
+
T: 'timeout',
|
|
83
|
+
c: 'concurrency',
|
|
84
|
+
u: 'update-snapshots'
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
updateNotifier({pkg: cli.pkg}).notify();
|
|
89
|
+
|
|
90
|
+
if (cli.flags.init) {
|
|
91
|
+
require('ava-init')();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (
|
|
96
|
+
((hasFlag('--watch') || hasFlag('-w')) && (hasFlag('--tap') || hasFlag('-t'))) ||
|
|
97
|
+
(conf.watch && conf.tap)
|
|
98
|
+
) {
|
|
99
|
+
throw new Error(colors.error(figures.cross) + ' The TAP reporter is not available when using watch mode.');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if ((hasFlag('--watch') || hasFlag('-w')) && isCi) {
|
|
103
|
+
throw new Error(colors.error(figures.cross) + ' Watch mode is not available in CI, as it prevents AVA from terminating.');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (hasFlag('--require') || hasFlag('-r')) {
|
|
107
|
+
throw new Error(colors.error(figures.cross) + ' The --require and -r flags are deprecated. Requirements should be configured in package.json - see documentation.');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const api = new Api({
|
|
111
|
+
failFast: cli.flags.failFast,
|
|
112
|
+
serial: cli.flags.serial,
|
|
113
|
+
require: arrify(conf.require),
|
|
114
|
+
cacheEnabled: cli.flags.cache !== false,
|
|
115
|
+
powerAssert: cli.flags.powerAssert !== false,
|
|
116
|
+
explicitTitles: cli.flags.watch,
|
|
117
|
+
match: arrify(cli.flags.match),
|
|
118
|
+
babelConfig: babelConfig.validate(conf.babel),
|
|
119
|
+
resolveTestsFrom: cli.input.length === 0 ? projectDir : process.cwd(),
|
|
120
|
+
projectDir,
|
|
121
|
+
timeout: cli.flags.timeout,
|
|
122
|
+
concurrency: cli.flags.concurrency ? parseInt(cli.flags.concurrency, 10) : 0,
|
|
123
|
+
updateSnapshots: cli.flags.updateSnapshots,
|
|
124
|
+
color: cli.flags.color
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
let reporter;
|
|
128
|
+
|
|
129
|
+
if (cli.flags.tap && !cli.flags.watch) {
|
|
130
|
+
reporter = new TapReporter();
|
|
131
|
+
} else if (cli.flags.verbose || isCi) {
|
|
132
|
+
reporter = new VerboseReporter({color: cli.flags.color});
|
|
133
|
+
} else {
|
|
134
|
+
reporter = new MiniReporter({color: cli.flags.color, watching: cli.flags.watch});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
reporter.api = api;
|
|
138
|
+
const logger = new Logger(reporter);
|
|
139
|
+
|
|
140
|
+
logger.start();
|
|
141
|
+
|
|
142
|
+
api.on('test-run', runStatus => {
|
|
143
|
+
reporter.api = runStatus;
|
|
144
|
+
runStatus.on('test', logger.test);
|
|
145
|
+
runStatus.on('error', logger.unhandledError);
|
|
146
|
+
|
|
147
|
+
runStatus.on('stdout', logger.stdout);
|
|
148
|
+
runStatus.on('stderr', logger.stderr);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const files = cli.input.length ? cli.input : arrify(conf.files);
|
|
152
|
+
|
|
153
|
+
if (cli.flags.watch) {
|
|
154
|
+
try {
|
|
155
|
+
const watcher = new Watcher(logger, api, files, arrify(conf.source));
|
|
156
|
+
watcher.observeStdin(process.stdin);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
if (err.name === 'AvaError') {
|
|
159
|
+
// An AvaError may be thrown if `chokidar` is not installed. Log it nicely.
|
|
160
|
+
console.error(` ${colors.error(figures.cross)} ${err.message}`);
|
|
161
|
+
logger.exit(1);
|
|
162
|
+
} else {
|
|
163
|
+
// Rethrow so it becomes an uncaught exception
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
api.run(files)
|
|
169
|
+
.then(runStatus => {
|
|
170
|
+
logger.finish(runStatus);
|
|
171
|
+
logger.exit(runStatus.failCount > 0 || runStatus.rejectionCount > 0 || runStatus.exceptionCount > 0 ? 1 : 0);
|
|
172
|
+
})
|
|
173
|
+
.catch(err => {
|
|
174
|
+
// Don't swallow exceptions. Note that any expected error should already
|
|
175
|
+
// have been logged.
|
|
176
|
+
setImmediate(() => {
|
|
177
|
+
throw err;
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const equalLength = require('equal-length');
|
|
4
|
+
const codeExcerpt = require('code-excerpt');
|
|
5
|
+
const truncate = require('cli-truncate');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
|
|
8
|
+
const formatLineNumber = (lineNumber, maxLineNumber) =>
|
|
9
|
+
' '.repeat(Math.max(0, String(maxLineNumber).length - String(lineNumber).length)) + lineNumber;
|
|
10
|
+
|
|
11
|
+
module.exports = (source, options) => {
|
|
12
|
+
if (!source.isWithinProject || source.isDependency) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const file = source.file;
|
|
17
|
+
const line = source.line;
|
|
18
|
+
|
|
19
|
+
options = options || {};
|
|
20
|
+
const maxWidth = options.maxWidth || 80;
|
|
21
|
+
|
|
22
|
+
let contents;
|
|
23
|
+
try {
|
|
24
|
+
contents = fs.readFileSync(file, 'utf8');
|
|
25
|
+
} catch (err) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const excerpt = codeExcerpt(contents, line, {around: 1});
|
|
30
|
+
if (!excerpt) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const lines = excerpt.map(item => ({
|
|
35
|
+
line: item.line,
|
|
36
|
+
value: truncate(item.value, maxWidth - String(line).length - 5)
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
const joinedLines = lines.map(line => line.value).join('\n');
|
|
40
|
+
const extendedLines = equalLength(joinedLines).split('\n');
|
|
41
|
+
|
|
42
|
+
return lines
|
|
43
|
+
.map((item, index) => ({
|
|
44
|
+
line: item.line,
|
|
45
|
+
value: extendedLines[index]
|
|
46
|
+
}))
|
|
47
|
+
.map(item => {
|
|
48
|
+
const isErrorSource = item.line === line;
|
|
49
|
+
|
|
50
|
+
const lineNumber = formatLineNumber(item.line, line) + ':';
|
|
51
|
+
const coloredLineNumber = isErrorSource ? lineNumber : chalk.grey(lineNumber);
|
|
52
|
+
const result = ` ${coloredLineNumber} ${item.value}`;
|
|
53
|
+
|
|
54
|
+
return isErrorSource ? chalk.bgRed(result) : result;
|
|
55
|
+
})
|
|
56
|
+
.join('\n');
|
|
57
|
+
};
|
package/lib/colors.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
2
|
+
const chalk = require('chalk');
|
|
3
3
|
|
|
4
4
|
module.exports = {
|
|
5
|
+
title: chalk.bold.white,
|
|
5
6
|
error: chalk.red,
|
|
6
7
|
skip: chalk.yellow,
|
|
7
8
|
todo: chalk.blue,
|
|
8
9
|
pass: chalk.green,
|
|
9
10
|
duration: chalk.gray.dim,
|
|
10
|
-
|
|
11
|
+
errorSource: chalk.gray,
|
|
12
|
+
errorStack: chalk.gray,
|
|
13
|
+
stack: chalk.red,
|
|
14
|
+
information: chalk.magenta
|
|
11
15
|
};
|