'use strict';
/**
* User Interface for the Scenario Runner.
*
* TODO(esprehn): This should be refactored now that ObjectModel exists
* to use angular bindings for the UI.
*/
angular.scenario.output('html', function(context, runner, model) {
var specUiMap = {},
lastStepUiMap = {};
context.append(
'
' +
''
);
runner.on('InteractivePause', function(spec, step) {
var ui = lastStepUiMap[spec.id];
ui.find('.test-title').
html('paused... resume when ready.');
});
runner.on('SpecBegin', function(spec) {
var ui = findContext(spec);
ui.find('> .tests').append(
''
);
ui = ui.find('> .tests li:last');
ui.append(
'' +
'
' +
' ' +
' ' +
'
' +
'
' +
''
);
ui.find('> .test-info .test-name').text(spec.name);
ui.find('> .test-info').click(function() {
var scrollpane = ui.find('> .scrollpane');
var actions = scrollpane.find('> .test-actions');
var name = context.find('> .test-info .test-name');
if (actions.find(':visible').length) {
actions.hide();
name.removeClass('open').addClass('closed');
} else {
actions.show();
scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
name.removeClass('closed').addClass('open');
}
});
specUiMap[spec.id] = ui;
});
runner.on('SpecError', function(spec, error) {
var ui = specUiMap[spec.id];
ui.append('');
ui.find('> pre').text(formatException(error));
});
runner.on('SpecEnd', function(spec) {
var ui = specUiMap[spec.id];
spec = model.getSpec(spec.id);
ui.removeClass('status-pending');
ui.addClass('status-' + spec.status);
ui.find("> .test-info .timer-result").text(spec.duration + "ms");
if (spec.status === 'success') {
ui.find('> .test-info .test-name').addClass('closed');
ui.find('> .scrollpane .test-actions').hide();
}
updateTotals(spec.status);
});
runner.on('StepBegin', function(spec, step) {
var ui = specUiMap[spec.id];
spec = model.getSpec(spec.id);
step = spec.getLastStep();
ui.find('> .scrollpane .test-actions').append('');
var stepUi = lastStepUiMap[spec.id] = ui.find('> .scrollpane .test-actions li:last');
stepUi.append(
'' +
''
);
stepUi.find('> .test-title').text(step.name);
var scrollpane = stepUi.parents('.scrollpane');
scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
});
runner.on('StepFailure', function(spec, step, error) {
var ui = lastStepUiMap[spec.id];
addError(ui, step.line, error);
});
runner.on('StepError', function(spec, step, error) {
var ui = lastStepUiMap[spec.id];
addError(ui, step.line, error);
});
runner.on('StepEnd', function(spec, step) {
var stepUi = lastStepUiMap[spec.id];
spec = model.getSpec(spec.id);
step = spec.getLastStep();
stepUi.find('.timer-result').text(step.duration + 'ms');
stepUi.removeClass('status-pending');
stepUi.addClass('status-' + step.status);
var scrollpane = specUiMap[spec.id].find('> .scrollpane');
scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
});
/**
* Finds the context of a spec block defined by the passed definition.
*
* @param {Object} The definition created by the Describe object.
*/
function findContext(spec) {
var currentContext = context.find('#specs');
angular.forEach(model.getDefinitionPath(spec), function(defn) {
var id = 'describe-' + defn.id;
if (!context.find('#' + id).length) {
currentContext.find('> .test-children').append(
''
);
context.find('#' + id).find('> h2').text('describe: ' + defn.name);
}
currentContext = context.find('#' + id);
});
return context.find('#describe-' + spec.definition.id);
}
/**
* Updates the test counter for the status.
*
* @param {string} the status.
*/
function updateTotals(status) {
var legend = context.find('#status-legend .status-' + status);
var parts = legend.text().split(' ');
var value = (parts[0] * 1) + 1;
legend.text(value + ' ' + parts[1]);
}
/**
* Add an error to a step.
*
* @param {Object} The JQuery wrapped context
* @param {Function} fn() that should return the file/line number of the error
* @param {Object} the error.
*/
function addError(context, line, error) {
context.find('.test-title').append('');
var message = _jQuery.trim(line() + '\n\n' + formatException(error));
context.find('.test-title pre:last').text(message);
}
});