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/lib/run-status.js CHANGED
@@ -1,56 +1,21 @@
1
1
  'use strict';
2
- var EventEmitter = require('events').EventEmitter;
3
- var path = require('path');
4
- var util = require('util');
5
- var chalk = require('chalk');
6
- var isObj = require('is-obj');
7
- var flatten = require('arr-flatten');
8
- var figures = require('figures');
9
-
10
- function RunStatus(opts) {
11
- if (!(this instanceof RunStatus)) {
12
- throw new TypeError('Class constructor RunStatus cannot be invoked without \'new\'');
13
- }
14
- EventEmitter.call(this);
15
-
16
- opts = opts || {};
17
- this.prefixTitles = opts.prefixTitles !== false;
18
- this.hasExclusive = Boolean(opts.runOnlyExclusive);
19
- this.base = opts.base || '';
20
-
21
- this.rejectionCount = 0;
22
- this.exceptionCount = 0;
23
- this.passCount = 0;
24
- this.knownFailureCount = 0;
25
- this.skipCount = 0;
26
- this.todoCount = 0;
27
- this.failCount = 0;
28
- this.fileCount = 0;
29
- this.testCount = 0;
30
- this.previousFailCount = 0;
31
- this.knownFailures = [];
32
- this.errors = [];
33
- this.stats = [];
34
- this.tests = [];
35
-
36
- Object.keys(RunStatus.prototype).forEach(function (key) {
37
- this[key] = this[key].bind(this);
38
- }, this);
39
- }
2
+ const EventEmitter = require('events');
3
+ const chalk = require('chalk');
4
+ const isObj = require('is-obj');
5
+ const flatten = require('arr-flatten');
6
+ const figures = require('figures');
7
+ const autoBind = require('auto-bind');
8
+ const prefixTitle = require('./prefix-title');
40
9
 
41
- util.inherits(RunStatus, EventEmitter);
42
- module.exports = RunStatus;
10
+ function sum(arr, key) {
11
+ let result = 0;
43
12
 
44
- RunStatus.prototype.observeFork = function (emitter) {
45
- emitter
46
- .on('teardown', this.handleTeardown)
47
- .on('stats', this.handleStats)
48
- .on('test', this.handleTest)
49
- .on('unhandledRejections', this.handleRejections)
50
- .on('uncaughtException', this.handleExceptions)
51
- .on('stdout', this.handleOutput.bind(this, 'stdout'))
52
- .on('stderr', this.handleOutput.bind(this, 'stderr'));
53
- };
13
+ arr.forEach(item => {
14
+ result += item[key];
15
+ });
16
+
17
+ return result;
18
+ }
54
19
 
55
20
  function normalizeError(err) {
56
21
  if (!isObj(err)) {
@@ -63,122 +28,115 @@ function normalizeError(err) {
63
28
  return err;
64
29
  }
65
30
 
66
- RunStatus.prototype.handleRejections = function (data) {
67
- this.rejectionCount += data.rejections.length;
68
-
69
- data.rejections.forEach(function (err) {
70
- err = normalizeError(err);
71
- err.type = 'rejection';
31
+ class RunStatus extends EventEmitter {
32
+ constructor(opts) {
33
+ super();
34
+
35
+ opts = opts || {};
36
+ this.prefixTitles = opts.prefixTitles !== false;
37
+ this.hasExclusive = Boolean(opts.runOnlyExclusive);
38
+ this.base = opts.base || '';
39
+ this.rejectionCount = 0;
40
+ this.exceptionCount = 0;
41
+ this.passCount = 0;
42
+ this.knownFailureCount = 0;
43
+ this.skipCount = 0;
44
+ this.todoCount = 0;
45
+ this.failCount = 0;
46
+ this.fileCount = 0;
47
+ this.testCount = 0;
48
+ this.remainingCount = 0;
49
+ this.previousFailCount = 0;
50
+ this.knownFailures = [];
51
+ this.errors = [];
52
+ this.stats = [];
53
+ this.tests = [];
54
+ this.failFastEnabled = opts.failFast || false;
55
+
56
+ autoBind(this);
57
+ }
58
+ observeFork(emitter) {
59
+ emitter
60
+ .on('teardown', this.handleTeardown)
61
+ .on('stats', this.handleStats)
62
+ .on('test', this.handleTest)
63
+ .on('unhandledRejections', this.handleRejections)
64
+ .on('uncaughtException', this.handleExceptions)
65
+ .on('stdout', this.handleOutput.bind(this, 'stdout'))
66
+ .on('stderr', this.handleOutput.bind(this, 'stderr'));
67
+ }
68
+ handleRejections(data) {
69
+ this.rejectionCount += data.rejections.length;
70
+
71
+ data.rejections.forEach(err => {
72
+ err = normalizeError(err);
73
+ err.type = 'rejection';
74
+ err.file = data.file;
75
+ this.emit('error', err, this);
76
+ this.errors.push(err);
77
+ });
78
+ }
79
+ handleExceptions(data) {
80
+ this.exceptionCount++;
81
+ const err = normalizeError(data.exception);
82
+ err.type = 'exception';
72
83
  err.file = data.file;
73
84
  this.emit('error', err, this);
74
85
  this.errors.push(err);
75
- }, this);
76
- };
77
-
78
- RunStatus.prototype.handleExceptions = function (data) {
79
- this.exceptionCount++;
80
- var err = normalizeError(data.exception);
81
- err.type = 'exception';
82
- err.file = data.file;
83
- this.emit('error', err, this);
84
- this.errors.push(err);
85
- };
86
-
87
- RunStatus.prototype.handleTeardown = function (data) {
88
- this.emit('dependencies', data.file, data.dependencies, this);
89
- };
90
-
91
- RunStatus.prototype.handleStats = function (stats) {
92
- this.emit('stats', stats, this);
93
-
94
- if (this.hasExclusive && !stats.hasExclusive) {
95
- return;
96
86
  }
97
-
98
- if (!this.hasExclusive && stats.hasExclusive) {
99
- this.hasExclusive = true;
100
- this.testCount = 0;
87
+ handleTeardown(data) {
88
+ this.emit('dependencies', data.file, data.dependencies, this);
101
89
  }
90
+ handleStats(stats) {
91
+ this.emit('stats', stats, this);
102
92
 
103
- this.testCount += stats.testCount;
104
- };
105
-
106
- RunStatus.prototype.handleTest = function (test) {
107
- test.title = this.prefixTitle(test.file) + test.title;
108
-
109
- if (test.error) {
110
- if (test.error.name !== 'AssertionError') {
111
- test.error.message = 'failed with "' + test.error.message + '"';
93
+ if (stats.hasExclusive) {
94
+ this.hasExclusive = true;
112
95
  }
113
96
 
114
- this.errors.push(test);
97
+ this.testCount += stats.testCount;
115
98
  }
99
+ handleTest(test) {
100
+ test.title = this.prefixTitle(test.file) + test.title;
116
101
 
117
- if (test.failing && !test.error) {
118
- this.knownFailures.push(test);
119
- }
102
+ if (test.error) {
103
+ if (test.error.name !== 'AssertionError') {
104
+ test.error.message = `Error: ${test.error.message}`;
105
+ }
120
106
 
121
- this.emit('test', test, this);
122
- };
107
+ this.errors.push(test);
108
+ }
123
109
 
124
- RunStatus.prototype.prefixTitle = function (file) {
125
- if (!this.prefixTitles) {
126
- return '';
127
- }
110
+ if (test.failing && !test.error) {
111
+ this.knownFailures.push(test);
112
+ }
128
113
 
129
- var separator = ' ' + chalk.gray.dim(figures.pointerSmall) + ' ';
130
-
131
- var prefix = path.relative('.', file)
132
- .replace(this.base, function (match, offset) {
133
- // only replace this.base if it is found at the start of the path
134
- return offset === 0 ? '' : match;
135
- })
136
- .replace(/\.spec/, '')
137
- .replace(/\.test/, '')
138
- .replace(/test\-/g, '')
139
- .replace(/\.js$/, '')
140
- .split(path.sep)
141
- .filter(function (p) {
142
- return p !== '__tests__';
143
- })
144
- .join(separator);
145
-
146
- if (prefix.length > 0) {
147
- prefix += separator;
114
+ this.emit('test', test, this);
148
115
  }
116
+ prefixTitle(file) {
117
+ if (!this.prefixTitles) {
118
+ return '';
119
+ }
149
120
 
150
- return prefix;
151
- };
152
-
153
- RunStatus.prototype.handleOutput = function (channel, data) {
154
- this.emit(channel, data, this);
155
- };
156
-
157
- RunStatus.prototype.processResults = function (results) {
158
- // assemble stats from all tests
159
- this.stats = results.map(function (result) {
160
- return result.stats;
161
- });
162
-
163
- this.tests = results.map(function (result) {
164
- return result.tests;
165
- });
166
-
167
- this.tests = flatten(this.tests);
168
-
169
- this.passCount = sum(this.stats, 'passCount');
170
- this.knownFailureCount = sum(this.stats, 'knownFailureCount');
171
- this.skipCount = sum(this.stats, 'skipCount');
172
- this.todoCount = sum(this.stats, 'todoCount');
173
- this.failCount = sum(this.stats, 'failCount');
174
- };
175
-
176
- function sum(arr, key) {
177
- var result = 0;
178
-
179
- arr.forEach(function (item) {
180
- result += item[key];
181
- });
121
+ const separator = ' ' + chalk.gray.dim(figures.pointerSmall) + ' ';
182
122
 
183
- return result;
123
+ return prefixTitle(file, this.base, separator);
124
+ }
125
+ handleOutput(channel, data) {
126
+ this.emit(channel, data, this);
127
+ }
128
+ processResults(results) {
129
+ // Assemble stats from all tests
130
+ this.stats = results.map(result => result.stats);
131
+ this.tests = results.map(result => result.tests);
132
+ this.tests = flatten(this.tests);
133
+ this.passCount = sum(this.stats, 'passCount');
134
+ this.knownFailureCount = sum(this.stats, 'knownFailureCount');
135
+ this.skipCount = sum(this.stats, 'skipCount');
136
+ this.todoCount = sum(this.stats, 'todoCount');
137
+ this.failCount = sum(this.stats, 'failCount');
138
+ this.remainingCount = this.testCount - this.passCount - this.failCount - this.skipCount - this.todoCount - this.knownFailureCount;
139
+ }
184
140
  }
141
+
142
+ module.exports = RunStatus;
package/lib/runner.js CHANGED
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
- var EventEmitter = require('events').EventEmitter;
3
- var util = require('util');
4
- var Promise = require('bluebird');
5
- var optionChain = require('option-chain');
6
- var matcher = require('matcher');
7
- var TestCollection = require('./test-collection');
2
+ const EventEmitter = require('events');
3
+ const Promise = require('bluebird');
4
+ const optionChain = require('option-chain');
5
+ const matcher = require('matcher');
6
+ const TestCollection = require('./test-collection');
7
+ const validateTest = require('./validate-test');
8
8
 
9
9
  function noop() {}
10
10
 
11
- var chainableMethods = {
11
+ const chainableMethods = {
12
12
  defaults: {
13
13
  type: 'test',
14
14
  serial: false,
@@ -35,32 +35,129 @@ var chainableMethods = {
35
35
  }
36
36
  };
37
37
 
38
- function Runner(options) {
39
- if (!(this instanceof Runner)) {
40
- throw new TypeError('Class constructor Runner cannot be invoked without \'new\'');
38
+ function wrapFunction(fn, args) {
39
+ return function (t) {
40
+ return fn.apply(this, [t].concat(args));
41
+ };
42
+ }
43
+
44
+ class Runner extends EventEmitter {
45
+ constructor(options) {
46
+ super();
47
+
48
+ options = options || {};
49
+
50
+ this.results = [];
51
+ this.tests = new TestCollection();
52
+ this.hasStarted = false;
53
+ this._bail = options.bail;
54
+ this._serial = options.serial;
55
+ this._match = options.match || [];
56
+ this._addTestResult = this._addTestResult.bind(this);
57
+ this._buildStats = this._buildStats.bind(this);
41
58
  }
59
+ _addTest(title, opts, fn, args) {
60
+ if (args) {
61
+ if (fn.title) {
62
+ title = fn.title.apply(fn, [title || ''].concat(args));
63
+ }
42
64
 
43
- EventEmitter.call(this);
65
+ fn = wrapFunction(fn, args);
66
+ }
44
67
 
45
- options = options || {};
68
+ if (opts.type === 'test' && this._match.length > 0) {
69
+ opts.exclusive = title !== null && matcher([title], this._match).length === 1;
70
+ }
46
71
 
47
- this.results = [];
48
- this.tests = new TestCollection();
49
- this.hasStarted = false;
50
- this._bail = options.bail;
51
- this._serial = options.serial;
52
- this._match = options.match || [];
53
- this._addTestResult = this._addTestResult.bind(this);
54
- this._buildStats = this._buildStats.bind(this);
55
- }
72
+ const validationError = validateTest(title, fn, opts);
73
+ if (validationError !== null) {
74
+ throw new TypeError(validationError);
75
+ }
56
76
 
57
- util.inherits(Runner, EventEmitter);
58
- module.exports = Runner;
77
+ if (opts.todo) {
78
+ fn = noop;
79
+ }
80
+
81
+ this.tests.add({
82
+ metadata: opts,
83
+ fn,
84
+ title
85
+ });
86
+ }
87
+ _addTestResult(result) {
88
+ const test = result.result;
89
+ const props = {
90
+ duration: test.duration,
91
+ title: test.title,
92
+ error: result.reason,
93
+ type: test.metadata.type,
94
+ skip: test.metadata.skipped,
95
+ todo: test.metadata.todo,
96
+ failing: test.metadata.failing
97
+ };
98
+
99
+ this.results.push(result);
100
+ this.emit('test', props);
101
+ }
102
+ _buildStats() {
103
+ const stats = {
104
+ testCount: 0,
105
+ skipCount: 0,
106
+ todoCount: 0
107
+ };
108
+
109
+ this.results
110
+ .map(result => {
111
+ return result.result;
112
+ })
113
+ .filter(test => {
114
+ return test.metadata.type === 'test';
115
+ })
116
+ .forEach(test => {
117
+ stats.testCount++;
118
+
119
+ if (test.metadata.skipped) {
120
+ stats.skipCount++;
121
+ }
122
+
123
+ if (test.metadata.todo) {
124
+ stats.todoCount++;
125
+ }
126
+ });
127
+
128
+ stats.failCount = this.results
129
+ .filter(result => {
130
+ return result.passed === false;
131
+ })
132
+ .length;
133
+
134
+ stats.knownFailureCount = this.results
135
+ .filter(result => {
136
+ return result.passed === true && result.result.metadata.failing;
137
+ })
138
+ .length;
139
+
140
+ stats.passCount = stats.testCount - stats.failCount - stats.skipCount - stats.todoCount;
141
+
142
+ return stats;
143
+ }
144
+ run(options) {
145
+ if (options.runOnlyExclusive && !this.tests.hasExclusive) {
146
+ return Promise.resolve(null);
147
+ }
148
+
149
+ this.tests.on('test', this._addTestResult);
150
+
151
+ this.hasStarted = true;
152
+
153
+ return Promise.resolve(this.tests.build(this._bail).run()).then(this._buildStats);
154
+ }
155
+ }
59
156
 
60
157
  optionChain(chainableMethods, function (opts, args) {
61
- var title;
62
- var fn;
63
- var macroArgIndex;
158
+ let title;
159
+ let fn;
160
+ let macroArgIndex;
64
161
 
65
162
  if (this.hasStarted) {
66
163
  throw new Error('All tests and hooks must be declared synchronously in your ' +
@@ -96,115 +193,6 @@ optionChain(chainableMethods, function (opts, args) {
96
193
  }
97
194
  }, Runner.prototype);
98
195
 
99
- function wrapFunction(fn, args) {
100
- return function (t) {
101
- return fn.apply(this, [t].concat(args));
102
- };
103
- }
104
-
105
- Runner.prototype._addTest = function (title, opts, fn, args) {
106
- if (args) {
107
- if (fn.title) {
108
- title = fn.title.apply(fn, [title || ''].concat(args));
109
- }
110
-
111
- fn = wrapFunction(fn, args);
112
- }
113
-
114
- if (opts.type === 'test' && this._match.length > 0) {
115
- opts.exclusive = title !== null && matcher([title], this._match).length === 1;
116
- }
117
-
118
- if (opts.todo) {
119
- if (typeof fn === 'function') {
120
- throw new TypeError('`todo` tests are not allowed to have an implementation. Use `test.skip()` for tests with an implementation.');
121
- }
122
-
123
- fn = noop;
124
-
125
- if (typeof title !== 'string') {
126
- throw new TypeError('`todo` tests require a title');
127
- }
128
- } else if (typeof fn !== 'function') {
129
- throw new TypeError('Expected an implementation. Use `test.todo()` for tests without an implementation.');
130
- }
131
-
132
- this.tests.add({
133
- metadata: opts,
134
- fn: fn,
135
- title: title
136
- });
137
- };
138
-
139
- Runner.prototype._addTestResult = function (result) {
140
- var test = result.result;
141
- var props = {
142
- duration: test.duration,
143
- title: test.title,
144
- error: result.reason,
145
- type: test.metadata.type,
146
- skip: test.metadata.skipped,
147
- todo: test.metadata.todo,
148
- failing: test.metadata.failing
149
- };
150
-
151
- this.results.push(result);
152
- this.emit('test', props);
153
- };
154
-
155
- Runner.prototype._buildStats = function () {
156
- var stats = {
157
- testCount: 0,
158
- skipCount: 0,
159
- todoCount: 0
160
- };
161
-
162
- this.results
163
- .map(function (result) {
164
- return result.result;
165
- })
166
- .filter(function (test) {
167
- return test.metadata.type === 'test';
168
- })
169
- .forEach(function (test) {
170
- stats.testCount++;
171
-
172
- if (test.metadata.skipped) {
173
- stats.skipCount++;
174
- }
175
-
176
- if (test.metadata.todo) {
177
- stats.todoCount++;
178
- }
179
- });
180
-
181
- stats.failCount = this.results
182
- .filter(function (result) {
183
- return result.passed === false;
184
- })
185
- .length;
186
-
187
- stats.knownFailureCount = this.results
188
- .filter(function (result) {
189
- return result.passed === true && result.result.metadata.failing;
190
- })
191
- .length;
192
-
193
- stats.passCount = stats.testCount - stats.failCount - stats.skipCount - stats.todoCount;
194
-
195
- return stats;
196
- };
197
-
198
- Runner.prototype.run = function (options) {
199
- if (options.runOnlyExclusive && !this.tests.hasExclusive) {
200
- return Promise.resolve(null);
201
- }
202
-
203
- this.tests.on('test', this._addTestResult);
204
-
205
- this.hasStarted = true;
206
-
207
- return Promise.resolve(this.tests.build(this._bail).run()).then(this._buildStats);
208
- };
209
-
210
196
  Runner._chainableMethods = chainableMethods.chainableMethods;
197
+
198
+ module.exports = Runner;