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/concurrent.js
CHANGED
|
@@ -1,96 +1,83 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
const Promise = require('bluebird');
|
|
3
|
+
const isPromise = require('is-promise');
|
|
4
|
+
const autoBind = require('auto-bind');
|
|
5
|
+
const AvaError = require('./ava-error');
|
|
6
|
+
|
|
7
|
+
class Concurrent {
|
|
8
|
+
constructor(tests, bail) {
|
|
9
|
+
if (!Array.isArray(tests)) {
|
|
10
|
+
throw new TypeError('Expected an array of tests');
|
|
11
|
+
}
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
this.results = [];
|
|
14
|
+
this.passed = true;
|
|
15
|
+
this.reason = null;
|
|
16
|
+
this.tests = tests;
|
|
17
|
+
this.bail = bail || false;
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
throw new TypeError('Expected an array of tests');
|
|
19
|
+
autoBind(this);
|
|
17
20
|
}
|
|
21
|
+
run() {
|
|
22
|
+
let results;
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
try {
|
|
25
|
+
results = this.tests.map(this._runTest);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
if (err instanceof AvaError) {
|
|
28
|
+
return this._results();
|
|
29
|
+
}
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
this[key] = this[key].bind(this);
|
|
27
|
-
}, this);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
Concurrent.prototype.run = function () {
|
|
31
|
-
var results;
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
results = this.tests.map(this._runTest);
|
|
35
|
-
} catch (err) {
|
|
36
|
-
if (err instanceof AvaError) {
|
|
37
|
-
return this._results();
|
|
31
|
+
throw err;
|
|
38
32
|
}
|
|
39
33
|
|
|
40
|
-
|
|
41
|
-
}
|
|
34
|
+
const isAsync = results.some(isPromise);
|
|
42
35
|
|
|
43
|
-
|
|
36
|
+
if (isAsync) {
|
|
37
|
+
return Promise.all(results)
|
|
38
|
+
.catch(AvaError, () => {})
|
|
39
|
+
.then(this._results);
|
|
40
|
+
}
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
return Promise.all(results)
|
|
47
|
-
.catch(AvaError, noop)
|
|
48
|
-
.then(this._results);
|
|
42
|
+
return this._results();
|
|
49
43
|
}
|
|
44
|
+
_runTest(test, index) {
|
|
45
|
+
const result = test.run();
|
|
50
46
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
Concurrent.prototype._runTest = function (test, index) {
|
|
55
|
-
var result = test.run();
|
|
56
|
-
|
|
57
|
-
if (isPromise(result)) {
|
|
58
|
-
var self = this;
|
|
47
|
+
if (isPromise(result)) {
|
|
48
|
+
return result.then(result => this._addResult(result, index));
|
|
49
|
+
}
|
|
59
50
|
|
|
60
|
-
return
|
|
61
|
-
return self._addResult(result, index);
|
|
62
|
-
});
|
|
51
|
+
return this._addResult(result, index);
|
|
63
52
|
}
|
|
53
|
+
_addResult(result, index) {
|
|
54
|
+
// Always save result when not in bail mode or all previous tests pass
|
|
55
|
+
if ((this.bail && this.passed) || !this.bail) {
|
|
56
|
+
this.results[index] = result;
|
|
57
|
+
}
|
|
64
58
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Concurrent.prototype._addResult = function (result, index) {
|
|
69
|
-
// always save result when not in bail mode or all previous tests pass
|
|
70
|
-
if ((this.bail && this.passed) || !this.bail) {
|
|
71
|
-
this.results[index] = result;
|
|
72
|
-
}
|
|
59
|
+
if (result.passed === false) {
|
|
60
|
+
this.passed = false;
|
|
73
61
|
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
// Only set reason once
|
|
63
|
+
if (!this.reason) {
|
|
64
|
+
this.reason = result.reason;
|
|
65
|
+
}
|
|
76
66
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
67
|
+
if (this.bail) {
|
|
68
|
+
throw new AvaError('Error in Concurrent while in bail mode');
|
|
69
|
+
}
|
|
80
70
|
}
|
|
81
71
|
|
|
82
|
-
|
|
83
|
-
throw new AvaError('Error in Concurrent while in bail mode');
|
|
84
|
-
}
|
|
72
|
+
return result;
|
|
85
73
|
}
|
|
74
|
+
_results() {
|
|
75
|
+
return {
|
|
76
|
+
passed: this.passed,
|
|
77
|
+
reason: this.reason,
|
|
78
|
+
result: this.results
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
86
82
|
|
|
87
|
-
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
Concurrent.prototype._results = function () {
|
|
91
|
-
return {
|
|
92
|
-
passed: this.passed,
|
|
93
|
-
reason: this.reason,
|
|
94
|
-
result: this.results
|
|
95
|
-
};
|
|
96
|
-
};
|
|
83
|
+
module.exports = Concurrent;
|
package/lib/enhance-assert.js
CHANGED
|
@@ -1,68 +1,76 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
const dotProp = require('dot-prop');
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
// When adding patterns, don't forget to add to
|
|
5
|
+
// https://github.com/avajs/babel-preset-transform-test-files/blob/master/espower-patterns.json
|
|
6
|
+
// Then release a new version of that preset and bump the SemVer range here.
|
|
7
|
+
const PATTERNS = [
|
|
7
8
|
't.truthy(value, [message])',
|
|
8
9
|
't.falsy(value, [message])',
|
|
9
10
|
't.true(value, [message])',
|
|
10
11
|
't.false(value, [message])',
|
|
11
|
-
't.is(value, expected, [message])',
|
|
12
|
-
't.not(value, expected, [message])',
|
|
13
|
-
't.deepEqual(value, expected, [message])',
|
|
14
|
-
't.notDeepEqual(value, expected, [message])',
|
|
15
12
|
't.regex(contents, regex, [message])',
|
|
16
|
-
't.notRegex(contents, regex, [message])'
|
|
17
|
-
// deprecated apis
|
|
18
|
-
't.ok(value, [message])',
|
|
19
|
-
't.notOk(value, [message])',
|
|
20
|
-
't.same(value, expected, [message])',
|
|
21
|
-
't.notSame(value, expected, [message])'
|
|
13
|
+
't.notRegex(contents, regex, [message])'
|
|
22
14
|
];
|
|
23
15
|
|
|
24
|
-
|
|
16
|
+
const NON_ENHANCED_PATTERNS = [
|
|
25
17
|
't.pass([message])',
|
|
26
18
|
't.fail([message])',
|
|
27
19
|
't.throws(fn, [message])',
|
|
28
20
|
't.notThrows(fn, [message])',
|
|
29
|
-
't.ifError(error, [message])'
|
|
21
|
+
't.ifError(error, [message])',
|
|
22
|
+
't.snapshot(contents, [message])',
|
|
23
|
+
't.is(value, expected, [message])',
|
|
24
|
+
't.not(value, expected, [message])',
|
|
25
|
+
't.deepEqual(value, expected, [message])',
|
|
26
|
+
't.notDeepEqual(value, expected, [message])'
|
|
30
27
|
];
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
opts.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
wrapOnlyPatterns: module.exports.NON_ENHANCED_PATTERNS,
|
|
43
|
-
bindReceiver: false
|
|
44
|
-
}
|
|
45
|
-
);
|
|
29
|
+
const enhanceAssert = opts => {
|
|
30
|
+
const empower = require('empower-core');
|
|
31
|
+
const enhanced = empower(opts.assert, {
|
|
32
|
+
destructive: false,
|
|
33
|
+
onError: opts.onError,
|
|
34
|
+
onSuccess: opts.onSuccess,
|
|
35
|
+
patterns: PATTERNS,
|
|
36
|
+
wrapOnlyPatterns: NON_ENHANCED_PATTERNS,
|
|
37
|
+
bindReceiver: false
|
|
38
|
+
});
|
|
46
39
|
|
|
47
40
|
return enhanced;
|
|
48
|
-
}
|
|
41
|
+
};
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
const isRangeMatch = (a, b) => {
|
|
44
|
+
return (a[0] === b[0] && a[1] === b[1]) ||
|
|
45
|
+
(a[0] > b[0] && a[0] < b[1]) ||
|
|
46
|
+
(a[1] > b[0] && a[1] < b[1]);
|
|
47
|
+
};
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
49
|
+
const computeStatement = (tokens, range) => {
|
|
50
|
+
return tokens
|
|
51
|
+
.filter(token => isRangeMatch(token.range, range))
|
|
52
|
+
.map(token => token.value === undefined ? token.type.label : token.value)
|
|
53
|
+
.join('');
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const getNode = (ast, path) => dotProp.get(ast, path.replace(/\//g, '.'));
|
|
57
|
+
|
|
58
|
+
const formatter = () => {
|
|
59
|
+
return context => {
|
|
60
|
+
const ast = JSON.parse(context.source.ast);
|
|
61
|
+
const tokens = JSON.parse(context.source.tokens);
|
|
62
|
+
const args = context.args[0].events;
|
|
63
|
+
|
|
64
|
+
return args
|
|
65
|
+
.map(arg => {
|
|
66
|
+
const range = getNode(ast, arg.espath).range;
|
|
67
|
+
return [computeStatement(tokens, range), arg.value];
|
|
68
|
+
})
|
|
69
|
+
.reverse();
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
module.exports = enhanceAssert;
|
|
74
|
+
module.exports.PATTERNS = PATTERNS;
|
|
75
|
+
module.exports.NON_ENHANCED_PATTERNS = NON_ENHANCED_PATTERNS;
|
|
76
|
+
module.exports.formatter = formatter;
|
package/lib/fork.js
CHANGED
|
@@ -1,39 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var AvaError = require('./ava-error');
|
|
9
|
-
var doSend = require('./send');
|
|
2
|
+
const childProcess = require('child_process');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const Promise = require('bluebird');
|
|
6
|
+
const debug = require('debug')('ava');
|
|
7
|
+
const AvaError = require('./ava-error');
|
|
10
8
|
|
|
11
9
|
if (fs.realpathSync(__filename) !== __filename) {
|
|
12
|
-
console.warn(
|
|
13
|
-
'WARNING: `npm link ava` and the `--preserve-symlink` flag are incompatible. ' +
|
|
14
|
-
'We have detected that AVA is linked via `npm link`, and that you are using either ' +
|
|
15
|
-
'an early version of Node 6, or the `--preserve-symlink` flag. This breaks AVA. ' +
|
|
16
|
-
'You should upgrade to Node 6.2.0+, avoid the `--preserve-symlink` flag, or avoid using `npm link ava`.'
|
|
17
|
-
);
|
|
10
|
+
console.warn('WARNING: `npm link ava` and the `--preserve-symlink` flag are incompatible. We have detected that AVA is linked via `npm link`, and that you are using either an early version of Node 6, or the `--preserve-symlink` flag. This breaks AVA. You should upgrade to Node 6.2.0+, avoid the `--preserve-symlink` flag, or avoid using `npm link ava`.');
|
|
18
11
|
}
|
|
19
12
|
|
|
20
|
-
|
|
13
|
+
let env = process.env;
|
|
21
14
|
|
|
22
|
-
//
|
|
15
|
+
// Ensure NODE_PATH paths are absolute
|
|
23
16
|
if (env.NODE_PATH) {
|
|
24
|
-
env =
|
|
17
|
+
env = Object.assign({}, env);
|
|
25
18
|
|
|
26
19
|
env.NODE_PATH = env.NODE_PATH
|
|
27
20
|
.split(path.delimiter)
|
|
28
|
-
.map(
|
|
29
|
-
return path.resolve(x);
|
|
30
|
-
})
|
|
21
|
+
.map(x => path.resolve(x))
|
|
31
22
|
.join(path.delimiter);
|
|
32
23
|
}
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
25
|
+
// In case the test file imports a different AVA install,
|
|
26
|
+
// the presence of this variable allows it to require this one instead
|
|
27
|
+
env.AVA_PATH = path.resolve(__dirname, '..');
|
|
28
|
+
|
|
29
|
+
module.exports = (file, opts, execArgv) => {
|
|
30
|
+
opts = Object.assign({
|
|
31
|
+
file,
|
|
37
32
|
baseDir: process.cwd(),
|
|
38
33
|
tty: process.stdout.isTTY ? {
|
|
39
34
|
columns: process.stdout.columns,
|
|
@@ -41,37 +36,44 @@ module.exports = function (file, opts) {
|
|
|
41
36
|
} : false
|
|
42
37
|
}, opts);
|
|
43
38
|
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
const args = [JSON.stringify(opts), opts.color ? '--color' : '--no-color'];
|
|
40
|
+
|
|
41
|
+
const ps = childProcess.fork(path.join(__dirname, 'test-worker.js'), args, {
|
|
42
|
+
cwd: opts.projectDir,
|
|
46
43
|
silent: true,
|
|
47
|
-
env
|
|
44
|
+
env,
|
|
45
|
+
execArgv: execArgv || process.execArgv
|
|
48
46
|
});
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
const relFile = path.relative('.', file);
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
let exiting = false;
|
|
51
|
+
const send = (name, data) => {
|
|
54
52
|
if (!exiting) {
|
|
55
53
|
// This seems to trigger a Node bug which kills the AVA master process, at
|
|
56
54
|
// least while running AVA's tests. See
|
|
57
55
|
// <https://github.com/novemberborn/_ava-tap-crash> for more details.
|
|
58
|
-
|
|
56
|
+
ps.send({
|
|
57
|
+
name: `ava-${name}`,
|
|
58
|
+
data,
|
|
59
|
+
ava: true
|
|
60
|
+
});
|
|
59
61
|
}
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
const testResults = [];
|
|
65
|
+
let results;
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
const promise = new Promise((resolve, reject) => {
|
|
66
68
|
ps.on('error', reject);
|
|
67
69
|
|
|
68
|
-
//
|
|
69
|
-
ps.on('message',
|
|
70
|
+
// Emit `test` and `stats` events
|
|
71
|
+
ps.on('message', event => {
|
|
70
72
|
if (!event.ava) {
|
|
71
73
|
return;
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
event.name = event.name.replace(/^ava
|
|
76
|
+
event.name = event.name.replace(/^ava-/, '');
|
|
75
77
|
event.data.file = relFile;
|
|
76
78
|
|
|
77
79
|
debug('ipc %s:\n%o', event.name, event.data);
|
|
@@ -79,36 +81,36 @@ module.exports = function (file, opts) {
|
|
|
79
81
|
ps.emit(event.name, event.data);
|
|
80
82
|
});
|
|
81
83
|
|
|
82
|
-
ps.on('test',
|
|
84
|
+
ps.on('test', props => {
|
|
83
85
|
testResults.push(props);
|
|
84
86
|
});
|
|
85
87
|
|
|
86
|
-
ps.on('results',
|
|
88
|
+
ps.on('results', data => {
|
|
87
89
|
results = data;
|
|
88
90
|
data.tests = testResults;
|
|
89
|
-
send(
|
|
91
|
+
send('teardown');
|
|
90
92
|
});
|
|
91
93
|
|
|
92
|
-
ps.on('exit',
|
|
94
|
+
ps.on('exit', (code, signal) => {
|
|
93
95
|
if (code > 0) {
|
|
94
|
-
return reject(new AvaError(relFile
|
|
96
|
+
return reject(new AvaError(`${relFile} exited with a non-zero exit code: ${code}`));
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
if (code === null && signal) {
|
|
98
|
-
return reject(new AvaError(relFile
|
|
100
|
+
return reject(new AvaError(`${relFile} exited due to ${signal}`));
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
if (results) {
|
|
102
104
|
resolve(results);
|
|
103
105
|
} else {
|
|
104
|
-
reject(new AvaError(
|
|
106
|
+
reject(new AvaError(`Test results were not received from ${relFile}`));
|
|
105
107
|
}
|
|
106
108
|
});
|
|
107
109
|
|
|
108
|
-
ps.on('no-tests',
|
|
109
|
-
send(
|
|
110
|
+
ps.on('no-tests', data => {
|
|
111
|
+
send('teardown');
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
let message = `No tests found in ${relFile}`;
|
|
112
114
|
|
|
113
115
|
if (!data.avaRequired) {
|
|
114
116
|
message += ', make sure to import "ava" at the top of your test file';
|
|
@@ -118,58 +120,55 @@ module.exports = function (file, opts) {
|
|
|
118
120
|
});
|
|
119
121
|
});
|
|
120
122
|
|
|
121
|
-
//
|
|
122
|
-
ps.on('teardown',
|
|
123
|
-
send(
|
|
123
|
+
// Teardown finished, now exit
|
|
124
|
+
ps.on('teardown', () => {
|
|
125
|
+
send('exit');
|
|
124
126
|
exiting = true;
|
|
125
127
|
});
|
|
126
128
|
|
|
127
|
-
//
|
|
128
|
-
ps.on('uncaughtException',
|
|
129
|
-
send(
|
|
129
|
+
// Uncaught exception in fork, need to exit
|
|
130
|
+
ps.on('uncaughtException', () => {
|
|
131
|
+
send('teardown');
|
|
130
132
|
});
|
|
131
133
|
|
|
132
|
-
ps.stdout.on('data',
|
|
134
|
+
ps.stdout.on('data', data => {
|
|
133
135
|
ps.emit('stdout', data);
|
|
134
136
|
});
|
|
135
137
|
|
|
136
|
-
ps.stderr.on('data',
|
|
138
|
+
ps.stderr.on('data', data => {
|
|
137
139
|
ps.emit('stderr', data);
|
|
138
140
|
});
|
|
139
141
|
|
|
140
142
|
promise.on = function () {
|
|
141
143
|
ps.on.apply(ps, arguments);
|
|
142
|
-
|
|
143
144
|
return promise;
|
|
144
145
|
};
|
|
145
146
|
|
|
146
|
-
promise.send =
|
|
147
|
-
send(
|
|
148
|
-
|
|
147
|
+
promise.send = (name, data) => {
|
|
148
|
+
send(name, data);
|
|
149
149
|
return promise;
|
|
150
150
|
};
|
|
151
151
|
|
|
152
|
-
promise.exit =
|
|
153
|
-
send(
|
|
154
|
-
|
|
152
|
+
promise.exit = () => {
|
|
153
|
+
send('init-exit');
|
|
155
154
|
return promise;
|
|
156
155
|
};
|
|
157
156
|
|
|
158
|
-
//
|
|
159
|
-
|
|
157
|
+
// Send 'run' event only when fork is listening for it
|
|
158
|
+
let isReady = false;
|
|
160
159
|
|
|
161
|
-
ps.on('stats',
|
|
160
|
+
ps.on('stats', () => {
|
|
162
161
|
isReady = true;
|
|
163
162
|
});
|
|
164
163
|
|
|
165
|
-
promise.run =
|
|
164
|
+
promise.run = options => {
|
|
166
165
|
if (isReady) {
|
|
167
|
-
send(
|
|
166
|
+
send('run', options);
|
|
168
167
|
return promise;
|
|
169
168
|
}
|
|
170
169
|
|
|
171
|
-
ps.on('stats',
|
|
172
|
-
send(
|
|
170
|
+
ps.on('stats', () => {
|
|
171
|
+
send('run', options);
|
|
173
172
|
});
|
|
174
173
|
|
|
175
174
|
return promise;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const indentString = require('indent-string');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const diff = require('diff');
|
|
5
|
+
|
|
6
|
+
const cleanUp = line => {
|
|
7
|
+
if (line[0] === '+') {
|
|
8
|
+
return `${chalk.green('+')} ${line.slice(1)}`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (line[0] === '-') {
|
|
12
|
+
return `${chalk.red('-')} ${line.slice(1)}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (line.match(/@@/)) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (line.match(/\\ No newline/)) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return ` ${line}`;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
module.exports = err => {
|
|
27
|
+
if (err.statements) {
|
|
28
|
+
const statements = JSON.parse(err.statements);
|
|
29
|
+
|
|
30
|
+
return statements
|
|
31
|
+
.map(statement => `${statement[0]}\n${chalk.grey('=>')} ${statement[1]}`)
|
|
32
|
+
.join('\n\n') + '\n';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if ((err.actualType === 'object' || err.actualType === 'array') && err.actualType === err.expectedType) {
|
|
36
|
+
const patch = diff.createPatch('string', err.actual, err.expected);
|
|
37
|
+
const msg = patch
|
|
38
|
+
.split('\n')
|
|
39
|
+
.slice(4)
|
|
40
|
+
.map(cleanUp)
|
|
41
|
+
.filter(Boolean)
|
|
42
|
+
.join('\n');
|
|
43
|
+
|
|
44
|
+
return `Difference:\n\n${msg}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (err.actualType === 'string' && err.expectedType === 'string') {
|
|
48
|
+
const patch = diff.diffChars(err.actual, err.expected);
|
|
49
|
+
const msg = patch
|
|
50
|
+
.map(part => {
|
|
51
|
+
if (part.added) {
|
|
52
|
+
return chalk.bgGreen.black(part.value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (part.removed) {
|
|
56
|
+
return chalk.bgRed.black(part.value);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return part.value;
|
|
60
|
+
})
|
|
61
|
+
.join('');
|
|
62
|
+
|
|
63
|
+
return `Difference:\n\n${msg}\n`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return [
|
|
67
|
+
'Actual:\n',
|
|
68
|
+
`${indentString(err.actual, 2)}\n`,
|
|
69
|
+
'Expected:\n',
|
|
70
|
+
`${indentString(err.expected, 2)}\n`
|
|
71
|
+
].join('\n');
|
|
72
|
+
};
|
package/lib/globals.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// Global objects / functions to be bound before requiring test file, so tests do not interfere
|
|
4
|
-
|
|
5
|
-
var x = module.exports;
|
|
3
|
+
// Global objects / functions to be bound before requiring test file, so tests do not interfere
|
|
6
4
|
|
|
5
|
+
const x = module.exports;
|
|
7
6
|
x.now = Date.now;
|
|
8
|
-
|
|
9
7
|
x.setTimeout = setTimeout;
|
|
10
|
-
|
|
11
8
|
x.clearTimeout = clearTimeout;
|
|
12
|
-
|
|
13
|
-
x.setImmediate = require('set-immediate-shim');
|
|
14
|
-
|
|
9
|
+
x.setImmediate = setImmediate;
|
|
15
10
|
x.options = {};
|
package/lib/hook.js
CHANGED
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
2
|
+
const Test = require('./test');
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
class Hook {
|
|
5
|
+
constructor(title, fn) {
|
|
6
|
+
if (typeof title === 'function') {
|
|
7
|
+
fn = title;
|
|
8
|
+
title = null;
|
|
9
|
+
}
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
throw new TypeError('Class constructor Hook cannot be invoked without \'new\'');
|
|
11
|
+
this.title = title;
|
|
12
|
+
this.fn = fn;
|
|
9
13
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
test(testTitle) {
|
|
15
|
+
const title = this.title || `${this.metadata.type} for "${testTitle}"`;
|
|
16
|
+
const test = new Test(title, this.fn);
|
|
17
|
+
test.metadata = this.metadata;
|
|
18
|
+
return test;
|
|
14
19
|
}
|
|
15
|
-
|
|
16
|
-
this.title = title;
|
|
17
|
-
this.fn = fn;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
var title = this.title || (this.metadata.type + ' for "' + testTitle + '"');
|
|
22
|
-
var test = new Test(title, this.fn);
|
|
23
|
-
|
|
24
|
-
test.metadata = this.metadata;
|
|
25
|
-
|
|
26
|
-
return test;
|
|
27
|
-
};
|
|
22
|
+
module.exports = Hook;
|