testem 3.19.0 → 3.19.1
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/api.js +1 -1
- package/lib/app.js +42 -49
- package/lib/browser_launcher.js +5 -6
- package/lib/config.js +57 -44
- package/lib/launcher.js +7 -11
- package/lib/log.js +92 -0
- package/lib/process-ctl.js +4 -4
- package/lib/reporters/dev/index.js +2 -1
- package/lib/reporters/dev/split_log_panel.js +1 -1
- package/lib/runners/browser_test_runner.js +12 -7
- package/lib/runners/hook_runner.js +13 -11
- package/lib/runners/process_test_runner.js +4 -5
- package/lib/runners/tap_process_test_runner.js +5 -6
- package/lib/runners/to-result.js +1 -1
- package/lib/server/index.js +31 -30
- package/lib/tap_consumer.js +1 -1
- package/lib/utils/browser-args.js +1 -1
- package/lib/utils/esbuild-browser-polyfills.js +46 -0
- package/lib/utils/esbuild-buffer-inject.js +6 -0
- package/lib/utils/fileutils.js +4 -4
- package/lib/utils/known-browsers.js +12 -11
- package/lib/utils/process.js +3 -4
- package/lib/utils/promises.js +130 -0
- package/lib/utils/report-file.js +1 -3
- package/lib/utils/reporter.js +3 -3
- package/lib/utils/run-timeout.js +4 -4
- package/lib/utils/signal-listeners.js +9 -7
- package/package.json +11 -12
package/lib/api.js
CHANGED
package/lib/app.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
const EventEmitter = require('events').EventEmitter;
|
|
4
|
-
const
|
|
4
|
+
const { fromCallback, using, disposer, mapLimit } = require('./utils/promises');
|
|
5
5
|
const Path = require('path');
|
|
6
|
-
const log = require('
|
|
6
|
+
const log = require('./log');
|
|
7
7
|
const StyledString = require('styled_string');
|
|
8
8
|
const _ = require('lodash');
|
|
9
9
|
|
|
@@ -64,16 +64,16 @@ module.exports = class App extends EventEmitter {
|
|
|
64
64
|
start(cb) {
|
|
65
65
|
log.info('Starting ' + this.config.appMode);
|
|
66
66
|
|
|
67
|
-
return
|
|
67
|
+
return using(SignalListeners.with(), signalListeners => {
|
|
68
68
|
signalListeners.on('signal', err => this.exit(err));
|
|
69
69
|
|
|
70
|
-
return
|
|
70
|
+
return using(Reporter.with(this, this.stdoutStream, this.reportFileName), reporter => {
|
|
71
71
|
this.reporter = reporter;
|
|
72
72
|
|
|
73
|
-
return
|
|
74
|
-
return
|
|
75
|
-
return
|
|
76
|
-
return
|
|
73
|
+
return using(this.fileWatch(), () => {
|
|
74
|
+
return using(this.getServer(), () => {
|
|
75
|
+
return using(this.getRunners(), () => {
|
|
76
|
+
return using(this.runHook('on_start'), () => {
|
|
77
77
|
let w = this.waitForTests();
|
|
78
78
|
|
|
79
79
|
if (cb) {
|
|
@@ -86,15 +86,15 @@ module.exports = class App extends EventEmitter {
|
|
|
86
86
|
|
|
87
87
|
this.emit('tests-finish');
|
|
88
88
|
|
|
89
|
-
return
|
|
89
|
+
return using(this.runHook('on_exit'), () => {});
|
|
90
90
|
}).catch(error => {
|
|
91
91
|
log.error(error);
|
|
92
92
|
log.info('Stopping ' + this.config.appMode);
|
|
93
93
|
|
|
94
94
|
this.emit('tests-error');
|
|
95
95
|
|
|
96
|
-
return new
|
|
97
|
-
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
using(this.runHook('on_exit'), () => {}).then(() => {
|
|
98
98
|
reject(error);
|
|
99
99
|
});
|
|
100
100
|
});
|
|
@@ -103,14 +103,14 @@ module.exports = class App extends EventEmitter {
|
|
|
103
103
|
});
|
|
104
104
|
});
|
|
105
105
|
});
|
|
106
|
-
}).
|
|
106
|
+
}).then(() => this.cleanExit(), err => this.cleanExit(err));
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
waitForTests() {
|
|
110
110
|
log.info('Waiting for tests.');
|
|
111
111
|
|
|
112
112
|
if (this.exited) {
|
|
113
|
-
return
|
|
113
|
+
return Promise.reject(this.exitErr || new Error('Testem exited before running any tests.'));
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
let run = this.triggerRun('Start');
|
|
@@ -119,7 +119,7 @@ module.exports = class App extends EventEmitter {
|
|
|
119
119
|
run.then(() => this.exit());
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
return new
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
123
|
this.on('testFinish', resolve);
|
|
124
124
|
this.on('testError', reject);
|
|
125
125
|
});
|
|
@@ -142,23 +142,23 @@ module.exports = class App extends EventEmitter {
|
|
|
142
142
|
|
|
143
143
|
stopCurrentRun() {
|
|
144
144
|
if (!this.currentRun) {
|
|
145
|
-
return
|
|
145
|
+
return Promise.resolve();
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
return
|
|
148
|
+
return Promise.all([ this.stopRunners(), this.currentRun ]);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
runTests() {
|
|
152
152
|
if (this.paused) {
|
|
153
|
-
return
|
|
153
|
+
return Promise.resolve();
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
log.info('Running tests...');
|
|
157
157
|
|
|
158
158
|
this.reporter.onStart('testem', { launcherId: 0 });
|
|
159
159
|
|
|
160
|
-
return
|
|
161
|
-
return
|
|
160
|
+
return using(this.runHook('before_tests'), () => {
|
|
161
|
+
return using(RunTimeout.with(this.config.get('timeout')), timeout => {
|
|
162
162
|
this.testSuiteTimeout = timeout;
|
|
163
163
|
|
|
164
164
|
timeout.on('timeout', () => {
|
|
@@ -176,7 +176,7 @@ module.exports = class App extends EventEmitter {
|
|
|
176
176
|
|
|
177
177
|
return this.currentRun;
|
|
178
178
|
}).then(() => {
|
|
179
|
-
return
|
|
179
|
+
return using(this.runHook('after_tests'), () => {});
|
|
180
180
|
});
|
|
181
181
|
}).catch(err => {
|
|
182
182
|
if (err.hideFromReporter) {
|
|
@@ -221,7 +221,7 @@ module.exports = class App extends EventEmitter {
|
|
|
221
221
|
return;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
startServer(
|
|
224
|
+
startServer() {
|
|
225
225
|
log.info('Starting server');
|
|
226
226
|
this.server = new Server(this.config);
|
|
227
227
|
this.server.on('file-requested', this.onFileRequested.bind(this));
|
|
@@ -229,11 +229,11 @@ module.exports = class App extends EventEmitter {
|
|
|
229
229
|
this.server.on('browser-relogin', this.onBrowserRelogin.bind(this));
|
|
230
230
|
this.server.on('server-error', this.onServerError.bind(this));
|
|
231
231
|
|
|
232
|
-
return this.server.start()
|
|
232
|
+
return this.server.start();
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
getServer() {
|
|
236
|
-
return this.startServer()
|
|
236
|
+
return disposer(Promise.resolve(this.startServer()), () => this.stopServer());
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
onFileRequested(filepath) {
|
|
@@ -294,12 +294,12 @@ module.exports = class App extends EventEmitter {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
fileWatch() {
|
|
297
|
-
return this.configureFileWatch()
|
|
297
|
+
return disposer(Promise.resolve(this.configureFileWatch()), () => {});
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
configureFileWatch(
|
|
300
|
+
configureFileWatch() {
|
|
301
301
|
if (this.config.get('disable_watching')) {
|
|
302
|
-
return
|
|
302
|
+
return Promise.resolve();
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
this.fileWatcher = new FileWatcher(this.config);
|
|
@@ -316,7 +316,7 @@ module.exports = class App extends EventEmitter {
|
|
|
316
316
|
this.triggerRun('Config changed');
|
|
317
317
|
});
|
|
318
318
|
} else {
|
|
319
|
-
|
|
319
|
+
using(this.runHook('on_change', {file: filepath}), () => {
|
|
320
320
|
this.triggerRun('File changed: ' + filepath);
|
|
321
321
|
});
|
|
322
322
|
}
|
|
@@ -333,13 +333,13 @@ module.exports = class App extends EventEmitter {
|
|
|
333
333
|
view.setErrorPopupMessage(new StyledString(text + '\n ').foreground('megenta'));
|
|
334
334
|
});
|
|
335
335
|
|
|
336
|
-
return
|
|
336
|
+
return Promise.resolve();
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
getRunners() {
|
|
340
|
-
return
|
|
340
|
+
return disposer(fromCallback(callback => {
|
|
341
341
|
this.createRunners(callback);
|
|
342
|
-
})
|
|
342
|
+
}), () => {
|
|
343
343
|
return this.killRunners();
|
|
344
344
|
});
|
|
345
345
|
}
|
|
@@ -385,45 +385,38 @@ module.exports = class App extends EventEmitter {
|
|
|
385
385
|
}
|
|
386
386
|
|
|
387
387
|
withTestTimeout() {
|
|
388
|
-
return this.startClock()
|
|
388
|
+
return disposer(this.startClock(), () => {
|
|
389
389
|
return this.cancelExistingTimeout();
|
|
390
390
|
});
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
singleRun(timeout) {
|
|
394
394
|
let limit = this.config.get('parallel');
|
|
395
|
+
let concurrency = (limit && limit >= 1) ? parseInt(limit) : Infinity;
|
|
395
396
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (limit && limit >= 1) {
|
|
399
|
-
options.concurrency = parseInt(limit);
|
|
400
|
-
} else {
|
|
401
|
-
options.concurrency = Infinity;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return Bluebird.map(this.runners, (runner) => {
|
|
397
|
+
return mapLimit(this.runners, concurrency, runner => {
|
|
405
398
|
if (this.exited) {
|
|
406
399
|
let e = new Error('Run canceled.');
|
|
407
400
|
e.hideFromReporter = true;
|
|
408
|
-
return
|
|
401
|
+
return Promise.reject(e);
|
|
409
402
|
}
|
|
410
403
|
if (this.restarting) {
|
|
411
|
-
return
|
|
404
|
+
return Promise.resolve();
|
|
412
405
|
}
|
|
413
406
|
return timeout.try(() => runner.start());
|
|
414
|
-
}
|
|
407
|
+
});
|
|
415
408
|
}
|
|
416
409
|
|
|
417
410
|
wrapUp(err) {
|
|
418
411
|
this.exit(err);
|
|
419
412
|
}
|
|
420
413
|
|
|
421
|
-
stopServer(
|
|
414
|
+
stopServer() {
|
|
422
415
|
if (!this.server) {
|
|
423
|
-
return
|
|
416
|
+
return Promise.resolve();
|
|
424
417
|
}
|
|
425
418
|
|
|
426
|
-
return this.server.stop()
|
|
419
|
+
return this.server.stop();
|
|
427
420
|
}
|
|
428
421
|
|
|
429
422
|
getExitCode() {
|
|
@@ -442,17 +435,17 @@ module.exports = class App extends EventEmitter {
|
|
|
442
435
|
}
|
|
443
436
|
|
|
444
437
|
stopRunners() {
|
|
445
|
-
return
|
|
438
|
+
return Promise.all(this.runners.map(runner => {
|
|
446
439
|
if (typeof runner.stop === 'function') {
|
|
447
440
|
return runner.stop();
|
|
448
441
|
}
|
|
449
442
|
|
|
450
443
|
return runner.exit();
|
|
451
|
-
});
|
|
444
|
+
}));
|
|
452
445
|
}
|
|
453
446
|
|
|
454
447
|
killRunners() {
|
|
455
|
-
return
|
|
448
|
+
return Promise.all(this.runners.map(runner => runner.exit()));
|
|
456
449
|
}
|
|
457
450
|
|
|
458
451
|
launchers() {
|
package/lib/browser_launcher.js
CHANGED
|
@@ -8,10 +8,9 @@ This file more or less figures out how to launch any browser on any platform.
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
var Bluebird = require('bluebird');
|
|
12
|
-
|
|
13
11
|
var fileutils = require('./utils/fileutils');
|
|
14
12
|
var envWithLocalPath = require('./utils/env-with-local-path');
|
|
13
|
+
const { filter, asCallback } = require('./utils/promises');
|
|
15
14
|
|
|
16
15
|
var executableExists = function(exe, config) {
|
|
17
16
|
return fileutils.executableExists(exe, { env: envWithLocalPath(config) });
|
|
@@ -24,7 +23,7 @@ function getAvailableBrowsers(config, browsers, cb) {
|
|
|
24
23
|
b.protocol = 'browser';
|
|
25
24
|
});
|
|
26
25
|
|
|
27
|
-
return
|
|
26
|
+
return filter(browsers, function(browser) {
|
|
28
27
|
return isInstalled(browser, config).then(function(result) {
|
|
29
28
|
if (!result) {
|
|
30
29
|
return false;
|
|
@@ -33,7 +32,7 @@ function getAvailableBrowsers(config, browsers, cb) {
|
|
|
33
32
|
browser.exe = result;
|
|
34
33
|
return true;
|
|
35
34
|
});
|
|
36
|
-
}).asCallback(cb);
|
|
35
|
+
}).then(...asCallback(cb));
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
function isInstalled(browser, config) {
|
|
@@ -50,11 +49,11 @@ function isInstalled(browser, config) {
|
|
|
50
49
|
|
|
51
50
|
function checkBrowser(browser, property, method) {
|
|
52
51
|
if (!browser[property]) {
|
|
53
|
-
return
|
|
52
|
+
return Promise.resolve(false);
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
if (Array.isArray(browser[property])) {
|
|
57
|
-
return
|
|
56
|
+
return filter(browser[property], method).then(function(result) {
|
|
58
57
|
if (result.length === 0) {
|
|
59
58
|
return false;
|
|
60
59
|
}
|
package/lib/config.js
CHANGED
|
@@ -12,12 +12,12 @@ or `testem.json` config file.
|
|
|
12
12
|
const os = require('os');
|
|
13
13
|
const fs = require('fs');
|
|
14
14
|
const yaml = require('js-yaml');
|
|
15
|
-
const log = require('
|
|
15
|
+
const log = require('./log');
|
|
16
16
|
const path = require('path');
|
|
17
17
|
const glob = require('glob').glob;
|
|
18
18
|
const url = require('url');
|
|
19
19
|
const querystring = require('querystring');
|
|
20
|
-
const
|
|
20
|
+
const { filter, reduce } = require('./utils/promises');
|
|
21
21
|
|
|
22
22
|
const browser_launcher = require('./browser_launcher');
|
|
23
23
|
const LauncherFactory = require('./launcher-factory');
|
|
@@ -72,7 +72,7 @@ class Config {
|
|
|
72
72
|
// Try all testem.json, testem.yml and testem.js
|
|
73
73
|
// testem.json gets precedence
|
|
74
74
|
let files = ['testem.json', '.testem.json', '.testem.yml', 'testem.yml', 'testem.js', '.testem.js', 'testem.cjs', '.testem.cjs'];
|
|
75
|
-
return
|
|
75
|
+
return filter(files.map(this.resolveConfigPath.bind(this)), fileExists).then(matched => {
|
|
76
76
|
let configFile = matched[0];
|
|
77
77
|
if (matched.length > 1) {
|
|
78
78
|
let baseNames = matched.map(fileName => path.basename(fileName));
|
|
@@ -158,28 +158,28 @@ class Config {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
readYAML(configFile, callback) {
|
|
161
|
-
fs.readFile(configFile
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
161
|
+
return fs.promises.readFile(configFile)
|
|
162
|
+
.then(data => {
|
|
163
|
+
this.fileOptions = yaml.load(String(data));
|
|
164
|
+
}, () => {})
|
|
165
|
+
.then(() => {
|
|
166
|
+
if (callback) {
|
|
167
|
+
callback.call(this);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
readJSON(configFile, callback) {
|
|
173
|
-
fs.readFile(configFile
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
this.fileOptions = cfg;
|
|
173
|
+
return fs.promises.readFile(configFile)
|
|
174
|
+
.then(data => {
|
|
175
|
+
this.fileOptions = JSON.parse(data.toString());
|
|
177
176
|
this.progOptions.file = configFile;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
callback
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
}, () => {})
|
|
178
|
+
.then(() => {
|
|
179
|
+
if (callback) {
|
|
180
|
+
callback.call(this);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
mergeUrlAndQueryParams(urlString, queryParamsObj) {
|
|
@@ -399,7 +399,7 @@ class Config {
|
|
|
399
399
|
});
|
|
400
400
|
|
|
401
401
|
dontWant = dontWant.map(p => p ? this.resolvePath(p) : p);
|
|
402
|
-
|
|
402
|
+
return reduce(positiveWants, (allThatIWant, patternEntry) => {
|
|
403
403
|
let pattern = isa(patternEntry, String) ? patternEntry : patternEntry.src;
|
|
404
404
|
let attrs = patternEntry.attrs || [];
|
|
405
405
|
let patternUrl = url.parse(pattern);
|
|
@@ -418,27 +418,33 @@ class Config {
|
|
|
418
418
|
})));
|
|
419
419
|
}, [])
|
|
420
420
|
.then(result => _.uniqBy(result, 'src'))
|
|
421
|
-
.
|
|
421
|
+
.then(result => {
|
|
422
|
+
if (callback) { callback(null, result); }
|
|
423
|
+
return result;
|
|
424
|
+
}, err => {
|
|
425
|
+
if (callback) { callback(err); }
|
|
426
|
+
throw err;
|
|
427
|
+
});
|
|
422
428
|
}
|
|
423
429
|
|
|
424
430
|
getSrcFiles(callback) {
|
|
425
431
|
let srcFiles = this.get('src_files') || '*.js';
|
|
426
432
|
let srcFilesIgnore = this.get('src_files_ignore') || '';
|
|
427
|
-
this.getFileSet(srcFiles, srcFilesIgnore, callback);
|
|
433
|
+
return this.getFileSet(srcFiles, srcFilesIgnore, callback);
|
|
428
434
|
}
|
|
429
435
|
|
|
430
436
|
getFooterScripts(callback) {
|
|
431
437
|
var want = this.get('footer_scripts') || [];
|
|
432
438
|
var dontWant = this.get('src_files_ignore') || '';
|
|
433
439
|
|
|
434
|
-
this.getFileSet(want, dontWant, callback);
|
|
440
|
+
return this.getFileSet(want, dontWant, callback);
|
|
435
441
|
}
|
|
436
442
|
|
|
437
443
|
|
|
438
444
|
getServeFiles(callback) {
|
|
439
445
|
let want = this.get('serve_files') || this.get('src_files') || '*.js';
|
|
440
446
|
let dontWant = this.get('serve_files_ignore') || this.get('src_files_ignore') || '';
|
|
441
|
-
this.getFileSet(want, dontWant, callback);
|
|
447
|
+
return this.getFileSet(want, dontWant, callback);
|
|
442
448
|
}
|
|
443
449
|
|
|
444
450
|
getUserDataDir() {
|
|
@@ -455,7 +461,7 @@ class Config {
|
|
|
455
461
|
|
|
456
462
|
getCSSFiles(callback) {
|
|
457
463
|
let want = this.get('css_files') || '';
|
|
458
|
-
this.getFileSet(want, '', callback);
|
|
464
|
+
return this.getFileSet(want, '', callback);
|
|
459
465
|
}
|
|
460
466
|
|
|
461
467
|
getAllOptions() {
|
|
@@ -475,7 +481,7 @@ class Config {
|
|
|
475
481
|
return options;
|
|
476
482
|
}
|
|
477
483
|
|
|
478
|
-
getTemplateData(cb) {
|
|
484
|
+
async getTemplateData(cb) {
|
|
479
485
|
let ret = {};
|
|
480
486
|
let options = this.getAllOptions();
|
|
481
487
|
let key;
|
|
@@ -490,24 +496,31 @@ class Config {
|
|
|
490
496
|
for (key in this.config) {
|
|
491
497
|
ret[key] = this.config[key];
|
|
492
498
|
}
|
|
493
|
-
this.getServeFiles((err, files) => {
|
|
494
|
-
let replaceSlashes = f => ({
|
|
495
|
-
src: f.src.replace(/\\/g, '/'),
|
|
496
|
-
attrs: f.attrs
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
ret.serve_files = files.map(replaceSlashes);
|
|
500
499
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
ret.footer_scripts = files;
|
|
505
|
-
if (cb) {
|
|
506
|
-
cb(err, ret);
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
});
|
|
500
|
+
const replaceSlashes = f => ({
|
|
501
|
+
src: f.src.replace(/\\/g, '/'),
|
|
502
|
+
attrs: f.attrs
|
|
510
503
|
});
|
|
504
|
+
|
|
505
|
+
try {
|
|
506
|
+
const [serveFiles, cssFiles, footerScripts] = await Promise.all([
|
|
507
|
+
this.getServeFiles(),
|
|
508
|
+
this.getCSSFiles(),
|
|
509
|
+
this.getFooterScripts()
|
|
510
|
+
]);
|
|
511
|
+
|
|
512
|
+
ret.serve_files = serveFiles.map(replaceSlashes);
|
|
513
|
+
ret.css_files = cssFiles.map(replaceSlashes);
|
|
514
|
+
ret.footer_scripts = footerScripts;
|
|
515
|
+
|
|
516
|
+
if (cb) {
|
|
517
|
+
cb(null, ret);
|
|
518
|
+
}
|
|
519
|
+
} catch (err) {
|
|
520
|
+
if (cb) {
|
|
521
|
+
cb(err, ret);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
511
524
|
}
|
|
512
525
|
}
|
|
513
526
|
|
package/lib/launcher.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
const log = require('
|
|
3
|
+
const log = require('./log');
|
|
4
4
|
const tmp = require('tmp');
|
|
5
5
|
const path = require('path');
|
|
6
|
-
const
|
|
6
|
+
const { fromCallback } = require('./utils/promises');
|
|
7
7
|
|
|
8
8
|
const template = require('./utils/strutils').template;
|
|
9
9
|
const ProcessCtl = require('./process-ctl');
|
|
@@ -54,15 +54,11 @@ module.exports = class Launcher {
|
|
|
54
54
|
const settings = this.settings;
|
|
55
55
|
this.setupBrowserTmpDir();
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
settings.setup.call(this, this.config, setupCallback);
|
|
61
|
-
});
|
|
62
|
-
}
|
|
57
|
+
const setupPromise = settings.setup
|
|
58
|
+
? fromCallback(setupCallback => settings.setup.call(this, this.config, setupCallback))
|
|
59
|
+
: Promise.resolve();
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
}).then(() => this.doLaunch());
|
|
61
|
+
return setupPromise.then(() => this.doLaunch());
|
|
66
62
|
}
|
|
67
63
|
|
|
68
64
|
doLaunch() {
|
|
@@ -84,7 +80,7 @@ module.exports = class Launcher {
|
|
|
84
80
|
|
|
85
81
|
return this.processCtl.exec(cmd, options);
|
|
86
82
|
} else {
|
|
87
|
-
return
|
|
83
|
+
return Promise.reject(new Error('No command or exe/args specified for launcher ' + this.name));
|
|
88
84
|
}
|
|
89
85
|
}
|
|
90
86
|
|
package/lib/log.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const EventEmitter = require('events');
|
|
2
|
+
const procLog = require('proc-log').log;
|
|
3
|
+
|
|
4
|
+
class Log extends EventEmitter {
|
|
5
|
+
constructor() {
|
|
6
|
+
super();
|
|
7
|
+
this.stream = process.stderr;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
formatRecord(level, args) {
|
|
11
|
+
let prefix = '';
|
|
12
|
+
let message = '';
|
|
13
|
+
|
|
14
|
+
if (args.length === 1) {
|
|
15
|
+
message = args[0];
|
|
16
|
+
} else if (args.length >= 2) {
|
|
17
|
+
prefix = args[0] || '';
|
|
18
|
+
message = args.slice(1).join(' ');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
level,
|
|
23
|
+
prefix,
|
|
24
|
+
message: String(message)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
write(record) {
|
|
29
|
+
if (this.stream && typeof this.stream.write === 'function') {
|
|
30
|
+
this.stream.write(record.message + '\n');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
emitLog(level, args) {
|
|
35
|
+
const record = this.formatRecord(level, args);
|
|
36
|
+
|
|
37
|
+
this.emit(`log.${level}`, record);
|
|
38
|
+
this.write(record);
|
|
39
|
+
|
|
40
|
+
if (procLog && typeof procLog[level] === 'function') {
|
|
41
|
+
procLog[level](...args);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
error(...args) {
|
|
46
|
+
this.emitLog('error', args);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
notice(...args) {
|
|
50
|
+
this.emitLog('notice', args);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
warn(...args) {
|
|
54
|
+
this.emitLog('warn', args);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
info(...args) {
|
|
58
|
+
this.emitLog('info', args);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
verbose(...args) {
|
|
62
|
+
this.emitLog('verbose', args);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
http(...args) {
|
|
66
|
+
this.emitLog('http', args);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
silly(...args) {
|
|
70
|
+
this.emitLog('silly', args);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
timing(...args) {
|
|
74
|
+
this.emitLog('timing', args);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
pause() {
|
|
78
|
+
this.emit('log.pause');
|
|
79
|
+
if (procLog && typeof procLog.pause === 'function') {
|
|
80
|
+
procLog.pause();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
resume() {
|
|
85
|
+
this.emit('log.resume');
|
|
86
|
+
if (procLog && typeof procLog.resume === 'function') {
|
|
87
|
+
procLog.resume();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = new Log();
|
package/lib/process-ctl.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
const log = require('
|
|
3
|
+
const log = require('./log');
|
|
4
4
|
const execa = require('execa').execa;
|
|
5
|
-
const Bluebird = require('bluebird');
|
|
6
5
|
const util = require('util');
|
|
7
6
|
const EventEmitter = require('events').EventEmitter;
|
|
8
7
|
const spawnargs = require('spawn-args');
|
|
@@ -12,6 +11,7 @@ const envWithLocalPath = require('./utils/env-with-local-path');
|
|
|
12
11
|
const fileutils = require('./utils/fileutils');
|
|
13
12
|
const Process = require('./utils/process');
|
|
14
13
|
const isWin = require('./utils/is-win')();
|
|
14
|
+
const { reduce } = require('./utils/promises');
|
|
15
15
|
|
|
16
16
|
const fileExists = fileutils.fileExists;
|
|
17
17
|
const executableExists = fileutils.executableExists;
|
|
@@ -53,14 +53,14 @@ module.exports = class ProcessCtl extends EventEmitter {
|
|
|
53
53
|
|
|
54
54
|
let p = new Process(this.name, { killTimeout: this.killTimeout }, process);
|
|
55
55
|
this.emit('processStarted', p);
|
|
56
|
-
return
|
|
56
|
+
return Promise.resolve(p);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
spawn(exe, args, options) {
|
|
60
60
|
let _options = this.prepareOptions(options);
|
|
61
61
|
|
|
62
62
|
if (Array.isArray(exe)) {
|
|
63
|
-
return
|
|
63
|
+
return reduce(exe, (found, exe) => {
|
|
64
64
|
if (found) {
|
|
65
65
|
return found;
|
|
66
66
|
}
|
|
@@ -10,7 +10,7 @@ The actual AppView. This encapsulates the entire UI.
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const StyledString = require('styled_string');
|
|
13
|
-
const log = require('
|
|
13
|
+
const log = require('../../log');
|
|
14
14
|
const Backbone = require('backbone');
|
|
15
15
|
|
|
16
16
|
const View = require('./view');
|
|
@@ -60,6 +60,7 @@ module.exports = View.extend({
|
|
|
60
60
|
if (atLeastOne && this.get('currentTab') < 0) {
|
|
61
61
|
this.set('currentTab', 0);
|
|
62
62
|
}
|
|
63
|
+
this.renderTop();
|
|
63
64
|
this.renderMiddle();
|
|
64
65
|
this.renderBottom();
|
|
65
66
|
});
|
|
@@ -213,7 +213,7 @@ module.exports = View.extend({
|
|
|
213
213
|
out += 'Top Level:\n' + indent(topLevelError) + '\n\n';
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
if (results && (tests = results.get('tests'))) {
|
|
216
|
+
if (results && (tests = results.get('tests')) && !topLevelError) {
|
|
217
217
|
var total = results.get('total');
|
|
218
218
|
var pending = results.get('pending');
|
|
219
219
|
var allDone = results.get('all');
|