You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
4.5 KiB
JavaScript
196 lines
4.5 KiB
JavaScript
5 years ago
|
'use strict';
|
||
|
var EventEmitter = require('events').EventEmitter;
|
||
|
var path = require('path');
|
||
|
var util = require('util');
|
||
|
var chalk = require('chalk');
|
||
|
var isObj = require('is-obj');
|
||
|
var flatten = require('arr-flatten');
|
||
|
var figures = require('figures');
|
||
|
var formatter = require('./enhance-assert').formatter();
|
||
|
|
||
|
function RunStatus(opts) {
|
||
|
if (!(this instanceof RunStatus)) {
|
||
|
throw new TypeError('Class constructor RunStatus cannot be invoked without \'new\'');
|
||
|
}
|
||
|
EventEmitter.call(this);
|
||
|
|
||
|
opts = opts || {};
|
||
|
this.prefixTitles = opts.prefixTitles !== false;
|
||
|
this.hasExclusive = Boolean(opts.runOnlyExclusive);
|
||
|
this.base = opts.base || '';
|
||
|
|
||
|
this.rejectionCount = 0;
|
||
|
this.exceptionCount = 0;
|
||
|
this.passCount = 0;
|
||
|
this.knownFailureCount = 0;
|
||
|
this.skipCount = 0;
|
||
|
this.todoCount = 0;
|
||
|
this.failCount = 0;
|
||
|
this.fileCount = 0;
|
||
|
this.testCount = 0;
|
||
|
this.previousFailCount = 0;
|
||
|
this.knownFailures = [];
|
||
|
this.errors = [];
|
||
|
this.stats = [];
|
||
|
this.tests = [];
|
||
|
|
||
|
Object.keys(RunStatus.prototype).forEach(function (key) {
|
||
|
this[key] = this[key].bind(this);
|
||
|
}, this);
|
||
|
}
|
||
|
|
||
|
util.inherits(RunStatus, EventEmitter);
|
||
|
module.exports = RunStatus;
|
||
|
|
||
|
RunStatus.prototype.observeFork = function (emitter) {
|
||
|
emitter
|
||
|
.on('teardown', this.handleTeardown)
|
||
|
.on('stats', this.handleStats)
|
||
|
.on('test', this.handleTest)
|
||
|
.on('unhandledRejections', this.handleRejections)
|
||
|
.on('uncaughtException', this.handleExceptions)
|
||
|
.on('stdout', this.handleOutput.bind(this, 'stdout'))
|
||
|
.on('stderr', this.handleOutput.bind(this, 'stderr'));
|
||
|
};
|
||
|
|
||
|
function normalizeError(err) {
|
||
|
if (!isObj(err)) {
|
||
|
err = {
|
||
|
message: err,
|
||
|
stack: err
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
RunStatus.prototype.handleRejections = function (data) {
|
||
|
this.rejectionCount += data.rejections.length;
|
||
|
|
||
|
data.rejections.forEach(function (err) {
|
||
|
err = normalizeError(err);
|
||
|
err.type = 'rejection';
|
||
|
err.file = data.file;
|
||
|
this.emit('error', err, this);
|
||
|
this.errors.push(err);
|
||
|
}, this);
|
||
|
};
|
||
|
|
||
|
RunStatus.prototype.handleExceptions = function (data) {
|
||
|
this.exceptionCount++;
|
||
|
var err = normalizeError(data.exception);
|
||
|
err.type = 'exception';
|
||
|
err.file = data.file;
|
||
|
this.emit('error', err, this);
|
||
|
this.errors.push(err);
|
||
|
};
|
||
|
|
||
|
RunStatus.prototype.handleTeardown = function (data) {
|
||
|
this.emit('dependencies', data.file, data.dependencies, this);
|
||
|
};
|
||
|
|
||
|
RunStatus.prototype.handleStats = function (stats) {
|
||
|
this.emit('stats', stats, this);
|
||
|
|
||
|
if (this.hasExclusive && !stats.hasExclusive) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!this.hasExclusive && stats.hasExclusive) {
|
||
|
this.hasExclusive = true;
|
||
|
this.testCount = 0;
|
||
|
}
|
||
|
|
||
|
this.testCount += stats.testCount;
|
||
|
};
|
||
|
|
||
|
RunStatus.prototype.handleTest = function (test) {
|
||
|
test.title = this.prefixTitle(test.file) + test.title;
|
||
|
|
||
|
if (test.error) {
|
||
|
if (test.error.powerAssertContext) {
|
||
|
var message = formatter(test.error.powerAssertContext);
|
||
|
|
||
|
if (test.error.originalMessage) {
|
||
|
message = test.error.originalMessage + ' ' + message;
|
||
|
}
|
||
|
|
||
|
test.error.message = message;
|
||
|
}
|
||
|
|
||
|
if (test.error.name !== 'AssertionError') {
|
||
|
test.error.message = 'failed with "' + test.error.message + '"';
|
||
|
}
|
||
|
|
||
|
this.errors.push(test);
|
||
|
}
|
||
|
|
||
|
if (test.failing && !test.error) {
|
||
|
this.knownFailures.push(test);
|
||
|
}
|
||
|
|
||
|
this.emit('test', test, this);
|
||
|
};
|
||
|
|
||
|
RunStatus.prototype.prefixTitle = function (file) {
|
||
|
if (!this.prefixTitles) {
|
||
|
return '';
|
||
|
}
|
||
|
|
||
|
var separator = ' ' + chalk.gray.dim(figures.pointerSmall) + ' ';
|
||
|
|
||
|
var prefix = path.relative('.', file)
|
||
|
.replace(this.base, function (match, offset) {
|
||
|
// only replace this.base if it is found at the start of the path
|
||
|
return offset === 0 ? '' : match;
|
||
|
})
|
||
|
.replace(/\.spec/, '')
|
||
|
.replace(/\.test/, '')
|
||
|
.replace(/test\-/g, '')
|
||
|
.replace(/\.js$/, '')
|
||
|
.split(path.sep)
|
||
|
.filter(function (p) {
|
||
|
return p !== '__tests__';
|
||
|
})
|
||
|
.join(separator);
|
||
|
|
||
|
if (prefix.length > 0) {
|
||
|
prefix += separator;
|
||
|
}
|
||
|
|
||
|
return prefix;
|
||
|
};
|
||
|
|
||
|
RunStatus.prototype.handleOutput = function (channel, data) {
|
||
|
this.emit(channel, data, this);
|
||
|
};
|
||
|
|
||
|
RunStatus.prototype.processResults = function (results) {
|
||
|
// assemble stats from all tests
|
||
|
this.stats = results.map(function (result) {
|
||
|
return result.stats;
|
||
|
});
|
||
|
|
||
|
this.tests = results.map(function (result) {
|
||
|
return result.tests;
|
||
|
});
|
||
|
|
||
|
this.tests = flatten(this.tests);
|
||
|
|
||
|
this.passCount = sum(this.stats, 'passCount');
|
||
|
this.knownFailureCount = sum(this.stats, 'knownFailureCount');
|
||
|
this.skipCount = sum(this.stats, 'skipCount');
|
||
|
this.todoCount = sum(this.stats, 'todoCount');
|
||
|
this.failCount = sum(this.stats, 'failCount');
|
||
|
};
|
||
|
|
||
|
function sum(arr, key) {
|
||
|
var result = 0;
|
||
|
|
||
|
arr.forEach(function (item) {
|
||
|
result += item[key];
|
||
|
});
|
||
|
|
||
|
return result;
|
||
|
}
|