1 | 'use strict';
|
2 |
|
3 | var colors = require('colors');
|
4 | var sprintf = require('util').format;
|
5 |
|
6 | function onRun() {
|
7 | if (this.node.skip) {
|
8 | this.state.testsSkipped++;
|
9 |
|
10 | this.out({
|
11 | format: [ '%s▹ %s', this.indent, this.node.description.underline ],
|
12 | colors: [ 'yellow' ]
|
13 | });
|
14 | } else {
|
15 | this.state.testsRun++;
|
16 |
|
17 | this.out('%s▸ %s', this.indent, this.node.description.underline);
|
18 |
|
19 | if (this.config.profile)
|
20 | this.runTime = process.hrTime();
|
21 | }
|
22 | }
|
23 |
|
24 | function writeTimeFrom(out, from, subject) {
|
25 | var diff = process.hrTime(from);
|
26 | out({
|
27 | format: [ '%s ◎ %s took %dms %dμs\n', subject, diff[0], diff[1] ],
|
28 | colors: [ 'italic', 'grey' ]
|
29 | });
|
30 | }
|
31 |
|
32 | function onNodeDone() {
|
33 | this.out('');
|
34 |
|
35 | if (this.config.profile && !this.isEmpty)
|
36 | writeTimeFrom(this.out, this.runTime, 'test');
|
37 | }
|
38 |
|
39 | function onTreeDone() {
|
40 | if (this.config.profile && this.hasChildTests)
|
41 | writeTimeFrom(this.out, this.runTime, 'test node and subtree');
|
42 |
|
43 | if(this.isEmpty && !this.node.skip)
|
44 | this.out({
|
45 | format: [ '%s This test has no content.\n', this.indent ],
|
46 | colors: [ 'yellow', 'italic' ]
|
47 | });
|
48 | }
|
49 |
|
50 | function onChildTest(node) {
|
51 | this.isEmpty = false;
|
52 | this.hasChildTests = true;
|
53 | var writer = new Writer(this.config, this.state, node, this.indentCount + 1);
|
54 | writer.listen();
|
55 | }
|
56 |
|
57 | function onAssertOk(text) {
|
58 | this.isEmpty = false;
|
59 | this.state.assertionsRun++;
|
60 |
|
61 | this.out({
|
62 | format: [ '%s ✔ %s', this.indent, text || 'ok' ],
|
63 | colors: [ 'green' ]
|
64 | });
|
65 | }
|
66 |
|
67 | function onAssertNotOk(text) {
|
68 | this.isEmpty = false;
|
69 | this.state.assertionsRun++;
|
70 | this.state.assertionsFailed++;
|
71 |
|
72 | if (!this.testFailed) {
|
73 | this.testFailed = true;
|
74 | this.state.testsFailed++;
|
75 | }
|
76 |
|
77 | this.out({
|
78 | format: [ '%s ✘ %s', this.indent, text || 'not ok' ],
|
79 | colors: [ 'red', 'bold' ]
|
80 | });
|
81 | }
|
82 |
|
83 | function onComment(args) {
|
84 | this.out({
|
85 | format: ['%s ✳ %s', this.indent, sprintf.apply(null, args)],
|
86 | colors: [ 'grey' ]
|
87 | })
|
88 | }
|
89 |
|
90 | function getIndent(count) {
|
91 | var str = '';
|
92 | for (var i = 0; i < count; i++)
|
93 | str += ' ';
|
94 |
|
95 | return str;
|
96 | }
|
97 |
|
98 | function Writer(config, state, node, indentCount) {
|
99 | this.config = config || {};
|
100 |
|
101 | this.state = state;
|
102 | this.node = node;
|
103 |
|
104 | this.indentCount = indentCount;
|
105 | this.indent = getIndent(indentCount);
|
106 | }
|
107 |
|
108 | Writer.prototype.isEmpty = true;
|
109 |
|
110 | Writer.prototype.listen = function () {
|
111 | this.node.once('run', onRun.bind(this));
|
112 | this.node.once('nodeDone', onNodeDone.bind(this));
|
113 | this.node.once('treeDone', onTreeDone.bind(this));
|
114 | this.node.on('childTest', onChildTest.bind(this));
|
115 | this.node.on('assertOk', onAssertOk.bind(this));
|
116 | this.node.on('assertNotOk', onAssertNotOk.bind(this));
|
117 | this.node.on('comment', onComment.bind(this));
|
118 | };
|
119 |
|
120 | Writer.prototype.out = function (format) {
|
121 | if (arguments.length === 1 && typeof format === 'object') {
|
122 | format = arguments[0].format;
|
123 | var colors = arguments[0].colors;
|
124 | } else if (arguments.length > 1) {
|
125 | format = [];
|
126 | Array.prototype.push.apply(format, arguments);
|
127 | }
|
128 |
|
129 | var str = Array.isArray(format) ? sprintf.apply(null, format) : format;
|
130 |
|
131 | if (colors && !this.config.noColors)
|
132 | str = colors.reduce(function (str, c) { return str[c]; }, str);
|
133 |
|
134 | (this.config.out || console.log)(str);
|
135 | };
|
136 |
|
137 | module.exports = function (runner, config) {
|
138 | var state = {
|
139 | testsRun: 0,
|
140 | assertionsRun: 0,
|
141 | testsFailed: 0,
|
142 | assertionsFailed: 0,
|
143 | testsSkipped: 0
|
144 | };
|
145 |
|
146 | var out = config && config.out || console.log;
|
147 |
|
148 | runner.on('file', function(filePath){
|
149 | out(filePath.cyan);
|
150 | out('');
|
151 | });
|
152 |
|
153 | runner.on('test', function (node) {
|
154 | var writer = new Writer(config, state, node, 0);
|
155 | writer.listen();
|
156 | });
|
157 |
|
158 | runner.on('done', function () {
|
159 | function numStr(num, str) {
|
160 | var format = '%d %s';
|
161 | if (num !== 1) format += 's';
|
162 |
|
163 | return sprintf(format, num, str);
|
164 | }
|
165 |
|
166 | var skippedStr = state.testsSkipped ? sprintf('(%s skipped)', numStr(state.testsSkipped, 'test')).yellow : '';
|
167 |
|
168 | out('# Summary');
|
169 | if (!state.testsFailed && !state.assertionsFailed) {
|
170 | var passStr = sprintf(
|
171 | '✔ Pass: %s, %s',
|
172 | numStr(state.testsRun, 'test'),
|
173 | numStr(state.assertionsRun, 'assertion'));
|
174 |
|
175 | out(' %s %s', passStr.green, skippedStr);
|
176 | } else {
|
177 | out(sprintf(
|
178 | ' ✘ Fail: %s, %s',
|
179 | numStr(state.testsFailed, 'test'),
|
180 | numStr(state.assertionsFailed, 'assertion'))
|
181 | .red.bold);
|
182 |
|
183 | var allRanStr = sprintf(
|
184 | '- %s, %s ran.',
|
185 | numStr(state.testsRun, 'test'),
|
186 | numStr(state.assertionsRun, 'assertion'));
|
187 |
|
188 | out(' %s %s', allRanStr.grey, skippedStr);
|
189 | }
|
190 | });
|
191 | }; |
\ | No newline at end of file |