* Removed old Queue & Runner in favor of Suite using the new QueueRunner

* New reporter interface across all reporters
* xdescribe & xit now store disabled specs
* Rewrite of HtmlReporter to support new interface and be more performant
This commit is contained in:
Davis W. Frank
2012-12-10 22:43:03 -08:00
committed by Dan Hansen and Davis W. Frank
parent 05977203a6
commit 3fc79bac9e
43 changed files with 3229 additions and 3318 deletions
+10 -9
View File
@@ -14,7 +14,10 @@
### Hard
* Finish killing Globals
* Guidelines: everything that isn't a CTOR should be closed inside `Env`, and everything that is a CTOR needs to be `new`ed inside the `Env`
* Guidelines:
* New objects can have constructors on `jasmine`
* Top level functions can live on `jasmine`
* Top level (i.e., any `jasmine` property) should only be referenced inside the `Env` constructor
* Spies
* isA functions:
* isArray_ - used in matchers and spies
@@ -26,20 +29,18 @@
* argsToArray is used for Spies and matching
* inherit is for how matchers are added/mixed in, reporters, and pretty printers
* formatException is used only inside Env/spec
* htmlEscape is for messages in matchers - should this be HTML at all? Is that Reporter responsibility?
* Suites need to be unit-tested
* Remove Queue from Suite in favor of queuerunner refactoring
* Remover Runner in favor of a top-level Suite
* This means Env needs to `new` a `Suite` first thing
* get feature parity back on HTMLReporter
* htmlEscape is for messages in matchers - should this be HTML at all? Is that * Matchers improvements
* move AddMatchers to Env & global (away from spec)
* make matchers unit-testable
* write doc on how to make a matcher
### Easy
* Refactor `queuerunner` into a new object
* xdescribe / xit make skipped specs instead of empty blocks
## Other Topics
* Build - can we, should we redo the build and release process AGAIN in order to make it less arcane
* Want to add JSHint to build
* Use a standard JS/Node based concat system instead of custom Ruby?
* Docs
* JsDoc is a pain to host and RubyMine is pretty good at navigating. I say we kill it officially
* Docco has gone over well. Should we annotate all the sources and then have Pages be more complex, having tutorials and annotated source like Backbone? Are we small enough?
+14 -1
View File
@@ -53,7 +53,19 @@
extend(window, jasmineInterface);
}
var htmlReporter = new jasmine.HtmlReporter(null, jasmine, env);
var queryString = new jasmine.QueryString({
getWindowLocation: function() { return window.location; }
});
env.catchExceptions(queryString.getParam("catch"));
var htmlReporter = new jasmine.HtmlReporter({
env: env,
queryString: queryString,
getContainer: function() { return document.body; },
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
@@ -68,6 +80,7 @@
if (currentWindowOnload) {
currentWindowOnload();
}
htmlReporter.initialize();
env.execute();
};
+280 -473
View File
@@ -1,512 +1,319 @@
jasmine.HtmlReporterHelpers = {};
jasmine.HtmlReporter = function(options) {
var env = options.env || {},
getContainer = options.getContainer,
now = options.now || function() { return new Date().getTime();},
createElement = options.createElement,
createTextNode = options.createTextNode,
results = [],
queryString = options.queryString,
startTime,
specsExecuted = 0,
failureCount = 0,
htmlReporterMain,
symbols;
jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
this.initialize = function() {
htmlReporterMain = createDom("div", {className: "html-reporter"},
createDom("div", {className: "banner"},
createDom("span", {className: "title"}, "Jasmine"),
createDom("span", {className: "version"}, env.versionString())
),
createDom("ul", {className: "symbol-summary"}),
createDom("div", {className: "alert"}),
createDom("div", {className: "results"},
createDom("div", {className: "failures"})
)
);
getContainer().appendChild(htmlReporterMain);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
if (!child.results) {
return;
}
var results = child.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
return status;
};
jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
var parentDiv = this.dom.summary;
var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
var parent = child[parentSuite];
if (parent) {
if (typeof this.views.suites[parent.id] == 'undefined') {
this.views.suites[parent.id] = new this.jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views, this.jasmine, this.catchExceptions);
}
parentDiv = this.views.suites[parent.id].element;
}
parentDiv.appendChild(childElement);
};
jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
//TODO: not really a helper, thus, no this.jasmine
for(var fn in jasmine.HtmlReporterHelpers) {
ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
}
};
jasmine.HtmlReporter = function(_doc, jasmine, env, options) {
options = options || {};
var self = this;
this.jasmine = jasmine || window.jasmine;
var doc = _doc || window.document;
var reporterView;
var dom = {};
// Jasmine Reporter Public Interface
self.reportRunnerStarting = function(runner) {
var specs = runner.specs() || [];
if (specs.length == 0) {
return;
}
createReporterDom(runner.env.versionString());
doc.body.appendChild(dom.reporter);
setExceptionHandling();
reporterView = new self.jasmine.HtmlReporter.ReporterView(dom, self.jasmine, env.catchingExceptions());
reporterView.addSpecs(specs, self.specFilter);
symbols = find(".symbol-summary")[0];
};
self.reportRunnerResults = function(runner) {
reporterView && reporterView.complete();
};
var specFilterPattern;
self.reportSuiteResults = function(suite) {
reporterView.suiteComplete(suite);
};
self.reportSpecStarting = function(spec) {
};
var lastYieldForRender = 0;
var refreshInterval = 250;
var yieldForRender = options.yieldForRender || function(fn) {
var now = Date.now();
var delta = (now - lastYieldForRender);
if (delta > refreshInterval) {
lastYieldForRender = now;
setTimeout(fn, 0);
} else {
fn();
}
}
self.reportSpecResults = function(result) {
yieldForRender(function() {reporterView.specComplete(result) });
};
self.log = function() {
var console = self.jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
self.specFilter = function(spec) {
if (!focusedSpecName()) {
this.specFilter = function(spec) {
if (!isFiltered()) {
return true;
}
return spec.getFullName().indexOf(focusedSpecName()) === 0;
var specName = spec.getFullName();
return !!(specName.match(specFilterPattern));
};
return self;
function focusedSpecName() {
var specName;
(function memoizeFocusedSpec() {
if (specName) {
return;
}
var paramMap = [];
var params = self.jasmine.HtmlReporter.parameters(doc);
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
specName = paramMap.spec;
})();
return specName;
}
function createReporterDom(version) {
dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
dom.banner = self.createDom('div', { className: 'banner' },
self.createDom('span', { className: 'title' }, "Jasmine "),
self.createDom('span', { className: 'version' }, version)),
dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
dom.alert = self.createDom('div', {className: 'alert'},
self.createDom('span', { className: 'exceptions' },
self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
dom.results = self.createDom('div', {className: 'results'},
dom.summary = self.createDom('div', { className: 'summary' }),
dom.details = self.createDom('div', { id: 'details' }))
);
}
function noTryCatch() {
return window.location.search.match(/catch=false/);
}
function searchWithCatch() {
var params = self.jasmine.HtmlReporter.parameters(window.document);
var removed = false;
var i = 0;
while (!removed && i < params.length) {
if (params[i].match(/catch=/)) {
params.splice(i, 1);
removed = true;
}
i++;
}
if (env.catchingExceptions()) {
params.push("catch=false");
}
return params.join("&");
}
function setExceptionHandling() {
var chxCatch = document.getElementById('no_try_catch');
if (noTryCatch()) {
chxCatch.setAttribute('checked', true);
env.catchExceptions(false);
}
chxCatch.onclick = function() {
window.location.search = searchWithCatch();
};
}
};
jasmine.HtmlReporter.parameters = function(doc) {
var paramStr = doc.location.search.substring(1);
var params = [];
if (paramStr.length > 0) {
params = paramStr.split('&');
}
return params;
}
jasmine.HtmlReporter.sectionLink = function(sectionName, catchExceptions) {
var link = '?';
var params = [];
if (sectionName) {
params.push('spec=' + encodeURIComponent(sectionName));
}
if (!catchExceptions) {
params.push("catch=false");
}
if (params.length > 0) {
link += params.join("&");
}
return link;
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
jasmine.HtmlReporter.ReporterView = function(dom, jasmine, catchExceptions) {
this.startedAt = new Date();
this.runningSpecCount = 0;
this.completeSpecCount = 0;
this.passedCount = 0;
this.failedCount = 0;
this.skippedCount = 0;
this.jasmine = jasmine || {};
this.createResultsMenu = function() {
this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
' | ',
this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
this.summaryMenuItem.onclick = function() {
dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
};
this.detailsMenuItem.onclick = function() {
showDetails();
};
var totalSpecsDefined;
this.jasmineStarted = function(options) {
totalSpecsDefined = options.totalSpecsDefined || 0;
startTime = now();
};
this.addSpecs = function(specs, specFilter) {
this.totalSpecCount = specs.length;
var summary = createDom("div", {className: "summary"});
this.views = {
specs: {},
suites: {}
};
var topResults = new jasmine.ResultsNode({}, "", null),
currentParent = topResults;
for (var i = 0; i < specs.length; i++) {
var spec = specs[i];
this.views.specs[spec.id] = new this.jasmine.HtmlReporter.SpecView(spec, dom, this.views, this.jasmine, catchExceptions);
if (specFilter(spec)) {
this.runningSpecCount++;
}
}
this.suiteStarted = function(result) {
currentParent.addChild(result, "suite");
currentParent = currentParent.last();
};
this.specComplete = function(result) {
this.completeSpecCount++;
//TODO: this needs to work in order to get blanks for skipped specs.
// if (isUndefined(this.views.specs[result.id])) {
// this.views.specs[result.id] = new this.jasmine.HtmlReporter.SpecView(result, dom);
// }
var specView = this.views.specs[result.id];
switch (specView.status()) {
case 'passed':
this.passedCount++;
break;
case 'failed':
this.failedCount++;
break;
case 'disabled':
this.skippedCount++;
break;
}
specView.refresh();
this.refresh();
};
this.suiteComplete = function(suite) {
var suiteView = this.views.suites[suite.id];
if (isUndefined(suiteView)) {
this.suiteDone = function(result) {
if (currentParent == topResults) {
return;
}
suiteView.refresh();
currentParent = currentParent.parent;
};
this.refresh = function() {
if (isUndefined(this.resultsMenu)) {
this.createResultsMenu();
}
// currently running UI
if (isUndefined(this.runningAlert)) {
this.runningAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "runningAlert bar" });
dom.alert.appendChild(this.runningAlert);
}
this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
// skipped specs UI
if (isUndefined(this.skippedAlert)) {
this.skippedAlert = this.createDom('a', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "skippedAlert bar" });
}
this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.skippedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.skippedAlert);
}
// passing specs UI
if (isUndefined(this.passedAlert)) {
this.passedAlert = this.createDom('span', { href: this.jasmine.HtmlReporter.sectionLink(null, catchExceptions), className: "passingAlert bar" });
}
this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
// failing specs UI
if (isUndefined(this.failedAlert)) {
this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
}
this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
if (this.failedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.failedAlert);
dom.alert.appendChild(this.resultsMenu);
}
// summary info
this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
this.specStarted = function(result) {
currentParent.addChild(result, "spec");
};
this.complete = function() {
dom.alert.removeChild(this.runningAlert);
this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.failedCount === 0) {
dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
} else {
showDetails();
var failures = [];
this.specDone = function(result) {
if (result.status != "disabled") {
specsExecuted++;
}
dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
symbols.appendChild(createDom("li", {
className: result.status,
id: "spec_" + result.id}
));
if (result.status == "failed") {
failureCount++;
var failure =
createDom("div", {className: "spec-detail failed"},
createDom("a", {className: "description", title: result.fullName, href: specHref(result)}, result.fullName),
createDom("div", {className: "messages"})
);
var messages = failure.childNodes[1];
for (var i = 0; i < result.failedExpectations.length; i++) {
var expectation = result.failedExpectations[i];
var stack = (expectation.trace && expectation.trace.stack) || "";
messages.appendChild(createDom("div", {className: "result-message"}, expectation.message));
messages.appendChild(createDom("div", {className: "stack-trace"}, stack));
}
failures.push(failure);
}
};
this.jasmineDone = function() {
var elapsed = now() - startTime;
var banner = find(".banner")[0];
banner.appendChild(createDom("span", {className: "duration"}, "finished in " + elapsed / 1000 + "s"));
var alert = find(".alert")[0];
alert.appendChild(createDom("span", { className: "exceptions" },
createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"),
createDom("input", {
className: "raise",
id: "raise-exceptions",
type: "checkbox"
})
));
var checkbox = find("input")[0];
checkbox.checked = !env.catchingExceptions();
checkbox.onclick = function() {
queryString.setParam("catch", !checkbox.checked);
};
if (specsExecuted < totalSpecsDefined) {
var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all";
alert.appendChild(
createDom("span", {className: "bar skipped"},
createDom("a", {href: "?", title: "Run all specs"}, skippedMessage)
)
);
}
var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount),
statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed");
alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage));
var results = find(".results")[0];
results.appendChild(summary);
summaryList(topResults, summary);
function summaryList(resultsTree, domParent) {
var specListNode;
for (var i = 0; i < resultsTree.children.length; i++) {
var resultNode = resultsTree.children[i];
if (resultNode.type == "suite") {
var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id},
createDom("li", {className: "suite-detail"},
createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
)
);
summaryList(resultNode, suiteListNode);
domParent.appendChild(suiteListNode);
}
if (resultNode.type == "spec") {
if (domParent.getAttribute("class") != "specs") {
specListNode = createDom("ul", {className: "specs"});
domParent.appendChild(specListNode);
}
specListNode.appendChild(
createDom("li", {
className: resultNode.result.status,
id: "spec-" + resultNode.result.id
},
createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
)
);
}
}
}
if (failures.length) {
alert.appendChild(
createDom('span', {className: "menu bar spec-list"},
createDom("span", {}, "Spec List | "),
createDom('a', {className: "failures-menu", href: "#"}, "Failures")));
alert.appendChild(
createDom('span', {className: "menu bar failure-list"},
createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"),
createDom("span", {}, " | Failures ")));
find(".failures-menu")[0].onclick = function() {
setMenuModeTo('failure-list');
};
find(".spec-list-menu")[0].onclick = function() {
setMenuModeTo('spec-list');
};
setMenuModeTo('failure-list');
var failureNode = find(".failures")[0];
for (var i = 0; i < failures.length; i++) {
failureNode.appendChild(failures[i]);
}
}
};
return this;
function showDetails() {
if (dom.reporter.className.search(/showDetails/) === -1) {
dom.reporter.className += " showDetails";
function find(selector) {
if (selector.match(/^\./)) {
var className = selector.substring(1);
return getContainer().getElementsByClassName(className);
} else {
return getContainer().getElementsByTagName(selector);
}
}
function isUndefined(obj) {
return typeof obj === 'undefined';
}
function createDom(type, attrs, childrenVarArgs) {
var el = createElement(type);
function isDefined(obj) {
return !isUndefined(obj);
}
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
function specPluralizedFor(count) {
var str = count + " spec";
if (count > 1) {
str += "s"
}
return str;
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
jasmine.HtmlReporter.SpecView = function(spec, dom, views, jasmine, catchExceptions) {
this.spec = spec;
this.dom = dom;
this.views = views;
this.jasmine = jasmine || {};
this.catchExceptions = catchExceptions;
this.symbol = this.createDom('li', { className: 'pending' });
this.dom.symbolSummary.appendChild(this.symbol);
this.summary = this.createDom('div', { className: 'specSummary' },
this.createDom('a', {
className: 'description',
//TODO: sectionLink is a dependency passed in that knows about catchingExceptions
//so we don't pass catchExceptions everywhere.
href: this.jasmine.HtmlReporter.sectionLink(this.spec.getFullName(), catchExceptions),
title: this.spec.getFullName()
}, this.spec.description)
);
this.detail = this.createDom('div', { className: 'specDetail' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.getFullName())
);
};
jasmine.HtmlReporter.SpecView.prototype.status = function() {
return this.spec.status();
};
jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
this.symbol.className = this.status();
switch (this.status()) {
case 'disabled':
break;
case 'passed':
this.appendSummaryToSuiteDiv();
break;
case 'failed':
this.appendSummaryToSuiteDiv();
this.appendFailureDetail();
break;
}
};
jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
this.summary.className += ' ' + this.status();
this.appendToSummary(this.spec, this.summary);
};
jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
this.detail.className += ' ' + this.status();
var resultItems = this.spec.failedExpectations;
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && !result.passed) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
if (typeof child === 'string') {
el.appendChild(createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
}
if (messagesDiv.childNodes.length > 0) {
this.detail.appendChild(messagesDiv);
this.dom.details.appendChild(this.detail);
function pluralize(singular, count) {
var word = (count == 1 ? singular : singular + "s");
return "" + count + " " + word;
}
function specHref(result) {
return "?spec=" + encodeURIComponent(result.fullName);
}
function isFiltered() {
buildSpecFilter();
return !!specFilterPattern;
}
function buildSpecFilter() {
var specFilterParam = queryString.getParam("spec") || "";
specFilterPattern = new RegExp(specFilterParam);
}
function setMenuModeTo(mode) {
htmlReporterMain.setAttribute("class", "html-reporter " + mode);
}
};jasmine.ResultsNode = function(result, type, parent) {
this.result = result;
this.type = type;
this.parent = parent;
this.children = [];
this.addChild = function(result, type) {
this.children.push(new jasmine.ResultsNode(result, type, this));
};
this.last = function() {
return this.children[this.children.length-1];
}
};jasmine.QueryString = function(options) {
this.setParam = function(key, value) {
var paramMap = queryStringToParamMap();
paramMap[key] = value;
options.getWindowLocation().search = toQueryString(paramMap);
};
this.getParam = function(key) {
return queryStringToParamMap()[key];
};
return this;
function toQueryString(paramMap) {
var qStrPairs = [];
for (var prop in paramMap) {
qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop]));
}
return "?" + qStrPairs.join('&');
}
function queryStringToParamMap() {
var paramStr = options.getWindowLocation().search.substring(1),
params = [],
paramMap = {};
if (paramStr.length > 0) {
params = paramStr.split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
var value = decodeURIComponent(p[1]);
if (value === "true" || value === "false") {
value = JSON.parse(value);
}
paramMap[decodeURIComponent(p[0])] = value;
}
}
return paramMap;
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);
jasmine.HtmlReporter.SuiteView = function(suite, dom, views, jasmine, catchExceptions) {
this.suite = suite;
this.dom = dom;
this.views = views;
this.jasmine = jasmine || {};
this.catchExceptions = catchExceptions;
this.element = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'description', href: this.jasmine.HtmlReporter.sectionLink(this.suite.getFullName(), catchExceptions) }, this.suite.description)
);
this.appendToSummary(this.suite, this.element);
};
jasmine.HtmlReporter.SuiteView.prototype.status = function() {
return this.getSpecStatus(this.suite);
};
jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
this.element.className += " " + this.status();
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+51 -50
View File
@@ -1,52 +1,53 @@
body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
#HTMLReporter a { text-decoration: none; }
#HTMLReporter a:hover { text-decoration: underline; }
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
#HTMLReporter .version { color: #aaaaaa; }
#HTMLReporter .banner { margin-top: 14px; }
#HTMLReporter .duration { color: #aaaaaa; float: right; }
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
#HTMLReporter .runningAlert { background-color: #666666; }
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
#HTMLReporter .passingAlert { background-color: #a6b779; }
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
#HTMLReporter .failingAlert { background-color: #cf867e; }
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
#HTMLReporter .results { margin-top: 14px; }
#HTMLReporter #details { display: none; }
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter.showDetails .summary { display: none; }
#HTMLReporter.showDetails #details { display: block; }
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter .summary { margin-top: 14px; }
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
#HTMLReporter .description + .suite { margin-top: 0; }
#HTMLReporter .suite { margin-top: 14px; }
#HTMLReporter .suite a { color: #333333; }
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
#HTMLReporter .resultMessage span.result { display: block; }
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
.html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
.html-reporter a { text-decoration: none; }
.html-reporter a:hover { text-decoration: underline; }
.html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; }
.html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; }
.html-reporter .banner .version { margin-left: 14px; }
.html-reporter #jasmine_content { position: fixed; right: 100%; }
.html-reporter .version { color: #aaaaaa; }
.html-reporter .banner { margin-top: 14px; }
.html-reporter .duration { color: #aaaaaa; float: right; }
.html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; }
.html-reporter .symbol-summary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
.html-reporter .symbol-summary li.passed { font-size: 14px; }
.html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; }
.html-reporter .symbol-summary li.failed { line-height: 9px; }
.html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
.html-reporter .symbol-summary li.disabled { font-size: 14px; }
.html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; }
.html-reporter .symbol-summary li.pending { line-height: 11px; }
.html-reporter .symbol-summary li.pending:before { color: #aaaaaa; content: "-"; }
.html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
.html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
.html-reporter .bar.failed { background-color: #b03911; }
.html-reporter .bar.passed { background-color: #a6b779; }
.html-reporter .bar.skipped { background-color: #bababa; }
.html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; }
.html-reporter .bar.menu a { color: #333333; }
.html-reporter .bar a { color: white; }
.html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; }
.html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; }
.html-reporter .running-alert { background-color: #666666; }
.html-reporter .results { margin-top: 14px; }
.html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
.html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
.html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
.html-reporter.showDetails .summary { display: none; }
.html-reporter.showDetails #details { display: block; }
.html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
.html-reporter .summary { margin-top: 14px; }
.html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; }
.html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; }
.html-reporter .summary li.passed a { color: #5e7d00; }
.html-reporter .summary li.failed a { color: #b03911; }
.html-reporter .description + .suite { margin-top: 0; }
.html-reporter .suite { margin-top: 14px; }
.html-reporter .suite a { color: #333333; }
.html-reporter .failures .spec-detail { margin-bottom: 28px; }
.html-reporter .failures .spec-detail .description { display: block; color: white; background-color: #b03911; }
.html-reporter .result-message { padding-top: 14px; color: #333333; }
.html-reporter .result-message span.result { display: block; }
.html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
File diff suppressed because it is too large Load Diff
+169 -254
View File
@@ -1,292 +1,207 @@
describe("ConsoleReporter", function() {
//keep these literal. otherwise the test loses value as a test.
function green(str) {
return '\033[32m' + str + '\033[0m';
}
function red(str) {
return '\033[31m' + str + '\033[0m';
}
function yellow(str) {
return '\033[33m' + str + '\033[0m';
}
function prefixGreen(str) {
return '\033[32m' + str;
}
function prefixRed(str) {
return '\033[31m' + str;
}
var newline = "\n";
var passingSpec = { status: 'passed' },
failingSpec = { status: 'failed' },
skippedSpec = { status: 'disabled' },
passingRun = {
specs: function() {
return [null, null, null];
},
results: function() {
return {failedCount: 0, items_: [null, null, null]};
}
},
failingRun = {
specs: function() {
return [null, null, null];
},
results: function() {
return {
failedCount: 7, items_: [null, null, null]};
}
};
function repeatedlyInvoke(f, times) {
for (var i = 0; i < times; i++) f(times + 1);
}
function repeat(thing, times) {
var arr = [];
for (var i = 0; i < times; i++) arr.push(thing);
return arr;
}
function simulateRun(reporter, specResults, suiteResults, finalRunner, startTime, endTime) {
reporter.reportRunnerStarting();
for (var i = 0; i < specResults.length; i++) {
reporter.reportSpecResults(specResults[i]);
}
for (i = 0; i < suiteResults.length; i++) {
reporter.reportSuiteResults(suiteResults[i]);
}
reporter.runnerStartTime = startTime;
reporter.now = function() {
return endTime;
};
reporter.reportRunnerResults(finalRunner);
}
var reporter, out, done;
var out;
beforeEach(function() {
out = (function() {
var output = "";
return {
print:function(str) {
print: function(str) {
output += str;
},
getOutput:function() {
getOutput: function() {
return output;
},
clear: function() {
output = "";
}
};
})();
done = false;
reporter = new jasmine.ConsoleReporter(out.print, function(runner) {
done = true
});
}());
});
describe('Integration', function() {
it("prints the proper output under a pass scenario - small numbers.", function() {
simulateRun(reporter,
repeat(passingSpec, 3),
[],
{ },
1000,
1777
);
var output = out.getOutput();
expect(output).toMatch(/^Started/);
expect(output).toMatch(/\.\.\./);
expect(output).toMatch(/3 specs, 0 failures/);
it("reports that the suite has started to the console", function() {
var reporter = new jasmine.ConsoleReporter({
print: out.print
});
it("prints the proper output under a pass scenario. large numbers.", function() {
simulateRun(reporter,
repeat(passingSpec, 57),
[],
{},
1000,
1777);
reporter.jasmineStarted();
var output = out.getOutput();
expect(output).toMatch(/^Started/);
expect(output).toMatch(/\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\./);
expect(output).toMatch(/57 specs, 0 failures/);
});
it("prints the proper output under a failure scenario.", function() {
var base1 = extend({}, failingSpec),
failingSpec1 = extend(base1, {
fullName: 'The oven heats up',
failedExpectations: [
{trace:{stack:"stack trace one\n second line"}},
{trace:{stack:"stack trace two"}}
]}),
base2 = extend({}, failingSpec),
failingSpec2 = extend(base2, {
fullName: "The washing machine washes clothes",
failedExpectations: [
{trace:{stack:"stack trace one"}}
]});
simulateRun(reporter,
[failingSpec1, passingSpec, failingSpec2],
[
{description:"The oven",
results:function() {
return {
items_:[
{failedCount:2,
description:"heats up",
items_:[
{trace:{stack:"stack trace one\n second line"}},
{trace:{stack:"stack trace two"}}
]}
]
};
}},
{description:"The washing machine",
results:function() {
return {
items_:[
{failedCount:2,
description:"washes clothes",
items_:[
{trace:{stack:"stack trace one"}}
]}
]
};
}}
],
{
specs: function() {
return [null, null, null];
},
results:function() {
return {
items_: [null, null, null],
totalCount: 7,
failedCount: 2
};
}
},
1000,
1777);
var output = out.getOutput();
expect(output).toMatch(/^Started/);
expect(output).toMatch(/F\.F/);
expect(output).toMatch(/The oven heats up\n stack trace one\n second line\n stack trace two/);
expect(output).toMatch(/The washing machine washes clothes\n stack trace one/);
expect(output).toMatch(/3 specs, 2 failures/);
});
expect(out.getOutput()).toEqual("Started\n");
});
describe('When a Jasmine environment executes', function() {
beforeEach(function() {
reporter.reportRunnerStarting();
it("reports a passing spec as a dot", function() {
var reporter = new jasmine.ConsoleReporter({
print: out.print
});
it("should print 'Started' to the console", function() {
expect(out.getOutput()).toEqual("Started" + newline);
reporter.specDone({status: "passed"});
expect(out.getOutput()).toEqual(".");
});
it("does not report a disabled spec", function() {
var reporter = new jasmine.ConsoleReporter({
print: out.print
});
describe('when a spec reports', function() {
beforeEach(function() {
out.clear();
});
reporter.specDone({status: "disabled"});
it("prints a green dot if the spec passes", function() {
reporter.reportSpecResults(passingSpec);
expect(out.getOutput()).toEqual("");
});
expect(out.getOutput()).toMatch(/\./);
});
it("prints a red dot if the spec fails", function() {
reporter.reportSpecResults(failingSpec);
expect(out.getOutput()).toMatch(/F/);
});
it("prints a yellow star if the spec was skipped", function() {
reporter.reportSpecResults(skippedSpec);
expect(out.getOutput()).toMatch(/\*/);
});
it("reports a failing spec as an 'F'", function() {
var reporter = new jasmine.ConsoleReporter({
print: out.print
});
reporter.specDone({status: "failed"});
describe('and finishes', function() {
expect(out.getOutput()).toEqual("F");
});
describe('when reporting the execution time', function() {
it("reports a summary when done (singluar spec and time)", function() {
var fakeNow = jasmine.createSpy('fake Date.now'),
reporter = new jasmine.ConsoleReporter({
print: out.print,
now: fakeNow
});
it("prints the full finished message", function() {
reporter.now = function() {
return 1000;
};
reporter.reportRunnerStarting();
reporter.now = function() {
return 1777;
};
reporter.reportRunnerResults(failingRun);
expect(out.getOutput()).toContain("Finished in 0.777 seconds");
});
fakeNow.andReturn(500);
it("prints round time numbers correctly", function() {
function run(startTime, endTime) {
out.clear();
reporter.runnerStartTime = startTime;
reporter.now = function() {
return endTime;
};
reporter.reportRunnerResults(passingRun);
reporter.jasmineStarted();
reporter.specDone({status: "passed"});
fakeNow.andReturn(1500);
out.clear();
reporter.jasmineDone();
expect(out.getOutput()).toMatch(/1 spec, 0 failures/);
expect(out.getOutput()).toMatch("Finished in 1 second\n");
});
it("reports a summary when done (pluralized specs and seconds)", function() {
var fakeNow = jasmine.createSpy('fake Date.now'),
reporter = new jasmine.ConsoleReporter({
print: out.print,
now: fakeNow
});
fakeNow.andReturn(500);
reporter.jasmineStarted();
reporter.specDone({status: "passed"});
reporter.specDone({
status: "failed",
description: "with a failing spec",
fullName: "A suite with a failing spec",
failedExpectations: [
{
passed: false,
message: "Expected true to be false.",
expected: false,
actual: true,
trace: {
stack: "foo\nbar\nbaz"
}
run(1000, 11000);
expect(out.getOutput()).toContain("10 seconds");
run(1000, 2000);
expect(out.getOutput()).toContain("1 seconds");
run(1000, 1100);
expect(out.getOutput()).toContain("0.1 seconds");
run(1000, 1010);
expect(out.getOutput()).toContain("0.01 seconds");
run(1000, 1001);
expect(out.getOutput()).toContain("0.001 seconds");
});
});
describe("done callback", function() {
it("calls back when done", function() {
expect(done).toBeFalsy();
reporter.reportRunnerResults({
specs: function() {
return [null, null, null];
},
results:function() {
return {items_: [null, null, null], totalCount: 7, failedCount: 0};
}
});
expect(done).toBeTruthy();
});
});
}
]
});
out.clear();
fakeNow.andReturn(600);
reporter.jasmineDone();
expect(out.getOutput()).toMatch(/2 specs, 1 failure/);
expect(out.getOutput()).toMatch("Finished in 0.1 seconds\n");
});
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
}
it("reports a summary when done that includes stack traces for a failing suite", function() {
var reporter = new jasmine.ConsoleReporter({
print: out.print
});
reporter.jasmineStarted();
reporter.specDone({status: "passed"});
reporter.specDone({
status: "failed",
description: "with a failing spec",
fullName: "A suite with a failing spec",
failedExpectations: [
{
passed: false,
message: "Expected true to be false.",
expected: false,
actual: true,
trace: {
stack: "foo bar baz"
}
}
]
});
out.clear();
reporter.jasmineDone();
expect(out.getOutput()).toMatch(/foo bar baz/);
});
it("calls the onComplete callback when the suite is done", function() {
var onComplete = jasmine.createSpy('onComplete'),
reporter = new jasmine.ConsoleReporter({
print: out.print,
onComplete: onComplete
});
reporter.jasmineDone();
expect(onComplete).toHaveBeenCalled();
});
describe("with color", function() {
it("reports that the suite has started to the console", function() {
var reporter = new jasmine.ConsoleReporter({
print: out.print,
showColors: true
});
reporter.jasmineStarted();
expect(out.getOutput()).toEqual("Started\n");
});
it("reports a passing spec as a dot", function() {
var reporter = new jasmine.ConsoleReporter({
print: out.print,
showColors: true
});
reporter.specDone({status: "passed"});
expect(out.getOutput()).toEqual("\033[32m.\033[0m");
});
it("does not report a disabled spec", function() {
var reporter = new jasmine.ConsoleReporter({
print: out.print,
showColors: true
});
reporter.specDone({status: 'disabled'});
expect(out.getOutput()).toEqual("");
});
it("reports a failing spec as an 'F'", function() {
var reporter = new jasmine.ConsoleReporter({
print: out.print,
showColors: true
});
reporter.specDone({status: 'failed'});
expect(out.getOutput()).toEqual("\033[31mF\033[0m");
});
});
});
+152 -28
View File
@@ -1,12 +1,13 @@
describe("jasmine.Env", function() {
// TODO: Fix these unit tests!
describe("Env", function() {
var env;
beforeEach(function() {
env = new jasmine.Env();
env.updateInterval = 0;
});
describe('ids', function () {
it('nextSpecId should return consecutive integers, starting at 0', function () {
describe('ids', function() {
it('nextSpecId should return consecutive integers, starting at 0', function() {
expect(env.nextSpecId()).toEqual(0);
expect(env.nextSpecId()).toEqual(1);
expect(env.nextSpecId()).toEqual(2);
@@ -17,21 +18,21 @@ describe("jasmine.Env", function() {
var fakeReporter;
beforeEach(function() {
fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log"]);
fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["jasmineStarted"]);
});
describe('version', function () {
describe('version', function() {
var oldVersion;
beforeEach(function () {
beforeEach(function() {
oldVersion = jasmine.version_;
});
afterEach(function () {
afterEach(function() {
jasmine.version_ = oldVersion;
});
it('should raise an error if version is not set', function () {
it('should raise an error if version is not set', function() {
jasmine.version_ = null;
var exception;
try {
@@ -79,8 +80,8 @@ describe("jasmine.Env", function() {
it("should allow reporters to be registered", function() {
env.addReporter(fakeReporter);
env.reporter.log("message");
expect(fakeReporter.log).toHaveBeenCalledWith("message");
env.reporter.jasmineStarted();
expect(fakeReporter.jasmineStarted).toHaveBeenCalled();
});
});
@@ -138,8 +139,12 @@ describe("jasmine.Env", function() {
describe("even if there are several", function() {
beforeEach(function() {
env.addEqualityTester(function(a, b) { return jasmine.undefined; });
env.addEqualityTester(function(a, b) { return jasmine.undefined; });
env.addEqualityTester(function(a, b) {
return jasmine.undefined;
});
env.addEqualityTester(function(a, b) {
return jasmine.undefined;
});
});
it("should use normal equality rules", function() {
@@ -151,61 +156,180 @@ describe("jasmine.Env", function() {
it("should evaluate custom equality testers in the order they are declared", function() {
isEqual = false;
env.addEqualityTester(function(a, b) { return true; });
env.addEqualityTester(function(a, b) {
return true;
});
expect(env.equals_('abc', 'abc')).toBeFalsy();
});
});
});
});
describe("jasmine Env (integration)", function() {
describe("Env (integration)", function() {
it("Suites execute as expected (no nesting)", function() {
var env = new jasmine.Env(),
calls = [];
env.describe("A Suite", function() {
env.it("with a spec", function() {
calls.push("with a spec");
});
env.it("and another spec", function() {
calls.push("and another spec");
});
});
env.execute();
expect(calls).toEqual([
"with a spec",
"and another spec"
]);
});
it("Nested Suites execute as expected", function() {
var env = new jasmine.Env(),
calls = [];
env.describe("Outer suite", function() {
env.it("an outer spec", function() {
calls.push('an outer spec')
});
env.describe("Inner suite", function() {
env.it("an inner spec", function() {
calls.push('an inner spec');
});
env.it("another inner spec", function() {
calls.push('another inner spec');
});
});
});
env.execute();
expect(calls).toEqual([
'an outer spec',
'an inner spec',
'another inner spec'
]);
});
it("Multiple top-level Suites execute as expected", function() {
var env = new jasmine.Env(),
calls = [];
env.describe("Outer suite", function() {
env.it("an outer spec", function() {
calls.push('an outer spec')
});
env.describe("Inner suite", function() {
env.it("an inner spec", function() {
calls.push('an inner spec');
});
env.it("another inner spec", function() {
calls.push('another inner spec');
});
});
});
env.describe("Another outer suite", function() {
env.it("a 2nd outer spec", function() {
calls.push('a 2nd outer spec')
});
});
env.execute();
expect(calls).toEqual([
'an outer spec',
'an inner spec',
'another inner spec',
'a 2nd outer spec'
]);
});
it("Mock clock can be installed and used in tests", function() {
var setTimeout = jasmine.createSpy('setTimeout'),
globalTimeoutFn = jasmine.createSpy('globalTimeoutFn'),
fakeTimeoutFn = jasmine.createSpy('fakeTimeoutFn'),
env = new jasmine.Env({global: { setTimeout: setTimeout }});
var globalSetTimeout = jasmine.createSpy('globalSetTimeout'),
delayedFunctionForGlobalClock = jasmine.createSpy('delayedFunctionForGlobalClock'),
delayedFunctionForMockClock = jasmine.createSpy('delayedFunctionForMockClock'),
env = new jasmine.Env({global: { setTimeout: globalSetTimeout }});
env.describe("tests", function() {
env.it("test with mock clock", function() {
env.clock.install();
env.clock.setTimeout(fakeTimeoutFn, 100);
env.clock.setTimeout(delayedFunctionForMockClock, 100);
env.clock.tick(100);
});
env.it("test without mock clock", function() {
env.clock.setTimeout(globalTimeoutFn, 100);
env.clock.setTimeout(delayedFunctionForGlobalClock, 100);
});
});
expect(setTimeout).not.toHaveBeenCalled();
expect(fakeTimeoutFn).not.toHaveBeenCalled();
expect(globalSetTimeout).not.toHaveBeenCalled();
expect(delayedFunctionForMockClock).not.toHaveBeenCalled();
env.execute();
expect(fakeTimeoutFn).toHaveBeenCalled();
expect(setTimeout).toHaveBeenCalledWith(globalTimeoutFn, 100);
expect(delayedFunctionForMockClock).toHaveBeenCalled();
expect(globalSetTimeout).toHaveBeenCalledWith(delayedFunctionForGlobalClock, 100);
});
it("should report as expected", function() {
var env = new jasmine.Env(),
reporter = jasmine.createSpyObj('fakeReproter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
env.addReporter(reporter);
env.describe("A Suite", function() {
env.it("with a top level spec", function() {
env.expect(true).toBe(true);
});
env.describe("with a nested suite", function() {
env.xit("with a disabled spec", function() {
env.expect(true).toBe(true);
});
env.it("with a spec", function() {
env.expect(true).toBe(false);
});
});
});
env.execute();
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 3
});
var suiteResult = reporter.suiteStarted.calls[0].args[0];
expect(suiteResult.description).toEqual("A Suite");
expect(reporter.jasmineDone).toHaveBeenCalled();
});
it("should be possible to get full name from a spec", function() {
var env = new jasmine.Env({global: { setTimeout: setTimeout }}),
topLevelSpec, nestedSpec, doublyNestedSpec;
topLevelSpec, nestedSpec, doublyNestedSpec;
env.describe("my tests", function() {
topLevelSpec = env.it("are sometimes top level", function() {
});
env.describe("are sometimes", function() {
nestedSpec = env.it("singly nested", function() {
});
env.describe("even", function() {
doublyNestedSpec = env.it("doubly nested", function() {
});
});
});
});
env.execute();
expect(topLevelSpec.getFullName()).toBe("my tests are sometimes top level.");
expect(nestedSpec.getFullName()).toBe("my tests are sometimes singly nested.");
expect(doublyNestedSpec.getFullName()).toBe("my tests are sometimes even doubly nested.");
+100 -8
View File
@@ -1,5 +1,5 @@
describe('jasmine.jsApiReporter', function() {
describe('results', function () {
xdescribe('JsApiReporter (integration specs)', function() {
describe('results', function() {
var reporter, spec1, spec2;
var env;
var suite, nestedSuite, nestedSpec;
@@ -33,13 +33,13 @@ describe('jasmine.jsApiReporter', function() {
});
it('results() should return a hash of all results, indexed by spec id', function () {
it('results() should return a hash of all results, indexed by spec id', function() {
var expectedSpec1Results = {
result: "passed"
},
expectedSpec2Results = {
result: "failed"
};
result: "passed"
},
expectedSpec2Results = {
result: "failed"
};
expect(reporter.results()[spec1.id].result).toEqual('passed');
expect(reporter.results()[spec2.id].result).toEqual('failed');
});
@@ -78,3 +78,95 @@ describe('jasmine.jsApiReporter', function() {
});
});
});
describe("JsApiReporter", function() {
it("knows when a full environment is started", function() {
var reporter = new jasmine.JsApiReporter();
expect(reporter.started).toBe(false);
expect(reporter.finished).toBe(false);
reporter.jasmineStarted();
expect(reporter.started).toBe(true);
expect(reporter.finished).toBe(false);
});
it("knows when a full environment is done", function() {
var reporter = new jasmine.JsApiReporter();
expect(reporter.started).toBe(false);
expect(reporter.finished).toBe(false);
reporter.jasmineStarted();
reporter.jasmineDone();
expect(reporter.finished).toBe(true);
});
it("defaults to 'loaded' status", function() {
var reporter = new jasmine.JsApiReporter();
expect(reporter.status()).toEqual('loaded');
});
it("reports 'started' when Jasmine has started", function() {
var reporter = new jasmine.JsApiReporter();
reporter.jasmineStarted();
expect(reporter.status()).toEqual('started');
});
it("reports 'done' when Jasmine is done", function() {
var reporter = new jasmine.JsApiReporter();
reporter.jasmineDone();
expect(reporter.status()).toEqual('done');
});
it("tracks a suite", function() {
var reporter = new jasmine.JsApiReporter();
reporter.suiteStarted({
id: 123,
description: "A suite"
});
var suites = reporter.suites();
expect(suites).toEqual({123: {id: 123, description: "A suite"}});
reporter.suiteDone({
id: 123,
description: "A suite",
status: 'passed'
});
expect(suites).toEqual({123: {id: 123, description: "A suite", status: 'passed'}});
});
it("tracks a spec", function() {
var reporter = new jasmine.JsApiReporter();
reporter.specStarted({
id: 123,
description: "A spec"
});
var specs = reporter.specs();
expect(specs).toEqual({123: {id: 123, description: "A spec"}});
reporter.specDone({
id: 123,
description: "A spec",
status: 'passed'
});
expect(specs).toEqual({123: {id: 123, description: "A spec", status: 'passed'}});
});
});
-45
View File
@@ -1,45 +0,0 @@
describe("jasmine.MultiReporter", function() {
var multiReporter, fakeReporter1, fakeReporter2;
beforeEach(function() {
multiReporter = new jasmine.MultiReporter();
fakeReporter1 = originalJasmine.createSpyObj("fakeReporter1", ["reportSpecResults"]);
fakeReporter2 = originalJasmine.createSpyObj("fakeReporter2", ["reportSpecResults", "reportRunnerStarting"]);
multiReporter.addReporter(fakeReporter1);
multiReporter.addReporter(fakeReporter2);
});
it("should support all the method calls that jasmine.Reporter supports", function() {
var delegate = {};
multiReporter.addReporter(delegate);
addMatchers({
toDelegateMethod: function(methodName) {
delegate[methodName] = originalJasmine.createSpy(methodName);
this.actual[methodName]("whatever argument");
return delegate[methodName].wasCalled &&
delegate[methodName].mostRecentCall.args.length == 1 &&
delegate[methodName].mostRecentCall.args[0] == "whatever argument";
}
});
expect(multiReporter).toDelegateMethod('reportRunnerStarting');
expect(multiReporter).toDelegateMethod('reportRunnerResults');
expect(multiReporter).toDelegateMethod('reportSuiteResults');
expect(multiReporter).toDelegateMethod('reportSpecStarting');
expect(multiReporter).toDelegateMethod('reportSpecResults');
expect(multiReporter).toDelegateMethod('log');
});
it("should delegate to any and all subreporters", function() {
multiReporter.reportSpecResults('blah', 'foo');
expect(fakeReporter1.reportSpecResults).toHaveBeenCalledWith('blah', 'foo');
expect(fakeReporter2.reportSpecResults).toHaveBeenCalledWith('blah', 'foo');
});
it("should quietly skip delegating to any subreporters which lack the given method", function() {
multiReporter.reportRunnerStarting('blah', 'foo');
expect(fakeReporter2.reportRunnerStarting).toHaveBeenCalledWith('blah', 'foo');
});
});
+132
View File
@@ -0,0 +1,132 @@
describe("QueueRunner", function() {
it("runs all the functions it's passed", function() {
var calls = [],
fn1 = jasmine.createSpy('fn1'),
fn2 = jasmine.createSpy('fn2'),
queueRunner = new jasmine.QueueRunner({
fns: [fn1, fn2]
});
fn1.andCallFake(function() {
calls.push('fn1');
});
fn2.andCallFake(function() {
calls.push('fn2');
});
queueRunner.execute();
expect(calls).toEqual(['fn1', 'fn2']);
});
it("supports asynchronous functions, only advancing to next function after a done() callback", function() {
//TODO: it would be nice if spy arity could match the fake, so we could do something like:
//createSpy('asyncfn').andCallFake(function(done) {});
var onComplete = originalJasmine.createSpy('onComplete'),
beforeCallback = originalJasmine.createSpy('beforeCallback'),
fnCallback = originalJasmine.createSpy('fnCallback'),
afterCallback = originalJasmine.createSpy('afterCallback'),
fn1 = function(done) {
beforeCallback();
setTimeout(function() {
done()
}, 100);
},
fn2 = function(done) {
fnCallback();
setTimeout(function() {
done()
}, 100);
},
fn3 = function(done) {
afterCallback();
setTimeout(function() {
done()
}, 100);
},
queueRunner = new jasmine.QueueRunner({
fns: [fn1, fn2, fn3],
onComplete: onComplete
});
clock.install();
queueRunner.execute();
expect(beforeCallback).toHaveBeenCalled();
expect(fnCallback).not.toHaveBeenCalled();
expect(afterCallback).not.toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
clock.tick(100);
expect(fnCallback).toHaveBeenCalled();
expect(afterCallback).not.toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
clock.tick(100);
expect(afterCallback).toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
clock.tick(100);
expect(onComplete).toHaveBeenCalled();
});
it("calls an exception handler when an exception is thrown in a fn", function() {
var fn = function() {
throw new Error('fake error');
},
exceptionCallback = jasmine.createSpy('exception callback'),
queueRunner = new jasmine.QueueRunner({
fns: [fn],
onException: exceptionCallback
});
queueRunner.execute();
expect(exceptionCallback).toHaveBeenCalledWith(jasmine.any(Error));
});
it("rethrows an exception if told to", function() {
var fn = function() {
throw new Error('fake error');
},
queueRunner = new jasmine.QueueRunner({
fns: [fn],
catchingExceptions: function() { return false; }
});
expect(function() { queueRunner.execute(); }).toThrow();
});
it("calls a provided complete callback when done", function() {
var fn = jasmine.createSpy('fn'),
completeCallback = jasmine.createSpy('completeCallback'),
queueRunner = new jasmine.QueueRunner({
fns: [fn],
onComplete: completeCallback
});
queueRunner.execute();
expect(completeCallback).toHaveBeenCalled();
});
it("calls a provided garbage collection function with the complete callback when done", function() {
var fn = jasmine.createSpy('fn'),
completeCallback = jasmine.createSpy('completeCallback'),
encourageGC = jasmine.createSpy('encourageGC'),
queueRunner = new jasmine.QueueRunner({
fns: [fn],
encourageGC: encourageGC,
onComplete: completeCallback
});
queueRunner.execute();
expect(encourageGC).toHaveBeenCalledWith(completeCallback);
});
});
+40
View File
@@ -0,0 +1,40 @@
describe("ReportDispatcher", function() {
it("builds an interface of requested methods", function() {
var dispatcher = new jasmine.ReportDispatcher(['foo', 'bar', 'baz']);
expect(dispatcher.foo).toBeDefined();
expect(dispatcher.bar).toBeDefined();
expect(dispatcher.baz).toBeDefined();
});
it("dispatches requested methods to added reporters", function() {
var dispatcher = new jasmine.ReportDispatcher(['foo', 'bar']),
reporter = jasmine.createSpyObj('reporter', ['foo', 'bar']),
anotherReporter = jasmine.createSpyObj('reporter', ['foo', 'bar']);
dispatcher.addReporter(reporter);
dispatcher.addReporter(anotherReporter);
dispatcher.foo(123, 456);
expect(reporter.foo).toHaveBeenCalledWith(123, 456);
expect(anotherReporter.foo).toHaveBeenCalledWith(123, 456);
dispatcher.bar('a', 'b');
expect(reporter.bar).toHaveBeenCalledWith('a', 'b');
expect(anotherReporter.bar).toHaveBeenCalledWith('a', 'b');
});
it("does not dispatch to a reporter if the reporter doesn't accept the method", function() {
var dispatcher = new jasmine.ReportDispatcher(['foo']),
reporter = jasmine.createSpyObj('reporter', ['baz']);
dispatcher.addReporter(reporter);
expect(function() {
dispatcher.foo(123, 456);
}).not.toThrow();
});
});
-56
View File
@@ -1,56 +0,0 @@
describe('jasmine.Reporter', function() {
var env;
beforeEach(function() {
env = new jasmine.Env();
env.updateInterval = 0;
});
it('should get called from the test runner', function() {
env.describe('Suite for JSON Reporter with Callbacks', function () {
env.it('should be a test', function() {
this.runs(function () {
this.expect(true).toEqual(true);
});
});
env.it('should be a failing test', function() {
this.runs(function () {
this.expect(false).toEqual(true);
});
});
});
env.describe('Suite for JSON Reporter with Callbacks 2', function () {
env.it('should be a test', function() {
this.runs(function () {
this.expect(true).toEqual(true);
});
});
});
var foo = 0;
var bar = 0;
var baz = 0;
env.addReporter({
reportSpecResults: function() {
foo++;
},
reportSuiteResults: function() {
bar++;
},
reportRunnerResults: function() {
baz++;
}
});
var runner = env.currentRunner();
runner.execute();
expect(foo).toEqual(3); // 'foo was expected to be 3, was ' + foo);
expect(bar).toEqual(2); // 'bar was expected to be 2, was ' + bar);
expect(baz).toEqual(1); // 'baz was expected to be 1, was ' + baz);
});
});
-168
View File
@@ -1,168 +0,0 @@
describe('RunnerTest', function() {
var fakeTimer;
var env;
beforeEach(function() {
env = new jasmine.Env();
env.updateInterval = 0;
});
describe('beforeEach', function() {
it('should run before each spec for all suites', function() {
var foo;
env.beforeEach(function() {
foo = 0;
});
env.describe('suite 1', function() {
env.it('test 1-1', function() {
foo++;
expect(foo).toEqual(1);
});
env.it('test 1-2', function() {
foo++;
expect(foo).toEqual(1);
});
});
env.describe('suite 2', function() {
env.it('test 2-1', function() {
foo++;
expect(foo).toEqual(1);
});
});
env.currentRunner().execute();
});
it('should provide all specs', function() {
env.describe('suite 1', function() {
env.it('test 1-1', function() {
});
env.it('test 1-2', function() {
});
});
env.describe('suite 2', function() {
env.it('test 2-1', function() {
});
});
expect(env.currentRunner().specs().length).toEqual(3);
});
});
describe('afterEach', function() {
it('should run after each spec for all suites', function() {
var foo = 3;
env.afterEach(function() {
foo = foo - 1;
});
env.describe('suite 1', function() {
env.it('test 1-1', function() {
expect(foo).toEqual(3);
});
env.it('test 1-2', function() {
expect(foo).toEqual(2);
});
});
env.describe('suite 2', function() {
env.it('test 2-1', function() {
expect(foo).toEqual(1);
});
});
env.currentRunner().execute();
});
it('should run after a failing spec', function () {
var afterEach = originalJasmine.createSpy();
env.afterEach(afterEach);
env.describe('suite',function() {
env.it('fails', function() {
this.expect(true).toBe(false);
});
}).execute();
expect(afterEach).toHaveBeenCalled();
});
});
it('should ignore suites that have been x\'d', function() {
var disabledDescribe = jasmine.createSpy('xdescribe');
env.xdescribe('one suite description', disabledDescribe);
env.currentRunner().execute();
expect(disabledDescribe).not.toHaveBeenCalled();
});
describe('reporting', function() {
var fakeReporter;
beforeEach(function() {
fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting", "reportRunnerResults"]);
env.addReporter(fakeReporter);
});
it('should report runner results when the runner has completed running', function() {
var specSpy = originalJasmine.createSpy('spec').andCallFake(function() {
expect(fakeReporter.reportRunnerResults).not.toHaveBeenCalled();
});
env.describe('description', function() {
env.it('should be a test', specSpy);
});
env.currentRunner().execute();
expect(specSpy).toHaveBeenCalled();
expect(fakeReporter.reportRunnerResults).toHaveBeenCalledWith(env.currentRunner());
});
});
it("should report when the tests start running", function() {
var fakeReporter = originalJasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting"]);
env.addReporter(fakeReporter);
var runner = new jasmine.Runner(env);
runner.arbitraryVariable = 'foo';
spyOn(runner.queue, 'start');
expect(fakeReporter.reportRunnerStarting).not.toHaveBeenCalled();
runner.execute();
expect(fakeReporter.reportRunnerStarting).toHaveBeenCalled();
var reportedRunner = fakeReporter.reportRunnerStarting.mostRecentCall.args[0];
expect(reportedRunner.arbitraryVariable).toEqual('foo');
expect(runner.queue.start).toHaveBeenCalled();
});
describe("when suites are nested", function() {
var suite1, suite2, suite3;
function suiteNames(suites) {
var suiteDescriptions = [];
for (var i = 0; i < suites.length; i++) {
suiteDescriptions.push(suites[i].getFullName());
}
return suiteDescriptions;
}
beforeEach(function() {
suite1 = env.describe("suite 1", function() {
suite2 = env.describe("suite 2", function() {
});
});
suite3 = env.describe("suite 3", function() {
});
});
it("#suites should return a flat array of all suites, including nested suites", function() {
var suites = env.currentRunner().suites();
expect(suiteNames(suites)).toEqual([suite1.getFullName(), suite2.getFullName(), suite3.getFullName()]);
});
it("#topLevelSuites should return a flat array of all top-level suites only", function() {
var suites = env.currentRunner().topLevelSuites();
expect(suiteNames(suites)).toEqual([suite1.getFullName(), suite3.getFullName()]);
});
});
});
+27 -13
View File
@@ -1,3 +1,4 @@
// TODO: This should really be part of the Env Integration Spec
describe("jasmine spec running", function () {
var env;
var fakeTimer;
@@ -74,11 +75,11 @@ describe("jasmine spec running", function () {
var actions = [];
env.beforeEach(function () {
actions.push('runner beforeEach');
actions.push('topSuite beforeEach');
});
env.afterEach(function () {
actions.push('runner afterEach');
actions.push('topSuite afterEach');
});
env.describe('Something', function() {
@@ -131,33 +132,33 @@ describe("jasmine spec running", function () {
var expected = [
"runner beforeEach",
"topSuite beforeEach",
"outer beforeEach",
"outer it 1",
"outer afterEach",
"runner afterEach",
"topSuite afterEach",
"runner beforeEach",
"topSuite beforeEach",
"outer beforeEach",
"inner 1 beforeEach",
"inner 1 it",
"inner 1 afterEach",
"outer afterEach",
"runner afterEach",
"topSuite afterEach",
"runner beforeEach",
"topSuite beforeEach",
"outer beforeEach",
"outer it 2",
"outer afterEach",
"runner afterEach",
"topSuite afterEach",
"runner beforeEach",
"topSuite beforeEach",
"outer beforeEach",
"inner 2 beforeEach",
"inner 2 it",
"inner 2 afterEach",
"outer afterEach",
"runner afterEach"
"topSuite afterEach"
];
expect(actions).toEqual(expected);
});
@@ -219,16 +220,30 @@ describe("jasmine spec running", function () {
expect(actions).toEqual(expected);
});
it("shouldn't run disabled suites", function() {
var specInADisabledSuite = originalJasmine.createSpy("specInADisabledSuite"),
suite = env.describe('A Suite', function() {
env.xdescribe('with a disabled suite', function(){
env.it('disabled spec', specInADisabledSuite);
});
});
suite.execute();
expect(specInADisabledSuite).not.toHaveBeenCalled();
});
it("shouldn't run disabled tests", function() {
var disabledSpec = originalJasmine.createSpy('disabledSpec'),
suite = env.describe('default current suite', function() {
env.xit('disabled spec').runs(disabledSpec);
env.xit('disabled spec', disabledSpec);
});
suite.execute();
expect(disabledSpec).not.toHaveBeenCalled();
});
it("should recover gracefully when there are errors in describe functions", function() {
// TODO: is this useful? It doesn't catch syntax errors
xit("should recover gracefully when there are errors in describe functions", function() {
var specs = [];
var superSimpleReporter = new jasmine.Reporter();
superSimpleReporter.reportSpecResults = function(result) {
@@ -275,5 +290,4 @@ describe("jasmine spec running", function () {
));
});
});
+137 -186
View File
@@ -1,233 +1,184 @@
describe("Spec", function() {
it("reports results for passing tests", function() {
var resultCallback = originalJasmine.createSpy('resultCallback'),
expectationFactory = function(actual, spec) {
expect(actual).toBe('some-actual');
return {
pass: function() {
spec.addExpectationResult(true);
}
}
},
spec = new jasmine.Spec({
description: 'my test',
id: 'some-id',
fn: function() {
this.expect('some-actual').pass();
},
resultCallback: resultCallback,
expectationFactory: expectationFactory
});
it("delegates execution to a QueueRunner", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
spec = new jasmine.Spec({
description: 'my test',
id: 'some-id',
fn: function() {},
queueRunner: fakeQueueRunner
});
spec.execute();
expect(resultCallback).toHaveBeenCalledWith({
id: "some-id",
status: "passed",
description: "my test",
failedExpectations: []
});
});
it("reports results for failing tests", function() {
var resultCallback = originalJasmine.createSpy('resultCallback'),
expectationFactory = function(actual, spec) {
expect(actual).toBe('some-actual');
return {
fail: function() {
spec.addExpectationResult(true);
}
}
},
spec = new jasmine.Spec({
description: 'my test',
id: 'some-id',
fn: function() {
this.expect('some-actual').fail();
},
resultCallback: resultCallback,
expectationFactory: expectationFactory
});
spec.execute();
expect(resultCallback).toHaveBeenCalledWith({
id: "some-id",
status: "passed",
description: "my test",
failedExpectations: []
});
expect(fakeQueueRunner).toHaveBeenCalled();
});
it("executes before fns, after fns", function() {
var before = originalJasmine.createSpy('before'),
after = originalJasmine.createSpy('after'),
fn = originalJasmine.createSpy('test body').andCallFake(function() {
expect(before).toHaveBeenCalled();
expect(after).not.toHaveBeenCalled();
});
spec = new jasmine.Spec({
fn: fn,
beforeFns: function() {
return [before]
},
afterFns: function() {
return [after]
}
});
it("should call the start callback on execution", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
beforesWereCalled = false,
startCallback = originalJasmine.createSpy('startCallback'),
spec = new jasmine.Spec({
id: 123,
description: 'foo bar',
fn: function() {},
onStart: startCallback,
queueRunner: fakeQueueRunner
});
spec.execute();
expect(before).toHaveBeenCalled();
expect(before.mostRecentCall.object).toBe(spec);
expect(fn).toHaveBeenCalled();
expect(after).toHaveBeenCalled();
expect(after.mostRecentCall.object).toBe(spec);
expect(startCallback).toHaveBeenCalledWith(spec);
});
it("passes an optional callback to spec bodies, befores, and afters", function() {
//TODO: it would be nice if spy arity could match the fake, so we could do something like:
//createSpy('asyncfn').andCallFake(function(done) {});
var resultCallback = originalJasmine.createSpy('resultCallback'),
beforeCallback = originalJasmine.createSpy('beforeCallback'),
fnCallback = originalJasmine.createSpy('fnCallback'),
afterCallback = originalJasmine.createSpy('afterCallback'),
before = function(done) {
beforeCallback();
setTimeout(function() { done() }, 100);
},
fn = function(done) {
fnCallback();
setTimeout(function() { done() }, 100);
},
after = function(done) {
afterCallback();
setTimeout(function() { done() }, 100);
},
spec = new jasmine.Spec({
resultCallback: resultCallback,
fn: fn,
beforeFns: function() {
return [before]
},
afterFns: function() {
return [after]
}
});
clock.install();
it("should call the start callback on execution but before any befores are called", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
beforesWereCalled = false,
startCallback = originalJasmine.createSpy('start-callback').andCallFake(function() {
expect(beforesWereCalled).toBe(false);
}),
spec = new jasmine.Spec({
fn: function() {},
beforeFns: function() {
return [function() {
beforesWereCalled = true
}]
},
onStart: startCallback,
queueRunner: fakeQueueRunner
});
spec.execute();
expect(beforeCallback).toHaveBeenCalled();
expect(fnCallback).not.toHaveBeenCalled();
expect(afterCallback).not.toHaveBeenCalled();
expect(resultCallback).not.toHaveBeenCalled();
expect(startCallback).toHaveBeenCalled();
});
clock.tick(100);
it("provides all before fns and after fns to be run", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
before = originalJasmine.createSpy('before'),
after = originalJasmine.createSpy('after'),
fn = originalJasmine.createSpy('test body').andCallFake(function() {
expect(before).toHaveBeenCalled();
expect(after).not.toHaveBeenCalled();
}),
spec = new jasmine.Spec({
fn: fn,
beforeFns: function() {
return [before]
},
afterFns: function() {
return [after]
},
queueRunner: fakeQueueRunner
});
expect(fnCallback).toHaveBeenCalled();
expect(afterCallback).not.toHaveBeenCalled();
expect(resultCallback).not.toHaveBeenCalled();
spec.execute();
clock.tick(100);
var allSpecFns = fakeQueueRunner.mostRecentCall.args[0].fns;
expect(allSpecFns).toEqual([before, fn, after]);
});
expect(afterCallback).toHaveBeenCalled();
expect(resultCallback).not.toHaveBeenCalled();
it("can be disabled, but still calls callbacks", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
clock.tick(100);
startCallback = originalJasmine.createSpy('startCallback'),
specBody = originalJasmine.createSpy('specBody'),
resultCallback = originalJasmine.createSpy('resultCallback'),
spec = new jasmine.Spec({
onStart:startCallback,
fn: specBody,
resultCallback: resultCallback,
queueRunner: fakeQueueRunner
});
spec.disable();
expect(spec.status()).toBe('disabled');
spec.execute();
expect(startCallback).not.toHaveBeenCalled();
expect(fakeQueueRunner).not.toHaveBeenCalled();
expect(specBody).not.toHaveBeenCalled();
expect(resultCallback).toHaveBeenCalled();
});
it("status returns null by default", function() {
it("should call the results callback on execution complete", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
startCallback = originalJasmine.createSpy('startCallback'),
specBody = originalJasmine.createSpy('specBody'),
resultCallback = originalJasmine.createSpy('resultCallback'),
spec = new jasmine.Spec({
onStart:startCallback,
fn: specBody,
resultCallback: resultCallback,
description: "with a spec",
getSpecName: function() { return "a suite with a spec"},
queueRunner: fakeQueueRunner
});
spec.disable();
expect(spec.status()).toBe('disabled');
spec.execute();
expect(startCallback).not.toHaveBeenCalled();
expect(fakeQueueRunner).not.toHaveBeenCalled();
expect(specBody).not.toHaveBeenCalled();
expect(resultCallback).toHaveBeenCalledWith({
id: spec.id,
status: 'disabled',
description: 'with a spec',
fullName: 'a suite with a spec',
failedExpectations: []
});
});
it("should call the done callback on execution complete", function() {
var done = originalJasmine.createSpy('done callback'),
spec = new jasmine.Spec({
fn: function() {},
catchExceptions: function() { return false; },
resultCallback: function() {},
queueRunner: function(attrs) { attrs.onComplete(); }
});
spec.execute(done);
expect(done).toHaveBeenCalled();
});
it("#status returns null by default", function() {
var spec = new jasmine.Spec({});
expect(spec.status()).toBeNull();
});
it("status returns passed if all expectations in the spec have passed", function() {
it("#status returns passed if all expectations in the spec have passed", function() {
var spec = new jasmine.Spec({});
spec.addExpectationResult(true);
expect(spec.status()).toBe('passed');
});
it("status returns failed if any expectations in the spec have failed", function() {
it("#status returns failed if any expectations in the spec have failed", function() {
var spec = new jasmine.Spec({});
spec.addExpectationResult(true);
spec.addExpectationResult(false);
expect(spec.status()).toBe('failed');
});
it("throws when an exception occurs in the spec fn if catchExceptions is false", function() {
//TODO: one day we should pass a stack with this.
var resultCallback = originalJasmine.createSpy('resultCallback'),
spec = new jasmine.Spec({
fn: function() {
throw new Error();
},
catchExceptions: false,
resultCallback: resultCallback
});
expect(function() {
spec.execute();
}).toThrow();
});
it("should call the start callback before any befores are called", function() {
var beforesWereCalled = false,
startCallback = originalJasmine.createSpy('start-callback').andCallFake(function() {
expect(beforesWereCalled).toBe(false);
}),
spec = new jasmine.Spec({
fn: function() {
},
beforeFns: function() {
return [function() {
beforesWereCalled = true
}]
},
startCallback: startCallback,
catchExceptions: false,
resultCallback: function() {
}
});
spec.execute();
expect(startCallback).toHaveBeenCalled();
});
it("can return its full name", function() {
var spec = new jasmine.Spec({
var spec;
spec = new jasmine.Spec({
getSpecName: function(passedVal) {
expect(passedVal).toBe(spec);
// expect(passedVal).toBe(spec); TODO: a exec time, spec is undefined WTF?
return 'expected val';
}
});
expect(spec.getFullName()).toBe('expected val');
});
it("can be disabled", function() {
var startCallback = originalJasmine.createSpy('startCallback'),
specBody = originalJasmine.createSpy('specBody'),
resultCallback = originalJasmine.createSpy('resultCallback'),
spec = new jasmine.Spec({
startCallback: startCallback,
fn: specBody,
resultCallback: resultCallback
});
spec.disable();
expect(spec.status()).toBe('disabled');
spec.execute();
expect(startCallback).not.toHaveBeenCalled();
expect(specBody).not.toHaveBeenCalled();
//TODO: with expected data.
expect(resultCallback).toHaveBeenCalled();
});
});
+149 -144
View File
@@ -1,118 +1,4 @@
//describe('Suite', function() {
// var env;
//
// beforeEach(function() {
// env = new jasmine.Env();
// env.updateInterval = 0;
// });
//
// describe('Specs', function () {
// var suite;
//
// beforeEach(function() {
// suite = env.describe('Suite 1', function () {
// env.it('Spec 1', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// env.it('Spec 2', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// env.describe('Suite 2', function () {
// env.it('Spec 3', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// });
// env.it('Spec 4', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// });
// });
//
// it('#specs should return all immediate children that are specs.', function () {
// var suiteSpecs = suite.specs();
// expect(suiteSpecs.length).toEqual(3);
// expect(suiteSpecs[0].description).toEqual('Spec 1');
// expect(suiteSpecs[1].description).toEqual('Spec 2');
// expect(suiteSpecs[2].description).toEqual('Spec 4');
// });
//
// it("#suites should return all immediate children that are suites.", function() {
// var nestedSuites = suite.suites();
// expect(nestedSuites.length).toEqual(1);
// expect(nestedSuites[0].description).toEqual('Suite 2');
// });
//
// it("#children should return all immediate children including suites and specs.", function() {
// var children = suite.children();
// expect(children.length).toEqual(4);
// expect(children[0].description).toEqual('Spec 1');
// expect(children[1].description).toEqual('Spec 2');
// expect(children[2].description).toEqual('Suite 2');
// expect(children[3].description).toEqual('Spec 4');
// });
// });
//
// describe('SpecCount', function () {
//
// it('should keep a count of the number of specs that are run', function() {
// var suite = env.describe('one suite description', function () {
// env.it('should be a test', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// env.it('should be another test', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// env.it('should be a third test', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// });
//
// expect(suite.specs().length).toEqual(3);
// });
//
// it('specCount should be correct even with runs/waits blocks', function() {
// var suite = env.describe('one suite description', function () {
// env.it('should be a test', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// env.it('should be another test', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// this.waits(10);
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// env.it('should be a third test', function() {
// this.runs(function () {
// this.expect(true).toEqual(true);
// });
// });
// });
//
// expect(suite.specs().length).toEqual(3);
// });
// });
//});
describe("Suite (unit tests)", function() {
describe("Suite", function() {
it("keeps its id", function() {
var env = new jasmine.Env(),
@@ -139,15 +25,16 @@ describe("Suite (unit tests)", function() {
var env = new jasmine.Env(),
parentSuite = new jasmine.Suite({
env: env,
description: "I am a suite"
description: "I am a parent suite",
parentSuite: jasmine.createSpy('pretend top level suite')
}),
suite = new jasmine.Suite({
env: env,
description: "I am a suite",
parentSuite: parentSuite
});
suite = new jasmine.Suite({
env: env,
description: "I am a suite"
});
expect(suite.getFullName()).toEqual("I am a suite");
expect(suite.getFullName()).toEqual("I am a parent suite I am a suite");
});
it("adds before functions in order of needed execution", function() {
@@ -182,9 +69,15 @@ describe("Suite (unit tests)", function() {
it("adds specs", function() {
var env = new jasmine.Env(),
fakeQueue = {
add: jasmine.createSpy()
},
suite = new jasmine.Suite({
env: env,
description: "I am a suite"
description: "I am a suite",
queueFactory: function() {
return fakeQueue
}
}),
fakeSpec = {};
@@ -192,34 +85,146 @@ describe("Suite (unit tests)", function() {
suite.addSpec(fakeSpec);
expect(suite.specs.length).toEqual(1);git
expect(suite.specs.length).toEqual(1);
});
});
// TODO:
describe("Suite (acceptance)", function() {
it("can execute and run all of its befores, specs, and afters", function() {
it("adds suites", function() {
var env = new jasmine.Env(),
calls = [];
env.describe("A suite", function() {
env.beforeEach(function() {
calls.push('before');
fakeQueue = {
add: jasmine.createSpy()
},
suite = new jasmine.Suite({
env: env,
description: "I am a suite",
queueFactory: function() {
return fakeQueue
}
}),
anotherSuite = new jasmine.Suite({
env: env,
description: "I am another suite",
queueFactory: function() {
return fakeQueue
}
});
env.it("with a spec", function() {
calls.push('spec');
});
expect(suite.suites.length).toEqual(0);
env.afterEach(function() {
calls.push('after');
});
});
suite.addSuite(anotherSuite);
env.execute();
expect(calls).toEqual(['before', 'spec', 'after']);
expect(suite.suites.length).toEqual(1);
});
it("can be disabled", function() {
var env = new jasmine.Env(),
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
suite = new jasmine.Suite({
env: env,
description: "with a child suite",
queueRunner: fakeQueueRunner
});
suite.disable();
expect(suite.disabled).toBe(true);
suite.execute();
expect(fakeQueueRunner).not.toHaveBeenCalled();
});
it("delegates execution of its specs and suites", function() {
var env = new jasmine.Env(),
parentSuiteDone = jasmine.createSpy('parent suite done'),
fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'),
parentSuite = new jasmine.Suite({
env: env,
description: "I am a parent suite",
queueRunner: fakeQueueRunnerForParent
}),
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
suite = new jasmine.Suite({
env: env,
description: "with a child suite",
queueRunner: fakeQueueRunner
}),
fakeSpec1 = {
execute: jasmine.createSpy('fakeSpec1')
};
spyOn(suite, "execute");
parentSuite.addSpec(fakeSpec1);
parentSuite.addSuite(suite);
parentSuite.execute(parentSuiteDone);
var parentSuiteFns = fakeQueueRunnerForParent.mostRecentCall.args[0].fns;
parentSuiteFns[0]();
expect(fakeSpec1.execute).toHaveBeenCalled();
parentSuiteFns[1]();
expect(suite.execute).toHaveBeenCalled();
});
it("calls a provided onStart callback when starting", function() {
var env = new jasmine.Env(),
suiteStarted = jasmine.createSpy('suiteStarted'),
fakeQueueRunner = function(attrs) { attrs.onComplete(); },
suite = new jasmine.Suite({
env: env,
description: "with a child suite",
onStart: suiteStarted,
queueRunner: fakeQueueRunner
}),
fakeSpec1 = {
execute: jasmine.createSpy('fakeSpec1')
};
suite.execute();
expect(suiteStarted).toHaveBeenCalledWith(suite);
});
it("calls a provided onComplete callback when done", function() {
var env = new jasmine.Env(),
suiteCompleted = jasmine.createSpy('parent suite done'),
fakeQueueRunner = function(attrs) { attrs.onComplete(); },
suite = new jasmine.Suite({
env: env,
description: "with a child suite",
queueRunner: fakeQueueRunner
}),
fakeSpec1 = {
execute: jasmine.createSpy('fakeSpec1')
};
suite.execute(suiteCompleted);
expect(suiteCompleted).toHaveBeenCalled();
});
it("calls a provided result callback when done", function() {
var env = new jasmine.Env(),
suiteResultsCallback = jasmine.createSpy('suite result callback'),
fakeQueueRunner = function(attrs) { attrs.onComplete(); },
suite = new jasmine.Suite({
env: env,
description: "with a child suite",
queueRunner: fakeQueueRunner,
resultCallback: suiteResultsCallback
}),
fakeSpec1 = {
execute: jasmine.createSpy('fakeSpec1')
};
suite.execute();
expect(suiteResultsCallback).toHaveBeenCalledWith({
id: suite.id,
status: '',
description: "with a child suite",
fullName: "with a child suite"
});
});
});
-155
View File
@@ -1,155 +0,0 @@
describe("HtmlReporter", function() {
var env;
var htmlReporter;
var body;
var fakeDocument;
beforeEach(function() {
env = new jasmine.Env();
env.updateInterval = 0;
body = document.createElement("body");
fakeDocument = { body: body, location: { search: "" } };
htmlReporter = new jasmine.HtmlReporter(fakeDocument, null, {
catchingExceptions: function() { return true; },
catchExceptions: function() { }
}, {yieldForRender: function(fn) { fn() }});
});
function fakeSpec(name) {
return {
getFullName: function() {
return name;
}
};
}
function findElements(divs, withClass) {
var els = [];
for (var i = 0; i < divs.length; i++) {
if (divs[i].className == withClass) els.push(divs[i]);
}
return els;
}
function findElement(divs, withClass) {
var els = findElements(divs, withClass);
if (els.length > 0) {
return els[0];
}
throw new Error("couldn't find div with class " + withClass);
}
it("should run only specs beginning with spec parameter", function() {
fakeDocument.location.search = "?spec=run%20this";
expect(htmlReporter.specFilter(fakeSpec("run this"))).toBeTruthy();
expect(htmlReporter.specFilter(fakeSpec("not the right spec"))).toBeFalsy();
expect(htmlReporter.specFilter(fakeSpec("not run this"))).toBeFalsy();
});
describe("running without any specs", function() {
var runner;
beforeEach(function() {
runner = env.currentRunner();
env.addReporter(htmlReporter);
});
it("should not error", function() {
var exec = function() {
runner.execute();
};
expect(exec).not.toThrow();
});
});
describe('Matcher reporting', function() {
var getResultMessageDiv = function(body) {
var divs = body.getElementsByTagName("div");
for (var i = 0; i < divs.length; i++) {
if (divs[i].className.match(/resultMessage/)) {
return divs[i];
}
}
};
var runner, spec, fakeTimer;
beforeEach(function() {
env.addReporter(htmlReporter);
});
describe('toContain', function() {
it('should show actual and expected', function() {
env.describe('test suite', function() {
env.it('spec 0', function() {
this.expect('foo').toContain('bar');
});
});
env.execute();
var resultEl = getResultMessageDiv(body);
expect(resultEl.innerHTML).toMatch(/foo/);
expect(resultEl.innerHTML).toMatch(/bar/);
});
});
});
describe("failure messages (integration)", function() {
var spec, results, expectationResult;
it("should add the failure message to the DOM (non-toEquals matchers)", function() {
env.describe("suite", function() {
env.it("will have log messages", function() {
this.expect('a').toBeNull();
});
});
env.addReporter(htmlReporter);
env.execute();
var divs = body.getElementsByTagName("div");
var errorDiv = findElement(divs, 'resultMessage fail');
expect(errorDiv.innerHTML).toMatch(/Expected 'a' to be null/);
});
it("should add the failure message to the DOM (non-toEquals matchers) html escaping", function() {
env.describe("suite", function() {
env.it("will have log messages", function() {
this.expect('1 < 2').toBeNull();
});
});
env.addReporter(htmlReporter);
env.execute();
var divs = body.getElementsByTagName("div");
var errorDiv = findElement(divs, 'resultMessage fail');
expect(errorDiv.innerHTML).toMatch(/Expected '1 &lt; 2' to be null/);
});
});
describe("duplicate example names", function() {
it("should report failures correctly", function() {
var suite1 = env.describe("suite", function() {
env.it("will have log messages", function() {
this.expect(true).toBeFalsy();
});
});
var suite2 = env.describe("suite", function() {
env.it("will have log messages", function() {
this.expect(true).toBeTruthy();
});
});
env.addReporter(htmlReporter);
env.execute();
var divs = body.getElementsByTagName("div");
var failedSpecDiv = findElement(divs, 'specDetail failed');
expect(failedSpecDiv.className).toEqual('specDetail failed');
expect(failedSpecDiv.innerHTML).not.toContain("this one passes!");
});
});
});
+571
View File
@@ -0,0 +1,571 @@
describe("New HtmlReporter", function() {
it("builds the initial DOM elements, including the title banner", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
// Main top-level elements
var divs = container.getElementsByTagName("div");
expect(findElement(divs, "html-reporter")).toBeTruthy();
expect(findElement(divs, "banner")).toBeTruthy();
expect(findElement(divs, "alert")).toBeTruthy();
expect(findElement(divs, "results")).toBeTruthy();
var uls = container.getElementsByTagName("ul");
expect(findElement(uls, "symbol-summary")).toBeTruthy();
// title banner
var banner = container.getElementsByClassName("banner")[0];
var title = banner.getElementsByClassName("title")[0];
expect(title.innerHTML).toMatch(/Jasmine/);
var version = banner.getElementsByClassName("version")[0];
expect(version.innerHTML).toMatch(/\d+\.\d+\.\d+\srevision\s+\d+/);
});
describe("when a spec is done", function() {
it("reports the status symbol of a disabled spec", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
getContainer = function() { return container; },
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.specDone({id: 789, status: "disabled"});
var statuses = container.getElementsByClassName('symbol-summary')[0];
var specEl = statuses.getElementsByTagName('li')[0];
expect(specEl.getAttribute("class")).toEqual("disabled");
expect(specEl.getAttribute("id")).toEqual("spec_789");
});
it("reports the status symbol of a passing spec", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
getContainer = function() { return container; },
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.specDone({id: 123, status: "passed"});
var statuses = container.getElementsByClassName("symbol-summary")[0];
var specEl = statuses.getElementsByTagName("li")[0];
expect(specEl.getAttribute("class")).toEqual("passed");
expect(specEl.getAttribute("id")).toEqual("spec_123");
});
it("reports the status symbol of a failing spec", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
getContainer = function() { return container; },
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.specDone({
id: 345,
status: "failed",
failedExpectations: []
});
var statuses = container.getElementsByClassName('symbol-summary')[0];
var specEl = statuses.getElementsByTagName('li')[0];
expect(specEl.getAttribute("class")).toEqual("failed");
expect(specEl.getAttribute("id")).toEqual("spec_345");
});
});
describe("when Jasmine is done", function() {
it("reports the run time", function() {
var env = new jasmine.Env(),
fakeNow = jasmine.createSpy('fake Date.now'),
container = document.createElement("div"),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
now: fakeNow,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
fakeNow.andReturn(500);
reporter.jasmineStarted({});
fakeNow.andReturn(600);
reporter.jasmineDone();
var banner = container.getElementsByClassName("banner")[0];
var duration = banner.getElementsByClassName("duration")[0];
expect(duration.innerHTML).toMatch(/finished in 0.1s/);
});
it("reports the suite and spec names with status", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.jasmineStarted({});
reporter.suiteStarted({
id: 1,
description: "A Suite",
fullName: "A Suite"
});
var specResult = {
id: 123,
description: "with a spec",
fullName: "A Suite with a spec",
status: "passed"
};
reporter.specStarted(specResult);
reporter.specDone(specResult);
reporter.suiteStarted({
id: 2,
description: "inner suite",
fullName: "A Suite inner suite"
});
var specResult = {
id: 124,
description: "with another spec",
fullName: "A Suite inner suite with another spec",
status: "passed"
};
reporter.specStarted(specResult);
reporter.specDone(specResult);
reporter.suiteDone({id: 2});
specResult = {
id: 209,
description: "with a failing spec",
fullName: "A Suite inner with a failing spec",
status: "failed",
failedExpectations: []
};
reporter.specStarted(specResult);
reporter.specDone(specResult);
reporter.suiteDone({id: 1});
reporter.jasmineDone();
var summary = container.getElementsByClassName("summary")[0];
console.error("=============>", summary);
expect(summary.childNodes.length).toEqual(1);
var outerSuite = summary.childNodes[0];
expect(outerSuite.childNodes.length).toEqual(4);
var classes = [];
for (var i = 0; i < outerSuite.childNodes.length; i++) {
var node = outerSuite.childNodes[i];
classes.push(node.getAttribute("class"));
}
expect(classes).toEqual(["suite-detail", "specs", "suite", "specs"]);
var suiteDetail = outerSuite.childNodes[0];
var suiteLink = suiteDetail.childNodes[0];
expect(suiteLink.text).toEqual("A Suite");
expect(suiteLink.getAttribute('href')).toEqual("?spec=A%20Suite");
var specs = outerSuite.childNodes[1];
var spec = specs.childNodes[0];
expect(spec.getAttribute("class")).toEqual("passed");
expect(spec.getAttribute("id")).toEqual("spec-123");
var specLink = spec.childNodes[0];
expect(specLink.text).toEqual("with a spec");
expect(specLink.getAttribute("href")).toEqual("?spec=A%20Suite%20with%20a%20spec");
// expect(specLink.getAttribute("title")).toEqual("A Suite with a spec");
});
describe("UI for raising/catching exceptions", function() {
it("should be unchecked if the env is catching", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.jasmineDone();
var raisingExceptionsUI = container.getElementsByClassName("raise")[0];
expect(raisingExceptionsUI.checked).toBe(false);
});
it("should be checked if the env is not catching", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
fakeQueryString = "",
fakeWindowLocation = {
search: fakeQueryString
},
queryString = new jasmine.QueryString({
getWindowLocation: function() { return fakeWindowLocation; }
}),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
queryString: queryString,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
env.catchExceptions(false);
reporter.jasmineDone();
var raisingExceptionsUI = container.getElementsByClassName("raise")[0];
expect(raisingExceptionsUI.checked).toBe(true);
});
it("should affect the query param for catching exceptions", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
fakeQueryString = "",
fakeWindowLocation = {
search: fakeQueryString
},
queryString = new jasmine.QueryString({
getWindowLocation: function() { return fakeWindowLocation; }
}),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
queryString: queryString,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.jasmineDone();
var input = container.getElementsByClassName("raise")[0];
input.click();
expect(queryString.getParam("catch")).toEqual(false);
input.click();
expect(queryString.getParam("catch")).toEqual(true);
});
});
describe("and all specs pass", function() {
var env, container, reporter;
beforeEach(function() {
env = new jasmine.Env();
container = document.createElement("div");
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.jasmineStarted({});
reporter.specDone({
id: 123,
description: "with a spec",
fullName: "A Suite with a spec",
status: "passed"
});
reporter.specDone({
id: 124,
description: "with another spec",
fullName: "A Suite inner suite with another spec",
status: "passed"
});
reporter.jasmineDone();
});
it("reports the specs counts", function() {
var alert = container.getElementsByClassName("alert")[0];
var alertBars = alert.getElementsByClassName("bar");
expect(alertBars.length).toEqual(1);
expect(alertBars[0].getAttribute('class')).toMatch(/passed/);
expect(alertBars[0].innerHTML).toMatch(/2 specs, 0 failures/);
});
it("reports no failure details", function() {
var specFailure = container.getElementsByClassName("failures")[0];
expect(specFailure.childNodes.length).toEqual(0);
});
});
describe("and some tests fail", function() {
var env, container, reporter;
beforeEach(function() {
env = new jasmine.Env();
container = document.createElement("div");
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.jasmineStarted({});
var passingResult = {id: 123, status: "passed"};
reporter.specStarted(passingResult);
reporter.specDone(passingResult);
var failingResult = {
id: 124,
status: "failed",
description: "a failing spec",
fullName: "a suite with a failing spec",
failedExpectations: [
{
message: "a failure message",
trace: {
stack: "a stack trace"
}
}
]
};
reporter.specStarted(failingResult);
reporter.specDone(failingResult);
reporter.jasmineDone();
});
it("reports the specs counts", function() {
var alert = container.getElementsByClassName("alert")[0];
var alertBars = alert.getElementsByClassName("bar");
expect(alertBars[0].getAttribute('class')).toMatch(/failed/);
expect(alertBars[0].innerHTML).toMatch(/2 specs, 1 failure/);
});
it("reports failure messages and stack traces", function() {
var specFailures = container.getElementsByClassName("failures")[0];
var failure = specFailures.childNodes[0];
expect(failure.getAttribute("class")).toMatch(/failed/);
expect(failure.getAttribute("class")).toMatch(/spec-detail/);
var specLink = failure.childNodes[0];
expect(specLink.getAttribute("class")).toEqual("description");
expect(specLink.getAttribute("title")).toEqual("a suite with a failing spec");
expect(specLink.getAttribute("href")).toEqual("?spec=a%20suite%20with%20a%20failing%20spec");
var message = failure.childNodes[1].childNodes[0];
expect(message.getAttribute("class")).toEqual("result-message");
expect(message.innerHTML).toEqual("a failure message");
var stackTrace = failure.childNodes[1].childNodes[1];
expect(stackTrace.getAttribute("class")).toEqual("stack-trace");
expect(stackTrace.innerHTML).toEqual("a stack trace");
});
it("allows switching between failure details and the spec summary", function() {
var menuBar = container.getElementsByClassName("bar")[1];
expect(menuBar.getAttribute("class")).not.toMatch(/hidden/);
var link = menuBar.getElementsByTagName('a')[0];
expect(link.text).toEqual("Failures");
expect(link.getAttribute("href")).toEqual("#");
});
it("sets the reporter to 'Failures List' mode", function() {
var reporterNode = container.getElementsByClassName("html-reporter")[0];
expect(reporterNode.getAttribute("class")).toMatch("failure-list");
});
});
});
describe("specFilter", function() {
it("always returns true if there is no filter", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
fakeQueryString = "",
fakeWindowLocation = {
search: fakeQueryString
},
queryString = new jasmine.QueryString({
getWindowLocation: function() { return fakeWindowLocation; }
}),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
queryString: queryString,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
}),
fakeSpec = {
getFullName: function() { return "A suite with a spec"}
};
expect(reporter.specFilter(fakeSpec)).toBe(true);
});
it("matches a focused spec name", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
fakeWindowLocation = {
search: "?spec=A%20suite%20with%20a%20spec"
},
queryString = new jasmine.QueryString({
getWindowLocation: function() { return fakeWindowLocation; }
}),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
queryString: queryString,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
}),
fakeMatchingSpec = {
getFullName: function() { return "A suite with a spec"}
},
fakeNonMatchingSpec = {
getFullName: function() { return "sasquatch"}
};
expect(reporter.specFilter(fakeMatchingSpec)).toBe(true);
expect(reporter.specFilter(fakeNonMatchingSpec)).toBe(false);
});
it("matches a substring of a spec name", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
fakeWindowLocation = {
search: "?spec=with"
},
queryString = new jasmine.QueryString({
getWindowLocation: function() { return fakeWindowLocation; }
}),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
queryString: queryString,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
}),
fakeMatchingSpec = {
getFullName: function() { return "A suite with a spec" }
},
fakeNonMatchingSpec = {
getFullName: function() { return "sasquatch"}
};
expect(reporter.specFilter(fakeMatchingSpec)).toBe(true);
expect(reporter.specFilter(fakeNonMatchingSpec)).toBe(false);
});
});
describe("when specs are filtered", function() {
it("shows the count of run specs and defined specs", function() {
var env = new jasmine.Env(),
container = document.createElement("div"),
getContainer = function() { return container; },
reporter = new jasmine.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.jasmineStarted({
totalSpecsDefined: 2
});
reporter.specDone({
id: 123,
description: "with a spec",
fullName: "A Suite with a spec",
status: "passed"
});
reporter.specDone({
id: 124,
description: "with another spec",
fullName: "A Suite inner suite with another spec",
status: "disabled"
});
reporter.jasmineDone();
var skippedBar = container.getElementsByClassName("bar")[0];
expect(skippedBar.getAttribute("class")).toMatch(/skipped/);
var runAllLink = skippedBar.childNodes[0];
expect(runAllLink.getAttribute("href")).toEqual("?");
expect(runAllLink.text).toMatch(/Ran \d+ of \d+ specs - run all/);
});
});
// try/catch
// utility functions
function findElements(divs, withClass) {
var els = [];
for (var i = 0; i < divs.length; i++) {
if (divs[i].className == withClass) els.push(divs[i]);
}
return els;
}
function findElement(divs, withClass) {
var els = findElements(divs, withClass);
if (els.length > 0) {
return els[0];
}
throw new Error("couldn't find div with class " + withClass);
}
});
+43
View File
@@ -0,0 +1,43 @@
describe("QueryString", function() {
describe("#setParam", function() {
it("sets the query string to include the given key/value pair", function() {
var windowLocation = {
search: ""
},
queryString = new jasmine.QueryString({
getWindowLocation: function() { return windowLocation }
});
queryString.setParam("foo", "bar baz");
expect(windowLocation.search).toMatch(/foo=bar%20baz/);
});
});
describe("#getParam", function() {
it("returns the value of the requested key", function() {
var windowLocation = {
search: "?baz=quux%20corge"
},
queryString = new jasmine.QueryString({
getWindowLocation: function() { return windowLocation }
});
expect(queryString.getParam("baz")).toEqual("quux corge");
});
it("returns null if the key is not present", function() {
var windowLocation = {
search: ""
},
queryString = new jasmine.QueryString({
getWindowLocation: function() { return windowLocation }
});
expect(queryString.getParam("baz")).toBeFalsy();
});
});
});
+62
View File
@@ -0,0 +1,62 @@
describe("ResultsNode", function() {
it("wraps a result", function() {
var fakeResult = {
id: 123,
message: "foo"
},
node = new jasmine.ResultsNode(fakeResult, "suite", null);
expect(node.result).toBe(fakeResult);
expect(node.type).toEqual("suite");
});
it("can add children with a type", function() {
var fakeResult = {
id: 123,
message: "foo"
},
fakeChildResult = {
id: 456,
message: "bar"
},
node = new jasmine.ResultsNode(fakeResult, "suite", null);
node.addChild(fakeChildResult, "spec");
expect(node.children.length).toEqual(1);
expect(node.children[0].result).toEqual(fakeChildResult);
expect(node.children[0].type).toEqual("spec");
});
it("has a pointer back to its parent ResultNode", function() {
var fakeResult = {
id: 123,
message: "foo"
},
fakeChildResult = {
id: 456,
message: "bar"
},
node = new jasmine.ResultsNode(fakeResult, "suite", null);
node.addChild(fakeChildResult, "spec");
expect(node.children[0].parent).toBe(node);
});
it("can provide the most recent child", function() {
var fakeResult = {
id: 123,
message: "foo"
},
fakeChildResult = {
id: 456,
message: "bar"
},
node = new jasmine.ResultsNode(fakeResult, "suite", null);
node.addChild(fakeChildResult, "spec");
expect(node.last()).toBe(node.children[node.children.length - 1]);
});
});
+1 -7
View File
@@ -5,20 +5,14 @@ src_dir:
src_files:
- 'core/base.js'
- 'core/util.js'
- 'core/Reporter.js'
#end of known dependencies
- 'core/Spec.js'
- 'core/Env.js'
- 'core/JsApiReporter.js'
- 'core/Matchers.js'
- 'core/MultiReporter.js'
- 'core/NestedResults.js'
- 'core/PrettyPrinter.js'
- 'core/Queue.js'
- 'core/Runner.js'
- 'core/Suite.js'
- 'html/HtmlReporterHelpers.js'
- 'html/HtmlReporter.js'
- 'html/**.js'
- '**/*.js'
stylesheets:
boot_dir: 'spec/support'
+5 -1
View File
@@ -86,7 +86,11 @@ jasmine.executeSpecs = function(specs, done, isVerbose, showColors) {
}
var jasmineEnv = jasmine.getEnv();
var consoleReporter = new jasmine.ConsoleReporter(util.print, done, showColors);
var consoleReporter = new jasmine.ConsoleReporter({
print: util.print,
onComplete: done,
showColors: showColors
});
jasmineEnv.addReporter(consoleReporter);
jasmineEnv.execute();
+6 -2
View File
@@ -91,7 +91,11 @@ jasmine.executeSpecs = function(specs, done, isVerbose, showColors) {
}
var jasmineEnv = jasmine.getEnv();
var consoleReporter = new jasmine.ConsoleReporter(util.print, done, showColors);
var consoleReporter = new jasmine.ConsoleReporter({
print: util.print,
onComplete: done,
showColors: showColors
});
jasmineEnv.addReporter(consoleReporter);
jasmineEnv.execute();
@@ -168,7 +172,7 @@ process.argv.forEach(function(arg) {
var specs = jasmine.getAllSpecFiles(__dirname, new RegExp("Spec.js$"));
var domIndependentSpecs = [];
for (var i = 0; i < specs.length; i++) {
if (fs.readFileSync(specs[i], "utf8").indexOf("document.createElement") < 0) {
if (!specs[i].match('html')) {
domIndependentSpecs.push(specs[i]);
}
}
+41 -40
View File
@@ -1,54 +1,55 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Spec Runner: Jasmine Core</title>
<title>Jasmine Spec Runner: Jasmine Core</title>
<link rel="shortcut icon" type="image/png" href="../images/jasmine_favicon.png">
<link rel="shortcut icon" type="image/png" href="../images/jasmine_favicon.png">
<link href="../lib/jasmine-core/jasmine.css" rel="stylesheet"/>
<script type="text/javascript" src="../lib/jasmine-core/jasmine.js"></script>
<script type="text/javascript" src="../lib/jasmine-core/jasmine-html.js"></script>
<script type="text/javascript" src="../lib/jasmine-core/boot/boot.js"></script>
<link href="../lib/jasmine-core/jasmine.css" rel="stylesheet"/>
<script type="text/javascript" src="../lib/jasmine-core/jasmine.js"></script>
<script type="text/javascript" src="../lib/jasmine-core/jasmine-html.js"></script>
<script type="text/javascript" src="../lib/jasmine-core/boot/boot.js"></script>
<!--This file is not included in jasmine.js - but let's put it here for now -->
<script type="text/javascript" src="../src/console/ConsoleReporter.js"></script>
<!--This file is not included in jasmine.js - but let's put it here for now -->
<script type="text/javascript" src="../src/console/ConsoleReporter.js"></script>
<script type="text/javascript">
//shim for our tests using originalJasmine.createSpy and the like that should really be using globals defined in boot.
var originalJasmine = jasmine;
</script>
<script type="text/javascript">
//shim for our tests using originalJasmine.createSpy and the like that should really be using globals defined in boot.
var originalJasmine = jasmine;
</script>
<script type="text/javascript">
// yes, really keep this here to keep us honest, but only for jasmine's own runner! [xw]
undefined = "diz be undefined yo";
</script>
<script type="text/javascript">
// yes, really keep this here to keep us honest, but only for jasmine's own runner! [xw]
undefined = "diz be undefined yo";
</script>
<!-- include spec files here... -->
<script type="text/javascript" src=".././spec/core/CustomMatchersSpec.js"></script>
<script type="text/javascript" src=".././spec/core/EnvSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ExceptionsSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ExceptionFormatterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ExpectationResultSpec.js"></script>
<script type="text/javascript" src=".././spec/core/JsApiReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/MatchersSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ClockSpec.js"></script>
<script type="text/javascript" src=".././spec/core/DelayedFunctionSchedulerSpec.js"></script>
<script type="text/javascript" src=".././spec/core/MultiReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/PrettyPrintSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/RunnerSpec.js"></script>
<script type="text/javascript" src=".././spec/core/SpecRunningSpec.js"></script>
<script type="text/javascript" src=".././spec/core/SpecSpec.js"></script>
<script type="text/javascript" src=".././spec/core/SpySpec.js"></script>
<script type="text/javascript" src=".././spec/core/SuiteSpec.js"></script>
<script type="text/javascript" src=".././spec/core/UtilSpec.js"></script>
<script type="text/javascript" src=".././spec/html/HTMLReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/html/MatchersHtmlSpec.js"></script>
<script type="text/javascript" src=".././spec/html/PrettyPrintHtmlSpec.js"></script>
<script type="text/javascript" src=".././spec/console/ConsoleReporterSpec.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src=".././spec/console/ConsoleReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ClockSpec.js"></script>
<script type="text/javascript" src=".././spec/core/CustomMatchersSpec.js"></script>
<script type="text/javascript" src=".././spec/core/DelayedFunctionSchedulerSpec.js"></script>
<script type="text/javascript" src=".././spec/core/EnvSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ExceptionFormatterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ExceptionsSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ExpectationResultSpec.js"></script>
<script type="text/javascript" src=".././spec/core/JsApiReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/MatchersSpec.js"></script>
<script type="text/javascript" src=".././spec/core/PrettyPrintSpec.js"></script>
<script type="text/javascript" src=".././spec/core/QueueRunnerSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ReportDispatcherSpec.js"></script>
<script type="text/javascript" src=".././spec/core/SpecRunningSpec.js"></script>
<script type="text/javascript" src=".././spec/core/SpecSpec.js"></script>
<script type="text/javascript" src=".././spec/core/SpySpec.js"></script>
<script type="text/javascript" src=".././spec/core/SuiteSpec.js"></script>
<script type="text/javascript" src=".././spec/core/UtilSpec.js"></script>
<script type="text/javascript" src=".././spec/html/MatchersHtmlSpec.js"></script>
<script type="text/javascript" src="html/HtmlReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/html/PrettyPrintHtmlSpec.js"></script>
<script type="text/javascript" src=".././spec/html/QueryStringSpec.js"></script>
<script type="text/javascript" src=".././spec/html/ResultsNodeSpec.js"></script>
</head>
<body>
+65 -161
View File
@@ -1,55 +1,72 @@
jasmine.ConsoleReporter = function(print, doneCallback, showColors) {
//inspired by mhevery's jasmine-node reporter
//https://github.com/mhevery/jasmine-node
doneCallback = doneCallback || function() {};
var ansi = {
jasmine.ConsoleReporter = function(options) {
var print = options.print,
showColors = options.showColors || false,
onComplete = options.onComplete || function() {},
now = options.now || function() { return new Date().getTime();},
startTime = 0,
specCount,
failureCount,
failedSpecs = [],
ansi = {
green: '\033[32m',
red: '\033[31m',
yellow: '\033[33m',
none: '\033[0m'
},
language = {
spec: "spec",
failure: "failure"
};
function coloredStr(color, str) {
return showColors ? (ansi[color] + str + ansi.none) : str;
}
this.jasmineStarted = function() {
startTime = now();
specCount = 0;
failureCount = 0;
print("Started");
printNewline();
};
function greenStr(str) {
return coloredStr("green", str);
}
this.jasmineDone = function() {
var elapsed = now() - startTime;
function redStr(str) {
return coloredStr("red", str);
}
printNewline();
for (var i = 0; i < failedSpecs.length; i++) {
specFailureDetails(failedSpecs[i]);
}
function yellowStr(str) {
return coloredStr("yellow", str);
}
printNewline();
var specCounts = specCount + " " + plural("spec", specCount) + ", " +
failureCount + " " + plural("failure", failureCount);
print(specCounts);
function newline() {
printNewline();
var seconds = elapsed / 1000;
print("Finished in " + seconds + " " + plural("second", seconds));
printNewline();
onComplete();
};
this.specDone = function(result) {
specCount++;
if (result.status == "passed") {
print(colored("green", '.'));
return;
}
if (result.status == "failed") {
failureCount++;
failedSpecs.push(result);
print(colored("red", 'F'));
}
};
return this;
function printNewline() {
print("\n");
}
function started() {
print("Started");
newline();
}
function greenDot() {
print(greenStr("."));
}
function redF() {
print(redStr("F"));
}
function yellowStar() {
print(yellowStr("*"));
function colored(color, str) {
return showColors ? (ansi[color] + str + ansi.none) : str;
}
function plural(str, count) {
@@ -73,129 +90,16 @@ jasmine.ConsoleReporter = function(print, doneCallback, showColors) {
return newArr.join("\n");
}
// function specFailureDetails(suiteDescription, specDescription, stackTraces) {
// newline();
// print(suiteDescription + " " + specDescription);
// newline();
// for (var i = 0; i < stackTraces.length; i++) {
// print(indent(stackTraces[i], 2));
// newline();
// }
// }
function specFailureDetails(specFailure) {
newline();
print(specFailure.fullName);
newline();
for (var i = 0; i < specFailure.failedExpectations.length; i++) {
var failedExpectation = specFailure.failedExpectations[i];
function specFailureDetails(result) {
printNewline();
print(result.fullName);
for (var i = 0; i < result.failedExpectations.length; i++) {
var failedExpectation = result.failedExpectations[i];
printNewline();
print(indent(failedExpectation.trace.stack, 2));
newline();
}
}
function finished(elapsed) {
newline();
print("Finished in " + elapsed / 1000 + " seconds");
}
function summary(colorF, specs, failed) {
newline();
print(colorF(specs + " " + plural(language.spec, specs) + ", " +
failed + " " + plural(language.failure, failed)));
newline();
newline();
}
function greenSummary(specs, failed) {
summary(greenStr, specs, failed);
}
function redSummary(specs, failed) {
summary(redStr, specs, failed);
}
function fullSuiteDescription(suite) {
var fullDescription = suite.description;
if (suite.parentSuite) fullDescription = fullSuiteDescription(suite.parentSuite) + " " + fullDescription;
return fullDescription;
}
this.now = function() {
return new Date().getTime();
};
this.reportRunnerStarting = function() {
this.runnerStartTime = this.now();
started();
};
this.reportSpecStarting = function() { /* do nothing */
};
this.specFailures = [];
this.specCount = 0;
this.reportSpecResults = function(result) {
this.specCount++;
if (result.status === 'disabled') {
yellowStar();
} else if (result.status === 'passed') {
greenDot();
} else {
redF();
this.specFailures.push(result);
}
};
// this.suiteResults = [];
this.reportSuiteResults = function(suite) {
// var suiteResult = {
// description: fullSuiteDescription(suite),
// failedSpecResults: []
// };
// suite.results().items_.forEach(function(spec) {
// if (spec.failedCount > 0 && spec.description) suiteResult.failedSpecResults.push(spec);
// });
// this.suiteResults.push(suiteResult);
};
// function eachSpecFailure(suiteResults, callback) {
// for (var i = 0; i < suiteResults.length; i++) {
// var suiteResult = suiteResults[i];
// for (var j = 0; j < suiteResult.failedSpecResults.length; j++) {
// var failedSpecResult = suiteResult.failedSpecResults[j];
// var stackTraces = [];
// for (var k = 0; k < failedSpecResult.items_.length; k++) stackTraces.push(failedSpecResult.items_[k].trace.stack);
// callback(suiteResult.description, failedSpecResult.description, stackTraces);
// }
// }
// }
function eachSpecFailure(specResult, callback) {
for (var i = 0; i < suiteResults.length; i++) {
var suiteResult = suiteResults[i];
for (var j = 0; j < suiteResult.failedSpecResults.length; j++) {
var failedSpecResult = suiteResult.failedSpecResults[j];
var stackTraces = [];
for (var k = 0; k < failedSpecResult.items_.length; k++) stackTraces.push(failedSpecResult.items_[k].trace.stack);
callback(suiteResult.description, failedSpecResult.description, stackTraces);
}
}
}
this.reportRunnerResults = function(runner) {
newline();
for (var i = 0; i < this.specFailures.length; i++) {
specFailureDetails(this.specFailures[i]);
}
finished(this.now() - this.runnerStartTime);
var summaryFunction = this.specFailures.length === 0 ? greenSummary : redSummary;
summaryFunction(this.specCount, this.specFailures.length);
doneCallback(!!this.specFailures.length);
};
printNewline();
}
};
+15 -15
View File
@@ -1,19 +1,19 @@
jasmine.Clock = function(global, delayedFunctionScheduler) {
var self = this,
realTimingFunctions = {
setTimeout: global.setTimeout,
clearTimeout: global.clearTimeout,
setInterval: global.setInterval,
clearInterval: global.clearInterval
},
fakeTimingFunctions = {
setTimeout: setTimeout,
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval
},
timer = realTimingFunctions,
installed = false;
realTimingFunctions = {
setTimeout: global.setTimeout,
clearTimeout: global.clearTimeout,
setInterval: global.setInterval,
clearInterval: global.clearInterval
},
fakeTimingFunctions = {
setTimeout: setTimeout,
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval
},
timer = realTimingFunctions,
installed = false;
self.install = function() {
installed = true;
@@ -72,7 +72,7 @@ jasmine.Clock = function(global, delayedFunctionScheduler) {
}
function setTimeout(fn, delay) {
return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments,2));
return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
}
function clearTimeout(id) {
+135 -127
View File
@@ -1,8 +1,3 @@
/**
* Environment for Jasmine
*
* @constructor
*/
(function() {
jasmine.Env = function(options) {
options = options || {};
@@ -10,21 +5,23 @@
var global = options.global || jasmine.getGlobal();
var catchExceptions = true;
var encourageGC = options.encourageGarbageCollection || encourageGarbageCollection;
this.clock = new jasmine.Clock(global, new jasmine.DelayedFunctionScheduler());
var suiteConstructor = jasmine.Suite;
var isSuite = function(thing) {
return thing instanceof suiteConstructor;
};
this.jasmine = jasmine;
this.currentRunner_ = new jasmine.Runner(this, isSuite);
this.spies_ = [];
this.currentSpec = null;
this.undefined = jasmine.undefined;
this.reporter = new jasmine.MultiReporter();
this.reporter = new jasmine.ReportDispatcher([
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
this.lastUpdate = 0;
this.specFilter = function() {
@@ -49,18 +46,18 @@
return expect;
};
var startCallback = function(spec) {
var specStarted = function(spec) {
self.currentSpec = spec;
self.reporter.reportSpecStarting(spec);
self.reporter.specStarted(spec.result);
};
var beforeFns = function(currentSuite) {
return function() {
var befores = [];
for (var suite = currentSuite; suite; suite = suite.parentSuite) {
befores = befores.concat(suite.before_)
befores = befores.concat(suite.beforeFns)
}
return befores.concat(self.currentRunner_.before_).reverse();
return befores.reverse();
}
};
@@ -68,9 +65,9 @@
return function() {
var afters = [];
for (var suite = currentSuite; suite; suite = suite.parentSuite) {
afters = afters.concat(suite.after_)
afters = afters.concat(suite.afterFns)
}
return afters.concat(self.currentRunner_.after_)
return afters;
}
};
@@ -87,60 +84,14 @@
return buildExpectationResult(attrs);
};
// TODO: fix this naming, and here's where the value comes in
this.catchExceptions = function(value) {
return catchExceptions = !!value;
};
this.catchingExceptions = function(value) {
catchExceptions = !!value;
return catchExceptions;
};
this.specFactory = function(description, fn, suite) {
var spec = new specConstructor({
id: self.nextSpecId(),
beforeFns: beforeFns(suite),
afterFns: afterFns(suite),
expectationFactory: expectationFactory,
exceptionFormatter: exceptionFormatter,
resultCallback: specResultCallback,
getSpecName: function(spec) {
return getSpecName(spec, suite)
},
startCallback: startCallback,
description: description,
catchingExceptions: this.catchingExceptions,
expectationResultFactory: expectationResultFactory,
fn: fn
});
if (!self.specFilter(spec)) {
spec.disable();
}
return spec;
function specResultCallback(result) {
self.clock.uninstall();
self.currentSpec = null;
encourageGC(function() {
suite.specComplete(result);
});
}
};
var queueConstructor = jasmine.Queue;
var queueFactory = function() {
return new queueConstructor(self);
};
this.suiteFactory = function(description) {
return new suiteConstructor({
env: self,
description: description,
currentSuite: self.currentSuite,
queueFactory: queueFactory,
isSuite: isSuite
});
this.catchingExceptions = function() {
return catchExceptions;
};
var maximumSpecCallbackDepth = 100;
@@ -155,6 +106,86 @@
fn();
}
}
var queueRunnerFactory = function(options) {
options.catchingExceptions = self.catchingExceptions;
options.encourageGC = options.encourageGarbageCollection || encourageGarbageCollection;
new jasmine.QueueRunner(options).run(options.fns, 0);
};
var totalSpecsDefined = 0;
this.specFactory = function(description, fn, suite) {
totalSpecsDefined++;
var spec = new specConstructor({
id: self.nextSpecId(),
beforeFns: beforeFns(suite),
afterFns: afterFns(suite),
expectationFactory: expectationFactory,
exceptionFormatter: exceptionFormatter,
resultCallback: specResultCallback,
getSpecName: function(spec) {
return getSpecName(spec, suite)
},
onStart: specStarted,
description: description,
expectationResultFactory: expectationResultFactory,
queueRunner: queueRunnerFactory,
fn: fn
});
if (!self.specFilter(spec)) {
spec.disable();
}
return spec;
function specResultCallback(result) {
self.removeAllSpies();
self.clock.uninstall();
self.currentSpec = null;
self.reporter.specDone(result);
}
};
var suiteStarted = function(suite) {
self.reporter.suiteStarted(suite.result);
};
var suiteConstructor = jasmine.Suite;
this.topSuite = new jasmine.Suite({
env: this,
id: this.nextSuiteId(),
description: 'Jasmine__TopLevel__Suite',
queueRunner: queueRunnerFactory,
completeCallback: function() {}, // TODO - hook this up
resultCallback: function() {} // TODO - hook this up
});
this.currentSuite = this.topSuite;
this.suiteFactory = function(description) {
return new suiteConstructor({
env: self,
id: self.nextSuiteId(),
description: description,
parentSuite: self.currentSuite,
queueRunner: queueRunnerFactory,
onStart: suiteStarted,
resultCallback: function(attrs) {
self.reporter.suiteDone(attrs);
}
});
};
this.execute = function() {
this.reporter.jasmineStarted({
totalSpecsDefined: totalSpecsDefined
});
this.topSuite.execute(this.reporter.jasmineDone);
};
};
//TODO: shim Spec addMatchers behavior into Env. Should be rewritten to remove globals, etc.
@@ -167,9 +198,7 @@
jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
this.matchersClass = newMatchersClass;
};
/**
* @returns an object containing jasmine version build info, if set.
*/
jasmine.Env.prototype.version = function() {
if (this.jasmine.version_) {
return this.jasmine.version_;
@@ -208,6 +237,7 @@
return spyObj;
};
// TODO: move this to closure
jasmine.Env.prototype.removeAllSpies = function() {
for (var i = 0; i < this.spies_.length; i++) {
var spy = this.spies_[i];
@@ -215,9 +245,8 @@
}
this.spies_ = [];
};
/**
* @returns string containing jasmine version build info, if set.
*/
// TODO: move this to closure
jasmine.Env.prototype.versionString = function() {
if (!this.jasmine.version_) {
return "version unknown";
@@ -232,42 +261,27 @@
return versionString;
};
/**
* @returns a sequential integer starting at 0
*/
// TODO: move this to closure
jasmine.Env.prototype.nextSpecId = function() {
return this.nextSpecId_++;
};
/**
* @returns a sequential integer starting at 0
*/
// TODO: move this to closure
jasmine.Env.prototype.nextSuiteId = function() {
return this.nextSuiteId_++;
};
/**
* Register a reporter to receive status updates from Jasmine.
* @param {jasmine.Reporter} reporter An object which will receive status updates.
*/
// TODO: move this to closure
jasmine.Env.prototype.addReporter = function(reporter) {
this.reporter.addReporter(reporter);
};
jasmine.Env.prototype.execute = function() {
this.currentRunner_.execute();
};
// TODO: move this to closure
jasmine.Env.prototype.describe = function(description, specDefinitions) {
var suite = this.suiteFactory(description, specDefinitions);
var parentSuite = this.currentSuite;
if (parentSuite) {
parentSuite.add(suite);
} else {
this.currentRunner_.addSuite(suite);
}
parentSuite.addSuite(suite);
this.currentSuite = suite;
var declarationError = null;
@@ -288,46 +302,40 @@
return suite;
};
jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
if (this.currentSuite) {
this.currentSuite.beforeEach(beforeEachFunction);
} else {
this.currentRunner_.beforeEach(beforeEachFunction);
}
};
jasmine.Env.prototype.currentRunner = function() {
return this.currentRunner_;
};
jasmine.Env.prototype.afterEach = function(afterEachFunction) {
if (this.currentSuite) {
this.currentSuite.afterEach(afterEachFunction);
} else {
this.currentRunner_.afterEach(afterEachFunction);
}
};
jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
return {
execute: function() {
}
};
// TODO: move this to closure
jasmine.Env.prototype.xdescribe = function(description, specDefinitions) {
var suite = this.describe(description, specDefinitions);
suite.disable();
return suite;
};
// TODO: move this to closure
jasmine.Env.prototype.it = function(description, fn) {
var spec = this.specFactory(description, fn, this.currentSuite);
this.currentSuite.add(spec);
this.currentSuite.addSpec(spec);
return spec;
};
jasmine.Env.prototype.xit = function(desc, func) {
return {
id: this.nextSpecId(),
runs: function() {
}
};
// TODO: move this to closure
jasmine.Env.prototype.xit = function(description, fn) {
var spec = this.it(description, fn);
spec.disable();
return spec;
};
// TODO: move this to closure
jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
this.currentSuite.beforeEach(beforeEachFunction);
};
// TODO: move this to closure
jasmine.Env.prototype.afterEach = function(afterEachFunction) {
this.currentSuite.afterEach(afterEachFunction);
};
// TODO: Still needed?
jasmine.Env.prototype.currentRunner = function() {
return this.topSuite;
};
jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
+46 -90
View File
@@ -1,104 +1,60 @@
/** JavaScript API reporter.
*
* @constructor
*/
jasmine.JsApiReporter = function(jasmine) {
this.jasmine = jasmine || {};
this.started = false;
this.finished = false;
this.suites_ = [];
this.results_ = {};
};
jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
this.started = true;
var suites = runner.topLevelSuites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
this.suites_.push(this.summarize_(suite));
}
};
var status = 'loaded';
jasmine.JsApiReporter.prototype.suites = function() {
return this.suites_;
};
jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
var isSuite = suiteOrSpec instanceof this.jasmine.Suite;
var summary = {
id: suiteOrSpec.id,
name: suiteOrSpec.description,
type: isSuite ? 'suite' : 'spec',
children: []
this.jasmineStarted = function() {
this.started = true;
status = 'started';
};
if (isSuite) {
var children = suiteOrSpec.children();
for (var i = 0; i < children.length; i++) {
summary.children.push(this.summarize_(children[i]));
}
}
return summary;
};
jasmine.JsApiReporter.prototype.results = function() {
return this.results_;
};
//noinspection JSUnusedLocalSymbols
jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
this.finished = true;
};
//noinspection JSUnusedLocalSymbols
jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
};
//noinspection JSUnusedLocalSymbols
jasmine.JsApiReporter.prototype.reportSpecResults = function(result) {
this.results_[result.id] = {
messages: result.failedExpectations,
//result is status
result: result.status
this.jasmineDone = function() {
this.finished = true;
status = 'done';
};
};
//noinspection JSUnusedLocalSymbols
jasmine.JsApiReporter.prototype.log = function(str) {
};
//TODO: make work with new presenter.
jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
var results = {};
for (var i = 0; i < specIds.length; i++) {
var specId = specIds[i];
results[specId] = this.summarizeResult_(this.results_[specId]);
}
return results;
};
jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
var summaryMessages = [];
var messagesLength = result.messages.length;
for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
var resultMessage = result.messages[messageIndex];
//TODO: use result presenter here, not a bunch of spec crap
summaryMessages.push({
//TODO: remove text.
text: resultMessage.type == 'log' ? resultMessage.toString() : this.jasmine.undefined,
//TODO: wat? in theory this is saying non-expect results should always be considered passed, but that's weird.
passed: resultMessage.passed || true, //status === 'passed'
type: resultMessage.type,
message: resultMessage.message,
trace: {
stack: !resultMessage.passed ? resultMessage.trace.stack : this.jasmine.undefined
}
});
}
return {
result : result.result,
messages : summaryMessages
this.status = function() {
return status;
};
};
var suites = {};
this.suiteStarted = function(result) {
storeSuite(result);
};
this.suiteDone = function(result) {
storeSuite(result);
};
function storeSuite(result) {
suites[result.id] = result;
}
this.suites = function() {
return suites;
};
var specs = {};
this.specStarted = function(result) {
storeSpec(result);
};
this.specDone = function(result) {
storeSpec(result);
};
function storeSpec(result) {
specs[result.id] = result;
}
this.specs = function() {
return specs;
};
};
-35
View File
@@ -1,35 +0,0 @@
/**
* @constructor
*/
jasmine.MultiReporter = function() {
this.subReporters_ = [];
};
jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
jasmine.MultiReporter.prototype.addReporter = function(reporter) {
this.subReporters_.push(reporter);
};
(function() {
var functionNames = [
"reportRunnerStarting",
"reportRunnerResults",
"reportSuiteResults",
"reportSpecStarting",
"reportSpecResults",
"log"
];
for (var i = 0; i < functionNames.length; i++) {
var functionName = functionNames[i];
jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
return function() {
for (var j = 0; j < this.subReporters_.length; j++) {
var subReporter = this.subReporters_[j];
if (subReporter[functionName]) {
subReporter[functionName].apply(subReporter, arguments);
}
}
};
})(functionName);
}
})();
-111
View File
@@ -1,111 +0,0 @@
jasmine.Queue = function(env) {
this.env = env;
// parallel to blocks. each true value in this array means the block will
// get executed even if we abort
this.ensured = [];
this.blocks = [];
this.running = false;
this.index = 0;
this.offset = 0;
this.abort = false;
};
jasmine.Queue.prototype.addBefore = function(block, ensure) {
if (ensure === this.env.undefined) {
ensure = false;
}
this.blocks.unshift(block);
this.ensured.unshift(ensure);
};
jasmine.Queue.prototype.add = function(block, ensure) {
if (ensure === this.env.undefined) {
ensure = false;
}
this.blocks.push(block);
this.ensured.push(ensure);
};
jasmine.Queue.prototype.insertNext = function(block, ensure) {
if (ensure === this.env.undefined) {
ensure = false;
}
this.ensured.splice((this.index + this.offset + 1), 0, ensure);
this.blocks.splice((this.index + this.offset + 1), 0, block);
this.offset++;
};
jasmine.Queue.prototype.start = function(onComplete) {
this.running = true;
this.onComplete = onComplete;
this.next_();
};
jasmine.Queue.prototype.isRunning = function() {
return this.running;
};
jasmine.Queue.LOOP_DONT_RECURSE = true;
jasmine.Queue.prototype.incrementQueue = function() {
if (this.blocks[this.index].abort) {
this.abort = true;
}
this.offset = 0;
this.index++;
this.next_();
}
jasmine.Queue.prototype.next_ = function() {
var self = this;
// var goAgain = true;
// while (goAgain) {
// goAgain = false;
if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) {
// var calledSynchronously = true;
// var completedSynchronously = false;
// var onComplete = function () {
// if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
// completedSynchronously = true;
// return;
// }
self.blocks[self.index].execute(function() { self.incrementQueue() });
// var now = new Date().getTime();
// if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
// self.env.lastUpdate = now;
// self.env.setTimeout(function() {
// self.next_();
// }, 0);
// } else {
// if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
// goAgain = true;
// } else {
// self.next_();
// }
// }
// };
// self.blocks[self.index].execute(function() { self.next_(); });
// calledSynchronously = false;
// if (completedSynchronously) {
// onComplete();
// }
} else {
self.running = false;
if (self.onComplete) {
self.onComplete();
}
}
// }
};
+40
View File
@@ -0,0 +1,40 @@
jasmine.QueueRunner = function(attrs) {
this.fns = attrs.fns || [];
this.onComplete = attrs.onComplete || function() {};
this.encourageGC = attrs.encourageGC || function(fn) {fn()};
this.onException = attrs.onException || function() {};
this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
};
jasmine.QueueRunner.prototype.execute = function() {
this.run(this.fns, 0)
};
jasmine.QueueRunner.prototype.run = function(fns, index) {
if (index >= fns.length) {
this.encourageGC(this.onComplete);
return;
}
var fn = fns[index];
var self = this;
if (fn.length > 0) {
attempt(function() { fn.call(self, function() { self.run(fns, index + 1) }) });
} else {
attempt(function() { fn.call(self); });
self.run(fns, index + 1);
}
function attempt(fn) {
try {
fn();
} catch (e) {
self.onException(e);
if (!self.catchingExceptions()) {
//TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way..
throw e;
}
}
}
};
+30
View File
@@ -0,0 +1,30 @@
jasmine.ReportDispatcher = function(methods) {
var dispatchedMethods = methods || [];
for (var i = 0; i < dispatchedMethods.length; i++) {
var method = dispatchedMethods[i];
this[method] = function(m) {
return function() {
dispatch(m, arguments);
};
}(method);
}
var reporters = [];
this.addReporter = function(reporter) {
reporters.push(reporter);
};
return this;
function dispatch(method, args) {
for (var i = 0; i < reporters.length; i++) {
var reporter = reporters[i];
if (reporter[method]) {
reporter[method].apply(reporter, args);
}
}
}
};
-31
View File
@@ -1,31 +0,0 @@
/** No-op base class for Jasmine reporters.
*
* @constructor
*/
jasmine.Reporter = function() {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.reportSpecResults = function(spec) {
};
//noinspection JSUnusedLocalSymbols
jasmine.Reporter.prototype.log = function(str) {
};
-80
View File
@@ -1,80 +0,0 @@
//TODO: runner is a special case of suite.
/**
* Runner
*
* @constructor
* @param {jasmine.Env} env
*/
jasmine.Runner = function(env, isSuite) {
var self = this;
self.env = env;
self.queue = new jasmine.Queue(env);
self.before_ = [];
self.after_ = [];
self.suites_ = [];
self.isSuite = isSuite || function() {};
};
jasmine.Runner.prototype.execute = function() {
var self = this;
if (self.env.reporter.reportRunnerStarting) {
self.env.reporter.reportRunnerStarting(this);
}
self.queue.start(function () {
self.finishCallback();
});
};
jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.splice(0,0,beforeEachFunction);
};
jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
afterEachFunction.typeName = 'afterEach';
this.after_.splice(0,0,afterEachFunction);
};
jasmine.Runner.prototype.finishCallback = function() {
this.env.reporter.reportRunnerResults(this);
};
jasmine.Runner.prototype.addSuite = function(suite) {
this.suites_.push(suite);
this.queue.add(suite);
};
//TODO: runner should die a slow unhappy death.
//Nobody should ever call instanceof.
jasmine.Runner.prototype.add = function(block) {
if (this.isSuite(block)) {
this.addSuite(block);
} else {
this.queue.add(block);
}
};
jasmine.Runner.prototype.specs = function () {
var suites = this.suites();
var specs = [];
for (var i = 0; i < suites.length; i++) {
specs = specs.concat(suites[i].specs());
}
return specs;
};
jasmine.Runner.prototype.suites = function() {
return this.suites_;
};
jasmine.Runner.prototype.topLevelSuites = function() {
var topLevelSuites = [];
for (var i = 0; i < this.suites_.length; i++) {
if (!this.suites_[i].parentSuite) {
topLevelSuites.push(this.suites_[i]);
}
}
return topLevelSuites;
};
+34 -46
View File
@@ -1,24 +1,33 @@
jasmine.Spec = function(attrs) {
this.failedExpectations = [];
this.encounteredExpectations = false;
this.expectationFactory = attrs.expectationFactory;
this.resultCallback = attrs.resultCallback || function() {};
this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id;
this.description = attrs.description;
this.description = attrs.description || '';
this.fn = attrs.fn;
this.beforeFns = attrs.beforeFns || function() {};
this.afterFns = attrs.afterFns || function() {};
this.catchingExceptions = attrs.catchingExceptions;
this.startCallback = attrs.startCallback || function() {};
this.onStart = attrs.onStart || function() {};
this.exceptionFormatter = attrs.exceptionFormatter || function() {};
this.getSpecName = attrs.getSpecName;
this.getSpecName = attrs.getSpecName || function() { return ''; };
this.expectationResultFactory = attrs.expectationResultFactory || function() {};
this.queueRunner = attrs.queueRunner || { execute: function() {}};
this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
status: this.status(),
failedExpectations: []
};
};
jasmine.Spec.prototype.addExpectationResult = function(passed, data) {
this.encounteredExpectations = true;
if (!passed) {
this.failedExpectations.push(data);
this.result.failedExpectations.push(data);
}
};
@@ -26,26 +35,22 @@ jasmine.Spec.prototype.expect = function(actual) {
return this.expectationFactory(actual, this);
};
jasmine.Spec.prototype.execute = function() {
jasmine.Spec.prototype.execute = function(onComplete) {
var self = this;
if (this.disabled) {
resultCallback();
complete();
return;
}
var befores = this.beforeFns() || [],
afters = this.afterFns() || [];
this.startCallback(this);
afters = this.afterFns() || [];
var allFns = befores.concat(this.fn).concat(afters);
queueRunner(allFns, 0);
function attempt(fn) {
try {
fn();
} catch (e) {
//TODO: weird. buildExpectationResult is really a presenter for expectations
//so this should take an expectation object.
this.onStart(this);
this.queueRunner({
fns: allFns,
onException: function(e) {
self.addExpectationResult(false, self.expectationResultFactory({
matcherName: "",
passed: false,
@@ -54,35 +59,17 @@ jasmine.Spec.prototype.execute = function() {
message: self.exceptionFormatter(e),
trace: e
}));
if (!self.catchingExceptions()) {
//TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way..
throw e;
}
}
}
},
onComplete: complete
});
function queueRunner(allFns, index) {
if (index >= allFns.length) {
resultCallback();
return;
}
var fn = allFns[index];
if (fn.length > 0) {
attempt(function() { fn.call(self, function() { queueRunner(allFns, index + 1) }) });
} else {
attempt(function() { fn.call(self); });
queueRunner(allFns, index + 1);
}
}
function complete() {
self.result.status = self.status();
self.resultCallback(self.result);
function resultCallback() {
self.resultCallback({
id: self.id,
status: self.status(),
description: self.description,
failedExpectations: self.failedExpectations
});
if (onComplete) {
onComplete();
}
}
};
@@ -98,7 +85,8 @@ jasmine.Spec.prototype.status = function() {
if (!this.encounteredExpectations) {
return null;
}
if (this.failedExpectations.length > 0) {
if (this.result.failedExpectations.length > 0) {
return 'failed';
} else {
return 'passed';
+59 -40
View File
@@ -3,33 +3,40 @@ jasmine.Suite = function(attrs) {
this.id = attrs.id;
this.parentSuite = attrs.parentSuite;
this.description = attrs.description;
this.onStart = attrs.onStart || function() {};
this.completeCallback = attrs.completeCallback || function() {};
this.resultCallback = attrs.resultCallback || function() {};
this.encourageGC = attrs.encourageGC || function(fn) {fn();};
this.beforeFns = [];
this.afterFns = [];
this.queueRunner = attrs.queueRunner || function() {};
this.disabled = false;
var queueFactory = attrs.queueFactory || function() {};
this.queue = queueFactory();
this.children_ = []; // TODO: rename
this.suites = []; // TODO: needed?
this.specs = []; // TODO: needed?
this.isSuite = attrs.isSuite || function() {};
this.children_ = []; // TODO: used by current reporters; keep for now
this.suites_ = [];
this.specs_ = [];
this.result = {
id: this.id,
status: this.disabled ? 'disabled' : '',
description: this.description,
fullName: this.getFullName()
};
};
jasmine.Suite.prototype.getFullName = function() {
var fullName = this.description;
for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
fullName = parentSuite.description + ' ' + fullName;
if (parentSuite.parentSuite) {
fullName = parentSuite.description + ' ' + fullName;
}
}
return fullName;
};
jasmine.Suite.prototype.finish = function(onComplete) {
this.env.reporter.reportSuiteResults(this);
this.finished = true;
if (typeof(onComplete) == 'function') {
onComplete();
}
jasmine.Suite.prototype.disable = function() {
this.disabled = true;
};
jasmine.Suite.prototype.beforeEach = function(fn) {
@@ -40,32 +47,15 @@ jasmine.Suite.prototype.afterEach = function(fn) {
this.afterFns.unshift(fn);
};
//TODO: interface should be addSpec or addSuite methods.
jasmine.Suite.prototype.add = function(suiteOrSpec) {
this.children_.push(suiteOrSpec);
if (this.isSuite(suiteOrSpec)) {
this.suites_.push(suiteOrSpec);
this.env.currentRunner().addSuite(suiteOrSpec);
} else {
this.specs_.push(suiteOrSpec);
}
this.queue.add(suiteOrSpec);
jasmine.Suite.prototype.addSpec = function(spec) {
this.children_.push(spec);
this.specs.push(spec); // TODO: needed?
};
jasmine.Suite.prototype.specComplete = function(specResult) {
specResult.fullName = this.getFullName() + ' ' + specResult.description + '.';
specResult.suite = this;
this.env.removeAllSpies();
this.env.reporter.reportSpecResults(specResult);
this.queue.incrementQueue();
};
jasmine.Suite.prototype.specs = function() {
return this.specs_;
};
jasmine.Suite.prototype.suites = function() {
return this.suites_;
jasmine.Suite.prototype.addSuite = function(suite) {
suite.parentSuite = this;
this.children_.push(suite);
this.suites.push(suite); // TODO: needed?
};
jasmine.Suite.prototype.children = function() {
@@ -74,7 +64,36 @@ jasmine.Suite.prototype.children = function() {
jasmine.Suite.prototype.execute = function(onComplete) {
var self = this;
this.queue.start(function () {
self.finish(onComplete);
if (this.disabled) {
complete();
return;
}
var allFns = [],
children = this.children_;
for (var i = 0; i < children.length; i++) {
allFns.push(wrapChild(children[i]));
function wrapChild(child) {
return function(done) {
child.execute(done);
}
}
}
this.onStart(this);
this.queueRunner({
fns: allFns,
onComplete: complete
});
function complete() {
self.resultCallback(self.result);
if (onComplete) {
onComplete();
}
}
};
+241 -154
View File
@@ -1,176 +1,263 @@
jasmine.HtmlReporter = function(_doc, jasmine, env, options) {
options = options || {};
var self = this;
this.jasmine = jasmine || window.jasmine;
var doc = _doc || window.document;
jasmine.HtmlReporter = function(options) {
var env = options.env || {},
getContainer = options.getContainer,
now = options.now || function() { return new Date().getTime();},
createElement = options.createElement,
createTextNode = options.createTextNode,
results = [],
queryString = options.queryString,
startTime,
specsExecuted = 0,
failureCount = 0,
htmlReporterMain,
symbols;
this.initialize = function() {
htmlReporterMain = createDom("div", {className: "html-reporter"},
createDom("div", {className: "banner"},
createDom("span", {className: "title"}, "Jasmine"),
createDom("span", {className: "version"}, env.versionString())
),
createDom("ul", {className: "symbol-summary"}),
createDom("div", {className: "alert"}),
createDom("div", {className: "results"},
createDom("div", {className: "failures"})
)
);
getContainer().appendChild(htmlReporterMain);
var reporterView;
var dom = {};
// Jasmine Reporter Public Interface
self.reportRunnerStarting = function(runner) {
var specs = runner.specs() || [];
if (specs.length == 0) {
return;
}
createReporterDom(runner.env.versionString());
doc.body.appendChild(dom.reporter);
setExceptionHandling();
reporterView = new self.jasmine.HtmlReporter.ReporterView(dom, self.jasmine, env.catchingExceptions());
reporterView.addSpecs(specs, self.specFilter);
symbols = find(".symbol-summary")[0];
};
self.reportRunnerResults = function(runner) {
reporterView && reporterView.complete();
};
var specFilterPattern;
self.reportSuiteResults = function(suite) {
reporterView.suiteComplete(suite);
};
self.reportSpecStarting = function(spec) {
};
var lastYieldForRender = 0;
var refreshInterval = 250;
var yieldForRender = options.yieldForRender || function(fn) {
var now = Date.now();
var delta = (now - lastYieldForRender);
if (delta > refreshInterval) {
lastYieldForRender = now;
setTimeout(fn, 0);
} else {
fn();
}
}
self.reportSpecResults = function(result) {
yieldForRender(function() {reporterView.specComplete(result) });
};
self.log = function() {
var console = self.jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
self.specFilter = function(spec) {
if (!focusedSpecName()) {
this.specFilter = function(spec) {
if (!isFiltered()) {
return true;
}
return spec.getFullName().indexOf(focusedSpecName()) === 0;
var specName = spec.getFullName();
return !!(specName.match(specFilterPattern));
};
return self;
var totalSpecsDefined;
this.jasmineStarted = function(options) {
totalSpecsDefined = options.totalSpecsDefined || 0;
startTime = now();
};
function focusedSpecName() {
var specName;
var summary = createDom("div", {className: "summary"});
(function memoizeFocusedSpec() {
if (specName) {
return;
}
var topResults = new jasmine.ResultsNode({}, "", null),
currentParent = topResults;
var paramMap = [];
var params = self.jasmine.HtmlReporter.parameters(doc);
this.suiteStarted = function(result) {
currentParent.addChild(result, "suite");
currentParent = currentParent.last();
};
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
specName = paramMap.spec;
})();
return specName;
}
function createReporterDom(version) {
dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
dom.banner = self.createDom('div', { className: 'banner' },
self.createDom('span', { className: 'title' }, "Jasmine "),
self.createDom('span', { className: 'version' }, version)),
dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
dom.alert = self.createDom('div', {className: 'alert'},
self.createDom('span', { className: 'exceptions' },
self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
dom.results = self.createDom('div', {className: 'results'},
dom.summary = self.createDom('div', { className: 'summary' }),
dom.details = self.createDom('div', { id: 'details' }))
);
}
function noTryCatch() {
return window.location.search.match(/catch=false/);
}
function searchWithCatch() {
var params = self.jasmine.HtmlReporter.parameters(window.document);
var removed = false;
var i = 0;
while (!removed && i < params.length) {
if (params[i].match(/catch=/)) {
params.splice(i, 1);
removed = true;
}
i++;
}
if (env.catchingExceptions()) {
params.push("catch=false");
this.suiteDone = function(result) {
if (currentParent == topResults) {
return;
}
return params.join("&");
}
currentParent = currentParent.parent;
};
function setExceptionHandling() {
var chxCatch = document.getElementById('no_try_catch');
this.specStarted = function(result) {
currentParent.addChild(result, "spec");
};
if (noTryCatch()) {
chxCatch.setAttribute('checked', true);
env.catchExceptions(false);
var failures = [];
this.specDone = function(result) {
if (result.status != "disabled") {
specsExecuted++;
}
chxCatch.onclick = function() {
window.location.search = searchWithCatch();
symbols.appendChild(createDom("li", {
className: result.status,
id: "spec_" + result.id}
));
if (result.status == "failed") {
failureCount++;
var failure =
createDom("div", {className: "spec-detail failed"},
createDom("a", {className: "description", title: result.fullName, href: specHref(result)}, result.fullName),
createDom("div", {className: "messages"})
);
var messages = failure.childNodes[1];
for (var i = 0; i < result.failedExpectations.length; i++) {
var expectation = result.failedExpectations[i];
var stack = (expectation.trace && expectation.trace.stack) || "";
messages.appendChild(createDom("div", {className: "result-message"}, expectation.message));
messages.appendChild(createDom("div", {className: "stack-trace"}, stack));
}
failures.push(failure);
}
};
this.jasmineDone = function() {
var elapsed = now() - startTime;
var banner = find(".banner")[0];
banner.appendChild(createDom("span", {className: "duration"}, "finished in " + elapsed / 1000 + "s"));
var alert = find(".alert")[0];
alert.appendChild(createDom("span", { className: "exceptions" },
createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"),
createDom("input", {
className: "raise",
id: "raise-exceptions",
type: "checkbox"
})
));
var checkbox = find("input")[0];
checkbox.checked = !env.catchingExceptions();
checkbox.onclick = function() {
queryString.setParam("catch", !checkbox.checked);
};
if (specsExecuted < totalSpecsDefined) {
var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all";
alert.appendChild(
createDom("span", {className: "bar skipped"},
createDom("a", {href: "?", title: "Run all specs"}, skippedMessage)
)
);
}
var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount),
statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed");
alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage));
var results = find(".results")[0];
results.appendChild(summary);
summaryList(topResults, summary);
function summaryList(resultsTree, domParent) {
var specListNode;
for (var i = 0; i < resultsTree.children.length; i++) {
var resultNode = resultsTree.children[i];
if (resultNode.type == "suite") {
var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id},
createDom("li", {className: "suite-detail"},
createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
)
);
summaryList(resultNode, suiteListNode);
domParent.appendChild(suiteListNode);
}
if (resultNode.type == "spec") {
if (domParent.getAttribute("class") != "specs") {
specListNode = createDom("ul", {className: "specs"});
domParent.appendChild(specListNode);
}
specListNode.appendChild(
createDom("li", {
className: resultNode.result.status,
id: "spec-" + resultNode.result.id
},
createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
)
);
}
}
}
if (failures.length) {
alert.appendChild(
createDom('span', {className: "menu bar spec-list"},
createDom("span", {}, "Spec List | "),
createDom('a', {className: "failures-menu", href: "#"}, "Failures")));
alert.appendChild(
createDom('span', {className: "menu bar failure-list"},
createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"),
createDom("span", {}, " | Failures ")));
find(".failures-menu")[0].onclick = function() {
setMenuModeTo('failure-list');
};
find(".spec-list-menu")[0].onclick = function() {
setMenuModeTo('spec-list');
};
setMenuModeTo('failure-list');
var failureNode = find(".failures")[0];
for (var i = 0; i < failures.length; i++) {
failureNode.appendChild(failures[i]);
}
}
};
return this;
function find(selector) {
if (selector.match(/^\./)) {
var className = selector.substring(1);
return getContainer().getElementsByClassName(className);
} else {
return getContainer().getElementsByTagName(selector);
}
}
function createDom(type, attrs, childrenVarArgs) {
var el = createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
}
function pluralize(singular, count) {
var word = (count == 1 ? singular : singular + "s");
return "" + count + " " + word;
}
function specHref(result) {
return "?spec=" + encodeURIComponent(result.fullName);
}
function isFiltered() {
buildSpecFilter();
return !!specFilterPattern;
}
function buildSpecFilter() {
var specFilterParam = queryString.getParam("spec") || "";
specFilterPattern = new RegExp(specFilterParam);
}
function setMenuModeTo(mode) {
htmlReporterMain.setAttribute("class", "html-reporter " + mode);
}
};
jasmine.HtmlReporter.parameters = function(doc) {
var paramStr = doc.location.search.substring(1);
var params = [];
if (paramStr.length > 0) {
params = paramStr.split('&');
}
return params;
}
jasmine.HtmlReporter.sectionLink = function(sectionName, catchExceptions) {
var link = '?';
var params = [];
if (sectionName) {
params.push('spec=' + encodeURIComponent(sectionName));
}
if (!catchExceptions) {
params.push("catch=false");
}
if (params.length > 0) {
link += params.join("&");
}
return link;
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
-64
View File
@@ -1,64 +0,0 @@
jasmine.HtmlReporterHelpers = {};
jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
if (!child.results) {
return;
}
var results = child.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
return status;
};
jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
var parentDiv = this.dom.summary;
var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
var parent = child[parentSuite];
if (parent) {
if (typeof this.views.suites[parent.id] == 'undefined') {
this.views.suites[parent.id] = new this.jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views, this.jasmine, this.catchExceptions);
}
parentDiv = this.views.suites[parent.id].element;
}
parentDiv.appendChild(childElement);
};
jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
//TODO: not really a helper, thus, no this.jasmine
for(var fn in jasmine.HtmlReporterHelpers) {
ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
}
};
+43
View File
@@ -0,0 +1,43 @@
jasmine.QueryString = function(options) {
this.setParam = function(key, value) {
var paramMap = queryStringToParamMap();
paramMap[key] = value;
options.getWindowLocation().search = toQueryString(paramMap);
};
this.getParam = function(key) {
return queryStringToParamMap()[key];
};
return this;
function toQueryString(paramMap) {
var qStrPairs = [];
for (var prop in paramMap) {
qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop]));
}
return "?" + qStrPairs.join('&');
}
function queryStringToParamMap() {
var paramStr = options.getWindowLocation().search.substring(1),
params = [],
paramMap = {};
if (paramStr.length > 0) {
params = paramStr.split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
var value = decodeURIComponent(p[1]);
if (value === "true" || value === "false") {
value = JSON.parse(value);
}
paramMap[decodeURIComponent(p[0])] = value;
}
}
return paramMap;
}
};
+15
View File
@@ -0,0 +1,15 @@
jasmine.ResultsNode = function(result, type, parent) {
this.result = result;
this.type = type;
this.parent = parent;
this.children = [];
this.addChild = function(result, type) {
this.children.push(new jasmine.ResultsNode(result, type, this));
};
this.last = function() {
return this.children[this.children.length-1];
}
};
+80 -68
View File
@@ -3,7 +3,7 @@
$line-height: 14px;
$margin-unit: 14px;
$feint-text-color: #aaa;
$faint-text-color: #aaa;
$light-text-color: #666;
$text-color: #333;
@@ -27,7 +27,7 @@ body {
overflow-y: scroll;
}
#HTMLReporter {
.html-reporter {
font-size: $font-size;
font-family: Monaco, "Lucida Console", monospace;
@@ -48,16 +48,21 @@ body {
}
.banner,
.symbolSummary,
.symbol-summary,
.summary,
.resultMessage,
.specDetail .description,
.result-message,
.spec .description,
.spec-detail .description,
.alert .bar,
.stackTrace {
.stack-trace {
padding-left: $margin-unit - 5px;
padding-right: $margin-unit - 5px;
}
.banner .version {
margin-left: $margin-unit;
};
// This div is available for testing elements that must be added to the DOM.
// We position it out of view, so it doesn't obstruct the runner.
#jasmine_content {
@@ -66,7 +71,7 @@ body {
}
.version {
color: $feint-text-color;
color: $faint-text-color;
}
//--- Banner ---//
@@ -76,13 +81,13 @@ body {
}
.duration {
color: $feint-text-color;
color: $faint-text-color;
float: right;
}
//--- Symbol summary ---//
.symbolSummary {
.symbol-summary {
@include clearfix;
margin: $line-height 0;
@@ -93,14 +98,12 @@ body {
width: $line-height;
margin-bottom: $line-height / 2;
//opacity: .9;
font-size: 16px;
&.passed {
font-size: 14px;
&:before{
&:before {
color: $passing-color;
content: "\02022";
}
@@ -109,7 +112,7 @@ body {
&.failed {
line-height: ($line-height / 2) + 2;
&:before{
&:before {
color: $failing-color;
content: "x";
font-weight: bold;
@@ -117,20 +120,20 @@ body {
}
}
&.skipped {
&.disabled {
font-size: 14px;
&:before{
&:before {
color: $neutral-color;
content: "\02022";
}
}
&.pending{
&.pending {
line-height: ($line-height / 2) + 4;
&:before {
color: $feint-text-color;
color: $faint-text-color;
content: "-";
}
}
@@ -144,7 +147,7 @@ body {
margin-right: 5px;
}
//--- Alert ---//
//--- Alerts: status bars ---//
.bar {
line-height: $line-height * 2;
@@ -152,40 +155,50 @@ body {
display: block;
color: #eee;
}
.runningAlert {
background-color: $light-text-color;
}
.skippedAlert {
background-color: $feint-text-color;
&:first-child {
background-color: $text-color;
}
&:hover {
text-decoration: none;
color: white;
text-decoration: underline;
}
}
.passingAlert {
background-color: $light-passing-color;
&:first-child {
background-color: $passing-color;
}
}
.failingAlert {
background-color: $light-failing-color;
&:first-child {
&.failed {
background-color: $failing-color
}
&.passed {
background-color: $light-passing-color;
}
&.skipped {
background-color: $neutral-color;
}
&.menu {
background-color: #fff;
color: $faint-text-color;
a {
color: $text-color;
}
}
a {
color: white;
}
}
// simplify toggle control between the two menu bars
&.spec-list {
.bar.menu.failure-list,
.results .failures {
display: none;
}
}
&.failure-list {
.bar.menu.spec-list,
.summary {
display: none;
}
}
.running-alert {
background-color: $light-text-color;
}
//--- Results ---//
@@ -196,16 +209,6 @@ body {
//--- Results menu ---//
#details {
display: none;
}
.resultsMenu,
.resultsMenu a {
background-color: #fff;
color: $text-color;
}
&.showDetails {
.summaryMenuItem {
@@ -236,19 +239,28 @@ body {
text-decoration: underline;
}
//--- Results summary ---//
//--- Results summary: Suites and Specs names/links ---//
.summary {
margin-top: $margin-unit;
.suite .suite, .specSummary {
ul {
list-style-type: none;
margin-left: $margin-unit;
padding-top: 0;
padding-left: 0;
&.suite {
margin-top: $margin-unit/2;
margin-bottom: $margin-unit/2
}
}
.specSummary {
li {
&.passed a {
color: $passing-color;
}
&.failed a {
color: $failing-color;
}
@@ -267,10 +279,10 @@ body {
}
}
//--- Results details ---//
//--- Failure details ---//
#details {
.specDetail {
.failures {
.spec-detail {
margin-bottom: $line-height * 2;
.description {
@@ -285,17 +297,17 @@ body {
}
}
.resultMessage {
.result-message {
padding-top: $line-height;
color: $text-color;
}
.resultMessage span.result {
.result-message span.result {
display: block;
}
.stackTrace {
.stack-trace {
margin: 5px 0 0 0;
max-height: $line-height * 16;
overflow: auto;
+51 -50
View File
@@ -1,52 +1,53 @@
body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
#HTMLReporter a { text-decoration: none; }
#HTMLReporter a:hover { text-decoration: underline; }
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
#HTMLReporter .version { color: #aaaaaa; }
#HTMLReporter .banner { margin-top: 14px; }
#HTMLReporter .duration { color: #aaaaaa; float: right; }
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
#HTMLReporter .runningAlert { background-color: #666666; }
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
#HTMLReporter .passingAlert { background-color: #a6b779; }
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
#HTMLReporter .failingAlert { background-color: #cf867e; }
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
#HTMLReporter .results { margin-top: 14px; }
#HTMLReporter #details { display: none; }
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter.showDetails .summary { display: none; }
#HTMLReporter.showDetails #details { display: block; }
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter .summary { margin-top: 14px; }
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
#HTMLReporter .description + .suite { margin-top: 0; }
#HTMLReporter .suite { margin-top: 14px; }
#HTMLReporter .suite a { color: #333333; }
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
#HTMLReporter .resultMessage span.result { display: block; }
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
.html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
.html-reporter a { text-decoration: none; }
.html-reporter a:hover { text-decoration: underline; }
.html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; }
.html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; }
.html-reporter .banner .version { margin-left: 14px; }
.html-reporter #jasmine_content { position: fixed; right: 100%; }
.html-reporter .version { color: #aaaaaa; }
.html-reporter .banner { margin-top: 14px; }
.html-reporter .duration { color: #aaaaaa; float: right; }
.html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; }
.html-reporter .symbol-summary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
.html-reporter .symbol-summary li.passed { font-size: 14px; }
.html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; }
.html-reporter .symbol-summary li.failed { line-height: 9px; }
.html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
.html-reporter .symbol-summary li.disabled { font-size: 14px; }
.html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; }
.html-reporter .symbol-summary li.pending { line-height: 11px; }
.html-reporter .symbol-summary li.pending:before { color: #aaaaaa; content: "-"; }
.html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
.html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
.html-reporter .bar.failed { background-color: #b03911; }
.html-reporter .bar.passed { background-color: #a6b779; }
.html-reporter .bar.skipped { background-color: #bababa; }
.html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; }
.html-reporter .bar.menu a { color: #333333; }
.html-reporter .bar a { color: white; }
.html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; }
.html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; }
.html-reporter .running-alert { background-color: #666666; }
.html-reporter .results { margin-top: 14px; }
.html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
.html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
.html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
.html-reporter.showDetails .summary { display: none; }
.html-reporter.showDetails #details { display: block; }
.html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
.html-reporter .summary { margin-top: 14px; }
.html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; }
.html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; }
.html-reporter .summary li.passed a { color: #5e7d00; }
.html-reporter .summary li.failed a { color: #b03911; }
.html-reporter .description + .suite { margin-top: 0; }
.html-reporter .suite { margin-top: 14px; }
.html-reporter .suite a { color: #333333; }
.html-reporter .failures .spec-detail { margin-bottom: 28px; }
.html-reporter .failures .spec-detail .description { display: block; color: white; background-color: #b03911; }
.html-reporter .result-message { padding-top: 14px; color: #333333; }
.html-reporter .result-message span.result { display: block; }
.html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
+5 -9
View File
@@ -6,25 +6,21 @@ class JasmineDev < Thor
"ExceptionFormatter.js",
"ExpectationResult.js",
"Env.js",
"Reporter.js",
"JsApiReporter.js",
"Matchers.js",
"MultiReporter.js",
"PrettyPrinter.js",
"Queue.js",
"Runner.js",
"QueueRunner.js",
"Spec.js",
"Suite.js",
"Clock.js",
"DelayedFunctionScheduler.js"
"DelayedFunctionScheduler.js",
"ReportDispatcher.js"
],
:html => [
"HtmlReporterHelpers.js",
"HtmlReporter.js",
"ReporterView.js",
"SpecView.js",
"SuiteView.js",
"ResultsNode.js",
"QueryString.js"
]
}
end