* 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

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?

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();
};

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;
}
};
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;
function specHref(result) {
return "?spec=" + encodeURIComponent(result.fullName);
}
this.element = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'description', href: this.jasmine.HtmlReporter.sectionLink(this.suite.getFullName(), catchExceptions) }, this.suite.description)
);
function isFiltered() {
buildSpecFilter();
this.appendToSummary(this.suite, this.element);
};
return !!specFilterPattern;
}
jasmine.HtmlReporter.SuiteView.prototype.status = function() {
return this.getSpecStatus(this.suite);
};
function buildSpecFilter() {
var specFilterParam = queryString.getParam("spec") || "";
jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
this.element.className += " " + this.status();
};
specFilterPattern = new RegExp(specFilterParam);
}
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
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;
}
};

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

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");
});
});
});

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.");

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'}});
});
});

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');
});
});

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);
});
});

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();
});
});

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);
});
});

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()]);
});
});
});

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 () {
));
});
});
});

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();
});
});

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"
});
});
});

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!");
});
});
});

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);
}
});

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();
});
});
});

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]);
});
});

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'

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();

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]);
}
}

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>

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();
}
};

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) {

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) {

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;
};
};

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);
}
})();

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
src/core/QueueRunner.js Normal file
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;
}
}
}
};

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);
}
}
}
};

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) {
};

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;
};

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';

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();
}
}
};

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);
};
}
};
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 (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));
if (sectionName) {
params.push('spec=' + encodeURIComponent(sectionName));
}
if (!catchExceptions) {
params.push("catch=false");
}
if (params.length > 0) {
link += params.join("&");
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);
}
}
return link;
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
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);
}
};

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
src/html/QueryString.js Normal file
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
src/html/ResultsNode.js Normal file
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];
}
};

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;
@@ -36,101 +36,104 @@ body {
a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
p, h1, h2, h3, h4, h5, h6 {
margin: 0;
line-height: $line-height;
}
.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 {
position: fixed;
right: 100%;
}
.version {
color: $feint-text-color;
color: $faint-text-color;
}
//--- Banner ---//
.banner {
margin-top: $line-height;
}
.duration {
color: $feint-text-color;
color: $faint-text-color;
float: right;
}
//--- Symbol summary ---//
.symbolSummary {
.symbol-summary {
@include clearfix;
margin: $line-height 0;
li {
display: block;
float: left;
height: $line-height / 2;
width: $line-height;
margin-bottom: $line-height / 2;
//opacity: .9;
font-size: 16px;
&.passed {
font-size: 14px;
&:before{
&:before {
color: $passing-color;
content: "\02022";
}
}
&.failed {
line-height: ($line-height / 2) + 2;
&:before{
&:before {
color: $failing-color;
content: "x";
font-weight: bold;
margin-left: -1px;
}
}
&.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;

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; }

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