aboutsummaryrefslogtreecommitdiff
path: root/node_modules/ava/lib/run-status.js
blob: 8e095655af05cd93d37a4d1f85e421eab18315dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
'use strict';
const EventEmitter = require('events');
const chalk = require('chalk');
const flatten = require('arr-flatten');
const figures = require('figures');
const autoBind = require('auto-bind');
const prefixTitle = require('./prefix-title');

function sum(arr, key) {
	let result = 0;

	arr.forEach(item => {
		result += item[key];
	});

	return result;
}

class RunStatus extends EventEmitter {
	constructor(opts) {
		super();

		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.remainingCount = 0;
		this.previousFailCount = 0;
		this.knownFailures = [];
		this.errors = [];
		this.stats = [];
		this.tests = [];
		this.failFastEnabled = opts.failFast || false;
		this.updateSnapshots = opts.updateSnapshots || false;

		autoBind(this);
	}
	observeFork(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'));
	}
	handleRejections(data) {
		this.rejectionCount += data.rejections.length;

		data.rejections.forEach(err => {
			err.type = 'rejection';
			err.file = data.file;
			this.emit('error', err, this);
			this.errors.push(err);
		});
	}
	handleExceptions(data) {
		this.exceptionCount++;
		const err = data.exception;
		err.type = 'exception';
		err.file = data.file;
		this.emit('error', err, this);
		this.errors.push(err);
	}
	handleTeardown(data) {
		this.emit('dependencies', data.file, data.dependencies, this);
		this.emit('touchedFiles', data.touchedFiles);
	}
	handleStats(stats) {
		this.emit('stats', stats, this);

		if (stats.hasExclusive) {
			this.hasExclusive = true;
		}

		this.testCount += stats.testCount;
	}
	handleTest(test) {
		test.title = this.prefixTitle(test.file) + test.title;

		if (test.error) {
			this.errors.push(test);
		}

		if (test.failing && !test.error) {
			this.knownFailures.push(test);
		}

		this.emit('test', test, this);
	}
	prefixTitle(file) {
		if (!this.prefixTitles) {
			return '';
		}

		const separator = ' ' + chalk.gray.dim(figures.pointerSmall) + ' ';

		return prefixTitle(file, this.base, separator);
	}
	handleOutput(channel, data) {
		this.emit(channel, data, this);
	}
	processResults(results) {
		// Assemble stats from all tests
		this.stats = results.map(result => result.stats);
		this.tests = results.map(result => 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');
		this.remainingCount = this.testCount - this.passCount - this.failCount - this.skipCount - this.todoCount - this.knownFailureCount;
	}
}

module.exports = RunStatus;