UNPKG

4.4 kBJavaScriptView Raw
1'use strict';
2
3var defined = require('defined');
4var createDefaultStream = require('./lib/default_stream');
5var Test = require('./lib/test');
6var createResult = require('./lib/results');
7var through = require('@ljharb/through');
8
9var canEmitExit = typeof process !== 'undefined' && process
10 && typeof process.on === 'function' && process.browser !== true;
11var canExit = typeof process !== 'undefined' && process
12 && typeof process.exit === 'function';
13
14module.exports = (function () {
15 var wait = false;
16 var harness;
17
18 function getHarness(opts) {
19 if (!opts) { opts = {}; }
20 opts.autoclose = !canEmitExit;
21 // this override is here since tests fail via nyc if createHarness is moved upwards
22 // eslint-disable-next-line no-use-before-define
23 if (!harness) { harness = createExitHarness(opts, wait); }
24 return harness;
25 }
26
27 function lazyLoad() {
28 // eslint-disable-next-line no-invalid-this
29 return getHarness().apply(this, arguments);
30 }
31
32 lazyLoad.wait = function () {
33 wait = true;
34 };
35
36 lazyLoad.run = function () {
37 var run = getHarness().run;
38
39 if (run) { run(); }
40 };
41
42 lazyLoad.only = function () {
43 return getHarness().only.apply(this, arguments);
44 };
45
46 lazyLoad.createStream = function (opts) {
47 var options = opts || {};
48 if (!harness) {
49 var output = through();
50 getHarness({ stream: output, objectMode: options.objectMode });
51 return output;
52 }
53 return harness.createStream(options);
54 };
55
56 lazyLoad.onFinish = function () {
57 return getHarness().onFinish.apply(this, arguments);
58 };
59
60 lazyLoad.onFailure = function () {
61 return getHarness().onFailure.apply(this, arguments);
62 };
63
64 lazyLoad.getHarness = getHarness;
65
66 return lazyLoad;
67}());
68
69function createHarness(conf_) {
70 var results = createResult();
71 if (!conf_ || conf_.autoclose !== false) {
72 results.once('done', function () { results.close(); });
73 }
74
75 function test(name, conf, cb) {
76 var t = new Test(name, conf, cb);
77 test._tests.push(t);
78
79 (function inspectCode(st) {
80 st.on('test', function sub(st_) {
81 inspectCode(st_);
82 });
83 st.on('result', function (r) {
84 if (!r.todo && !r.ok && typeof r !== 'string') { test._exitCode = 1; }
85 });
86 }(t));
87
88 results.push(t);
89 return t;
90 }
91 test._results = results;
92
93 test._tests = [];
94
95 test.createStream = function (opts) {
96 return results.createStream(opts);
97 };
98
99 test.onFinish = function (cb) {
100 results.on('done', cb);
101 };
102
103 test.onFailure = function (cb) {
104 results.on('fail', cb);
105 };
106
107 var only = false;
108 test.only = function () {
109 if (only) { throw new Error('there can only be one only test'); }
110 if (conf_.noOnly) { throw new Error('`only` tests are prohibited'); }
111 only = true;
112 var t = test.apply(null, arguments);
113 results.only(t);
114 return t;
115 };
116 test._exitCode = 0;
117
118 test.close = function () { results.close(); };
119
120 return test;
121}
122
123function createExitHarness(conf, wait) {
124 var config = conf || {};
125 var harness = createHarness({
126 autoclose: defined(config.autoclose, false),
127 noOnly: defined(conf.noOnly, defined(process.env.NODE_TAPE_NO_ONLY_TEST, false))
128 });
129 var running = false;
130 var ended = false;
131
132 function run() {
133 if (running) { return; }
134 running = true;
135 var stream = harness.createStream({ objectMode: config.objectMode });
136 var es = stream.pipe(config.stream || createDefaultStream());
137 if (canEmitExit && es) { // in node v0.4, `es` is `undefined`
138 // TODO: use `err` arg?
139 // eslint-disable-next-line no-unused-vars
140 es.on('error', function (err) { harness._exitCode = 1; });
141 }
142 stream.on('end', function () { ended = true; });
143 }
144
145 if (wait) {
146 harness.run = run;
147 } else {
148 run();
149 }
150
151 if (config.exit === false) { return harness; }
152 if (!canEmitExit || !canExit) { return harness; }
153
154 process.on('exit', function (code) {
155 // let the process exit cleanly.
156 if (typeof code === 'number' && code !== 0) {
157 return;
158 }
159
160 if (!ended) {
161 var only = harness._results._only;
162 for (var i = 0; i < harness._tests.length; i++) {
163 var t = harness._tests[i];
164 if (!only || t === only) {
165 t._exit();
166 }
167 }
168 }
169 harness.close();
170
171 process.removeAllListeners('exit'); // necessary for node v0.6
172 process.exit(code || harness._exitCode); // eslint-disable-line no-process-exit
173 });
174
175 return harness;
176}
177
178module.exports.createHarness = createHarness;
179module.exports.Test = Test;
180module.exports.test = module.exports; // tap compat
181module.exports.test.skip = Test.skip;