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 CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- const log = require('npmlog');
3
+ const log = require('./log');
4
4
  const Config = require('./config');
5
5
  const EventEmitter = require('events').EventEmitter;
6
6
  const fs = require('fs');
package/lib/app.js CHANGED
@@ -1,9 +1,9 @@
1
1
 
2
2
 
3
3
  const EventEmitter = require('events').EventEmitter;
4
- const Bluebird = require('bluebird');
4
+ const { fromCallback, using, disposer, mapLimit } = require('./utils/promises');
5
5
  const Path = require('path');
6
- const log = require('npmlog');
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 Bluebird.using(SignalListeners.with(), signalListeners => {
67
+ return using(SignalListeners.with(), signalListeners => {
68
68
  signalListeners.on('signal', err => this.exit(err));
69
69
 
70
- return Bluebird.using(Reporter.with(this, this.stdoutStream, this.reportFileName), reporter => {
70
+ return using(Reporter.with(this, this.stdoutStream, this.reportFileName), reporter => {
71
71
  this.reporter = reporter;
72
72
 
73
- return Bluebird.using(this.fileWatch(), () => {
74
- return Bluebird.using(this.getServer(), () => {
75
- return Bluebird.using(this.getRunners(), () => {
76
- return Bluebird.using(this.runHook('on_start'), () => {
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 Bluebird.using(this.runHook('on_exit'), () => {});
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 Bluebird((resolve, reject) => {
97
- Bluebird.using(this.runHook('on_exit'), () => {}).then(() => {
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
- }).asCallback(this.cleanExit);
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 Bluebird.reject(this.exitErr || new Error('Testem exited before running any tests.'));
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 Bluebird.Promise((resolve, reject) => {
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 Bluebird.resolve();
145
+ return Promise.resolve();
146
146
  }
147
147
 
148
- return Bluebird.all([ this.stopRunners(), this.currentRun ]);
148
+ return Promise.all([ this.stopRunners(), this.currentRun ]);
149
149
  }
150
150
 
151
151
  runTests() {
152
152
  if (this.paused) {
153
- return Bluebird.resolve();
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 Bluebird.using(this.runHook('before_tests'), () => {
161
- return Bluebird.using(RunTimeout.with(this.config.get('timeout')), timeout => {
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 Bluebird.using(this.runHook('after_tests'), () => {});
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(callback) {
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().asCallback(callback);
232
+ return this.server.start();
233
233
  }
234
234
 
235
235
  getServer() {
236
- return this.startServer().disposer(() => this.stopServer());
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().disposer(() => {});
297
+ return disposer(Promise.resolve(this.configureFileWatch()), () => {});
298
298
  }
299
299
 
300
- configureFileWatch(cb) {
300
+ configureFileWatch() {
301
301
  if (this.config.get('disable_watching')) {
302
- return Bluebird.resolve().asCallback(cb);
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
- Bluebird.using(this.runHook('on_change', {file: filepath}), () => {
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 Bluebird.resolve().asCallback(cb);
336
+ return Promise.resolve();
337
337
  }
338
338
 
339
339
  getRunners() {
340
- return Bluebird.fromCallback(callback => {
340
+ return disposer(fromCallback(callback => {
341
341
  this.createRunners(callback);
342
- }).disposer(() => {
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().disposer(() => {
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
- let options = {};
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 Bluebird.reject(e);
401
+ return Promise.reject(e);
409
402
  }
410
403
  if (this.restarting) {
411
- return Bluebird.resolve();
404
+ return Promise.resolve();
412
405
  }
413
406
  return timeout.try(() => runner.start());
414
- }, options);
407
+ });
415
408
  }
416
409
 
417
410
  wrapUp(err) {
418
411
  this.exit(err);
419
412
  }
420
413
 
421
- stopServer(callback) {
414
+ stopServer() {
422
415
  if (!this.server) {
423
- return Bluebird.resolve().asCallback(callback);
416
+ return Promise.resolve();
424
417
  }
425
418
 
426
- return this.server.stop().asCallback(callback);
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 Bluebird.each(this.runners, runner => {
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 Bluebird.each(this.runners, runner => runner.exit());
448
+ return Promise.all(this.runners.map(runner => runner.exit()));
456
449
  }
457
450
 
458
451
  launchers() {
@@ -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 Bluebird.filter(browsers, function(browser) {
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 Bluebird.resolve(false);
52
+ return Promise.resolve(false);
54
53
  }
55
54
 
56
55
  if (Array.isArray(browser[property])) {
57
- return Bluebird.filter(browser[property], method).then(function(result) {
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('npmlog');
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 Bluebird = require('bluebird');
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 Bluebird.filter(files.map(this.resolveConfigPath.bind(this)), fileExists).then(matched => {
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, (err, data) => {
162
- if (!err) {
163
- let cfg = yaml.load(String(data));
164
- this.fileOptions = cfg;
165
- }
166
- if (callback) {
167
- callback.call(this);
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, (err, data) => {
174
- if (!err) {
175
- let cfg = JSON.parse(data.toString());
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
- if (callback) {
180
- callback.call(this);
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
- Bluebird.reduce(positiveWants, (allThatIWant, patternEntry) => {
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
- .asCallback(callback);
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
- this.getCSSFiles((err, files) => {
502
- ret.css_files = files.map(replaceSlashes);
503
- this.getFooterScripts((err, files) => {
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('npmlog');
3
+ const log = require('./log');
4
4
  const tmp = require('tmp');
5
5
  const path = require('path');
6
- const Bluebird = require('bluebird');
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
- return Bluebird.resolve().asCallback(() => {
58
- if (settings.setup) {
59
- return Bluebird.fromCallback(setupCallback => {
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
- return Bluebird.resolve();
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 Bluebird.reject(new Error('No command or exe/args specified for launcher ' + this.name));
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();
@@ -1,8 +1,7 @@
1
1
 
2
2
 
3
- const log = require('npmlog');
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 Bluebird.resolve(p);
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 Bluebird.reduce(exe, (found, exe) => {
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('npmlog');
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');