testem
Version:
Test'em 'scripts! Javascript Unit testing made easy.
281 lines (263 loc) • 8.07 kB
JavaScript
'use strict';
var View = require('./view');
var ScrollableTextPanel = require('./scrollable_text_panel');
var tabs = require('./constants');
var styledString = require('styled_string');
var Chars = require('../../utils/chars');
var indent = require('../../utils/strutils').indent;
var Screen = require('./screen');
function failureDisplay(item) {
var extra = [];
var stacktrace = item.stack;
if (stacktrace) {
var stacklines = stacktrace.split('\n');
if (stacklines[0] === item.message) {
stacktrace = stacklines.slice(1).map(function(line) {
return line.trim();
}).join('\n');
}
extra.push(stacktrace);
} else {
if (item.file) {
extra.push(item.file);
}
if (item.line) {
extra.push(' ' + item.line);
}
}
if (item.expected) {
extra.push(' expected ' + (item.negative ? 'NOT ' : '') + item.expected);
}
if (item.actual) {
extra.push(' actual ' + item.actual);
}
if (item.at) {
extra.push(' at ' + item.at);
}
return Chars.cross + ' ' + (item.message || 'failed') +
(extra ? '\n' + indent(extra.join('\n')) : '');
}
function failedTestDisplay(test) {
var failedItems = (test.get('items') || []).filter(function(item) {
return !item.passed;
});
return test.get('name') + '\n' +
indent(failedItems.map(failureDisplay).join('\n'));
}
module.exports = View.extend({
defaults: {
visible: false,
focus: 'top'
},
initialize: function() {
if (!this.get('screen')) {
this.set('screen', new Screen());
}
var runner = this.get('runner');
var results = runner.get('results');
var messages = runner.get('messages');
var appview = this.get('appview');
var visible = this.get('visible');
var self = this;
var screen = this.get('screen');
var topPanel = this.topPanel = new ScrollableTextPanel({
line: tabs.TabStartLine + tabs.TabHeight - 1,
col: 0,
visible: visible,
screen: screen
});
var bottomPanel = this.bottomPanel = new ScrollableTextPanel({
col: 0,
visible: visible,
screen: screen
});
this.observe(appview, 'change:cols change:lines', function() {
self.syncDimensions();
self.render();
});
if (results) {
this.observe(results, 'change', function() {
self.syncDimensions();
self.syncResultsDisplay();
});
}
this.observe(messages, 'reset add remove', function() {
self.syncDimensions();
self.syncMessages();
});
this.observe(this, 'change:visible', function() {
var visible = self.get('visible');
topPanel.set('visible', visible, {silent: true});
bottomPanel.set('visible', visible, {silent: true});
self.syncDimensions({silent: true});
self.render();
});
this.syncDimensions({silent: true});
this.syncResultsDisplay({silent: true});
this.syncMessages({silent: true});
this.render();
},
toggleFocus: function() {
var focus = this.get('focus');
this.set('focus', focus === 'top' ? 'bottom' : 'top');
},
resetScrollPositions: function() {
this.topPanel.set('scrollOffset', 0);
this.bottomPanel.set('scrollOffset', 0);
},
targetPanel: function() {
var runner = this.get('runner');
var bottomPanel = this.bottomPanel;
var topPanel = this.topPanel;
if (runner.hasMessages() && runner.hasResults()) {
return (this.get('focus') === 'top') ? topPanel : bottomPanel;
} else if (runner.hasMessages()) {
return bottomPanel;
} else if (runner.hasResults()) {
return topPanel;
} else {
return topPanel;
}
},
scrollUp: function() {
this.targetPanel().scrollUp();
},
scrollDown: function() {
this.targetPanel().scrollDown();
},
pageUp: function() {
this.targetPanel().pageUp();
},
pageDown: function() {
this.targetPanel().pageDown();
},
halfPageUp: function() {
this.targetPanel().halfPageUp();
},
halfPageDown: function() {
this.targetPanel().halfPageDown();
},
syncMessages: function(options) {
this.bottomPanel.set('text', this.getMessagesText(), options);
},
syncResultsDisplay: function(options) {
this.topPanel.set('text', this.getResultsDisplayText(), options);
},
syncDimensions: function(options) {
var appview = this.get('appview');
var termCols = appview.get('cols');
var termLines = appview.get('lines');
var runner = this.get('runner');
if (runner.hasMessages() && runner.hasResults()) {
var midLine = Math.floor((termLines - tabs.LogPanelUnusedLines) / 2);
this.topPanel.set({
height: midLine,
width: termCols
}, options);
var line = midLine + tabs.TabStartLine + tabs.TabHeight - 1;
var bottomPanelAttrs = {
line: line,
height: termLines - line - 1,
width: termCols
};
this.bottomPanel.set(bottomPanelAttrs, options);
} else if (runner.hasMessages()) { // only has messages
this.topPanel.set({
height: 0,
width: termCols
}, options);
var height = termLines - tabs.LogPanelUnusedLines;
this.bottomPanel.set({
line: tabs.TabStartLine + tabs.TabHeight - 1,
height: height,
width: termCols
}, options);
} else { // only has results
// Hide the bottom panel if there are no messages
// to be displayed
var topPanelHeight = termLines - tabs.LogPanelUnusedLines;
this.topPanel.set({
height: topPanelHeight,
width: termCols
}, options);
this.bottomPanel.set({
line: tabs.TabStartLine + tabs.TabHeight + topPanelHeight,
height: 0,
width: termCols
}, options);
}
},
render: function() {
this.topPanel.render();
this.bottomPanel.render();
},
getResultsDisplayText: function() {
var runner = this.get('runner');
var results = runner.get('results');
var topLevelError = results ? results.get('topLevelError') : null;
var tests = null;
var out = '';
var pendingOut = '';
if (topLevelError) {
out += 'Top Level:\n' + indent(topLevelError) + '\n\n';
}
if (results && (tests = results.get('tests'))) {
var total = results.get('total');
var pending = results.get('pending');
var allDone = results.get('all');
if (!total) {
out = allDone ? 'No tests were run :(' : 'Please be patient :)';
} else {
var failedTests = tests.filter(function(test) {
return test.get('failed') > 0;
});
if (failedTests.length > 0) {
out += failedTests.map(failedTestDisplay).join('\n');
} else { // All passed
if (allDone) {
var pendingTests = tests.filter(function(test) {
return test.get('pending') > 0;
});
out += Chars.success + ' ' + total + ' tests complete';
if (pending > 0) {
out += ' (' + pending + ' pending)';
}
out += '.';
if (pending) {
pendingOut += '\n\n';
pendingOut += pendingTests.map(function(test) {
return '[PENDING] ' + test.get('name');
}).join('\n');
}
} else {
out += 'Looking good...';
}
}
}
}
return styledString(out, {foreground: 'cyan'})
.append(styledString(pendingOut, {foreground: 'yellow'}));
},
getMessagesText: function() {
var messages = this.get('runner').get('messages');
var retval = styledString('');
messages.forEach(function(message) {
var type = message.get('type');
var text = message.get('text');
var color = 'yellow';
switch (type) {
case 'warn':
color = 'cyan';
break;
case 'info':
color = 'green';
break;
case 'error':
color = 'red';
break;
}
retval = retval.concat(styledString(text, {foreground: color}));
});
return retval;
}
});