Commit dee327ac authored by Addy Osmani's avatar Addy Osmani

Merge pull request #198 from stas/emberjs-routing

Emberjs routing
parents 2c9508c3 f1084f90
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) {
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 jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
}
parentDiv = this.views.suites[parent.id].element;
}
parentDiv.appendChild(childElement);
};
jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
for(var fn in jasmine.HtmlReporterHelpers) {
ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
}
};
jasmine.HtmlReporter = function(_doc) {
var self = this;
var doc = _doc || window.document;
var reporterView;
var dom = {};
// Jasmine Reporter Public Interface
self.logRunningSpecs = false;
self.reportRunnerStarting = function(runner) {
var specs = runner.specs() || [];
if (specs.length == 0) {
return;
}
createReporterDom(runner.env.versionString());
doc.body.appendChild(dom.reporter);
reporterView = new jasmine.HtmlReporter.ReporterView(dom);
reporterView.addSpecs(specs, self.specFilter);
};
self.reportRunnerResults = function(runner) {
reporterView && reporterView.complete();
};
self.reportSuiteResults = function(suite) {
reporterView.suiteComplete(suite);
};
self.reportSpecStarting = function(spec) {
if (self.logRunningSpecs) {
self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
self.reportSpecResults = function(spec) {
reporterView.specComplete(spec);
};
self.log = function() {
var console = 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()) {
return true;
}
return spec.getFullName().indexOf(focusedSpecName()) === 0;
};
return self;
function focusedSpecName() {
var specName;
(function memoizeFocusedSpec() {
if (specName) {
return;
}
var paramMap = [];
var params = doc.location.search.substring(1).split('&');
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'}),
dom.results = self.createDom('div', {className: 'results'},
dom.summary = self.createDom('div', { className: 'summary' }),
dom.details = self.createDom('div', { id: 'details' }))
);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
this.startedAt = new Date();
this.runningSpecCount = 0;
this.completeSpecCount = 0;
this.passedCount = 0;
this.failedCount = 0;
this.skippedCount = 0;
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();
};
};
this.addSpecs = function(specs, specFilter) {
this.totalSpecCount = specs.length;
this.views = {
specs: {},
suites: {}
};
for (var i = 0; i < specs.length; i++) {
var spec = specs[i];
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
if (specFilter(spec)) {
this.runningSpecCount++;
}
}
};
this.specComplete = function(spec) {
this.completeSpecCount++;
if (isUndefined(this.views.specs[spec.id])) {
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
}
var specView = this.views.specs[spec.id];
switch (specView.status()) {
case 'passed':
this.passedCount++;
break;
case 'failed':
this.failedCount++;
break;
case 'skipped':
this.skippedCount++;
break;
}
specView.refresh();
this.refresh();
};
this.suiteComplete = function(suite) {
var suiteView = this.views.suites[suite.id];
if (isUndefined(suiteView)) {
return;
}
suiteView.refresh();
};
this.refresh = function() {
if (isUndefined(this.resultsMenu)) {
this.createResultsMenu();
}
// currently running UI
if (isUndefined(this.runningAlert)) {
this.runningAlert = this.createDom('a', {href: "?", 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: "?", 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: "?", 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.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();
}
dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
};
return this;
function showDetails() {
if (dom.reporter.className.search(/showDetails/) === -1) {
dom.reporter.className += " showDetails";
}
}
function isUndefined(obj) {
return typeof obj === 'undefined';
}
function isDefined(obj) {
return !isUndefined(obj);
}
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) {
this.spec = spec;
this.dom = dom;
this.views = views;
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',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
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.getSpecStatus(this.spec);
};
jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
this.symbol.className = this.status();
switch (this.status()) {
case 'skipped':
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.results().getItems();
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 && !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 (messagesDiv.childNodes.length > 0) {
this.detail.appendChild(messagesDiv);
this.dom.details.appendChild(this.detail);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
this.suite = suite;
this.dom = dom;
this.views = views;
this.element = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
);
this.appendToSummary(this.suite, this.element);
};
jasmine.HtmlReporter.SuiteView.prototype.status = function() {
return this.getSpecStatus(this.suite);
};
jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
this.element.className += " " + this.status();
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
/* @deprecated Use jasmine.HtmlReporter instead
*/
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.TrivialReporter.prototype.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.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('span', { className: 'title' }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onclick = function(evt) {
if (showPassed.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onclick = function(evt) {
if (showSkipped.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount === 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
var resultItems = results.getItems();
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 && !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 (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.TrivialReporter.prototype.log = function() {
var console = 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
}
}
};
jasmine.TrivialReporter.prototype.getLocation = function() {
return this.document.location;
};
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec) {
return true;
}
return spec.getFullName().indexOf(paramMap.spec) === 0;
};
#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 .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; }
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
#TrivialReporter .runner.running { background-color: yellow; }
#TrivialReporter .options { text-align: right; font-size: .8em; }
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
#TrivialReporter .suite .suite { margin: 5px; }
#TrivialReporter .suite.passed { background-color: #dfd; }
#TrivialReporter .suite.failed { background-color: #fdd; }
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
#TrivialReporter .spec.skipped { background-color: #bbb; }
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
#TrivialReporter .passed { background-color: #cfc; display: none; }
#TrivialReporter .failed { background-color: #fbb; }
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
#TrivialReporter .resultMessage .mismatch { color: black; }
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
var isCommonJS = typeof window == "undefined";
/**
* Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
*
* @namespace
*/
var jasmine = {};
if (isCommonJS) exports.jasmine = jasmine;
/**
* @private
*/
jasmine.unimplementedMethod_ = function() {
throw new Error("unimplemented method");
};
/**
* Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
* a plain old variable and may be redefined by somebody else.
*
* @private
*/
jasmine.undefined = jasmine.___undefined___;
/**
* Show diagnostic messages in the console if set to true
*
*/
jasmine.VERBOSE = false;
/**
* Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
*
*/
jasmine.DEFAULT_UPDATE_INTERVAL = 250;
/**
* Default timeout interval in milliseconds for waitsFor() blocks.
*/
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
jasmine.getGlobal = function() {
function getGlobal() {
return this;
}
return getGlobal();
};
/**
* Allows for bound functions to be compared. Internal use only.
*
* @ignore
* @private
* @param base {Object} bound 'this' for the function
* @param name {Function} function to find
*/
jasmine.bindOriginal_ = function(base, name) {
var original = base[name];
if (original.apply) {
return function() {
return original.apply(base, arguments);
};
} else {
// IE support
return jasmine.getGlobal()[name];
}
};
jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
jasmine.MessageResult = function(values) {
this.type = 'log';
this.values = values;
this.trace = new Error(); // todo: test better
};
jasmine.MessageResult.prototype.toString = function() {
var text = "";
for (var i = 0; i < this.values.length; i++) {
if (i > 0) text += " ";
if (jasmine.isString_(this.values[i])) {
text += this.values[i];
} else {
text += jasmine.pp(this.values[i]);
}
}
return text;
};
jasmine.ExpectationResult = function(params) {
this.type = 'expect';
this.matcherName = params.matcherName;
this.passed_ = params.passed;
this.expected = params.expected;
this.actual = params.actual;
this.message = this.passed_ ? 'Passed.' : params.message;
var trace = (params.trace || new Error(this.message));
this.trace = this.passed_ ? '' : trace;
};
jasmine.ExpectationResult.prototype.toString = function () {
return this.message;
};
jasmine.ExpectationResult.prototype.passed = function () {
return this.passed_;
};
/**
* Getter for the Jasmine environment. Ensures one gets created
*/
jasmine.getEnv = function() {
var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
return env;
};
/**
* @ignore
* @private
* @param value
* @returns {Boolean}
*/
jasmine.isArray_ = function(value) {
return jasmine.isA_("Array", value);
};
/**
* @ignore
* @private
* @param value
* @returns {Boolean}
*/
jasmine.isString_ = function(value) {
return jasmine.isA_("String", value);
};
/**
* @ignore
* @private
* @param value
* @returns {Boolean}
*/
jasmine.isNumber_ = function(value) {
return jasmine.isA_("Number", value);
};
/**
* @ignore
* @private
* @param {String} typeName
* @param value
* @returns {Boolean}
*/
jasmine.isA_ = function(typeName, value) {
return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
};
/**
* Pretty printer for expecations. Takes any object and turns it into a human-readable string.
*
* @param value {Object} an object to be outputted
* @returns {String}
*/
jasmine.pp = function(value) {
var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
stringPrettyPrinter.format(value);
return stringPrettyPrinter.string;
};
/**
* Returns true if the object is a DOM Node.
*
* @param {Object} obj object to check
* @returns {Boolean}
*/
jasmine.isDomNode = function(obj) {
return obj.nodeType > 0;
};
/**
* Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
*
* @example
* // don't care about which function is passed in, as long as it's a function
* expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
*
* @param {Class} clazz
* @returns matchable object of the type clazz
*/
jasmine.any = function(clazz) {
return new jasmine.Matchers.Any(clazz);
};
/**
* Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
* attributes on the object.
*
* @example
* // don't care about any other attributes than foo.
* expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
*
* @param sample {Object} sample
* @returns matchable object for the sample
*/
jasmine.objectContaining = function (sample) {
return new jasmine.Matchers.ObjectContaining(sample);
};
/**
* Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
*
* Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
* expectation syntax. Spies can be checked if they were called or not and what the calling params were.
*
* A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
*
* Spies are torn down at the end of every spec.
*
* Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
*
* @example
* // a stub
* var myStub = jasmine.createSpy('myStub'); // can be used anywhere
*
* // spy example
* var foo = {
* not: function(bool) { return !bool; }
* }
*
* // actual foo.not will not be called, execution stops
* spyOn(foo, 'not');
// foo.not spied upon, execution will continue to implementation
* spyOn(foo, 'not').andCallThrough();
*
* // fake example
* var foo = {
* not: function(bool) { return !bool; }
* }
*
* // foo.not(val) will return val
* spyOn(foo, 'not').andCallFake(function(value) {return value;});
*
* // mock example
* foo.not(7 == 7);
* expect(foo.not).toHaveBeenCalled();
* expect(foo.not).toHaveBeenCalledWith(true);
*
* @constructor
* @see spyOn, jasmine.createSpy, jasmine.createSpyObj
* @param {String} name
*/
jasmine.Spy = function(name) {
/**
* The name of the spy, if provided.
*/
this.identity = name || 'unknown';
/**
* Is this Object a spy?
*/
this.isSpy = true;
/**
* The actual function this spy stubs.
*/
this.plan = function() {
};
/**
* Tracking of the most recent call to the spy.
* @example
* var mySpy = jasmine.createSpy('foo');
* mySpy(1, 2);
* mySpy.mostRecentCall.args = [1, 2];
*/
this.mostRecentCall = {};
/**
* Holds arguments for each call to the spy, indexed by call count
* @example
* var mySpy = jasmine.createSpy('foo');
* mySpy(1, 2);
* mySpy(7, 8);
* mySpy.mostRecentCall.args = [7, 8];
* mySpy.argsForCall[0] = [1, 2];
* mySpy.argsForCall[1] = [7, 8];
*/
this.argsForCall = [];
this.calls = [];
};
/**
* Tells a spy to call through to the actual implemenatation.
*
* @example
* var foo = {
* bar: function() { // do some stuff }
* }
*
* // defining a spy on an existing property: foo.bar
* spyOn(foo, 'bar').andCallThrough();
*/
jasmine.Spy.prototype.andCallThrough = function() {
this.plan = this.originalValue;
return this;
};
/**
* For setting the return value of a spy.
*
* @example
* // defining a spy from scratch: foo() returns 'baz'
* var foo = jasmine.createSpy('spy on foo').andReturn('baz');
*
* // defining a spy on an existing property: foo.bar() returns 'baz'
* spyOn(foo, 'bar').andReturn('baz');
*
* @param {Object} value
*/
jasmine.Spy.prototype.andReturn = function(value) {
this.plan = function() {
return value;
};
return this;
};
/**
* For throwing an exception when a spy is called.
*
* @example
* // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
* var foo = jasmine.createSpy('spy on foo').andThrow('baz');
*
* // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
* spyOn(foo, 'bar').andThrow('baz');
*
* @param {String} exceptionMsg
*/
jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
this.plan = function() {
throw exceptionMsg;
};
return this;
};
/**
* Calls an alternate implementation when a spy is called.
*
* @example
* var baz = function() {
* // do some stuff, return something
* }
* // defining a spy from scratch: foo() calls the function baz
* var foo = jasmine.createSpy('spy on foo').andCall(baz);
*
* // defining a spy on an existing property: foo.bar() calls an anonymnous function
* spyOn(foo, 'bar').andCall(function() { return 'baz';} );
*
* @param {Function} fakeFunc
*/
jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
this.plan = fakeFunc;
return this;
};
/**
* Resets all of a spy's the tracking variables so that it can be used again.
*
* @example
* spyOn(foo, 'bar');
*
* foo.bar();
*
* expect(foo.bar.callCount).toEqual(1);
*
* foo.bar.reset();
*
* expect(foo.bar.callCount).toEqual(0);
*/
jasmine.Spy.prototype.reset = function() {
this.wasCalled = false;
this.callCount = 0;
this.argsForCall = [];
this.calls = [];
this.mostRecentCall = {};
};
jasmine.createSpy = function(name) {
var spyObj = function() {
spyObj.wasCalled = true;
spyObj.callCount++;
var args = jasmine.util.argsToArray(arguments);
spyObj.mostRecentCall.object = this;
spyObj.mostRecentCall.args = args;
spyObj.argsForCall.push(args);
spyObj.calls.push({object: this, args: args});
return spyObj.plan.apply(this, arguments);
};
var spy = new jasmine.Spy(name);
for (var prop in spy) {
spyObj[prop] = spy[prop];
}
spyObj.reset();
return spyObj;
};
/**
* Determines whether an object is a spy.
*
* @param {jasmine.Spy|Object} putativeSpy
* @returns {Boolean}
*/
jasmine.isSpy = function(putativeSpy) {
return putativeSpy && putativeSpy.isSpy;
};
/**
* Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
* large in one call.
*
* @param {String} baseName name of spy class
* @param {Array} methodNames array of names of methods to make spies
*/
jasmine.createSpyObj = function(baseName, methodNames) {
if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
}
var obj = {};
for (var i = 0; i < methodNames.length; i++) {
obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
}
return obj;
};
/**
* All parameters are pretty-printed and concatenated together, then written to the current spec's output.
*
* Be careful not to leave calls to <code>jasmine.log</code> in production code.
*/
jasmine.log = function() {
var spec = jasmine.getEnv().currentSpec;
spec.log.apply(spec, arguments);
};
/**
* Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
*
* @example
* // spy example
* var foo = {
* not: function(bool) { return !bool; }
* }
* spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
*
* @see jasmine.createSpy
* @param obj
* @param methodName
* @returns a Jasmine spy that can be chained with all spy methods
*/
var spyOn = function(obj, methodName) {
return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
};
if (isCommonJS) exports.spyOn = spyOn;
/**
* Creates a Jasmine spec that will be added to the current suite.
*
* // TODO: pending tests
*
* @example
* it('should be true', function() {
* expect(true).toEqual(true);
* });
*
* @param {String} desc description of this specification
* @param {Function} func defines the preconditions and expectations of the spec
*/
var it = function(desc, func) {
return jasmine.getEnv().it(desc, func);
};
if (isCommonJS) exports.it = it;
/**
* Creates a <em>disabled</em> Jasmine spec.
*
* A convenience method that allows existing specs to be disabled temporarily during development.
*
* @param {String} desc description of this specification
* @param {Function} func defines the preconditions and expectations of the spec
*/
var xit = function(desc, func) {
return jasmine.getEnv().xit(desc, func);
};
if (isCommonJS) exports.xit = xit;
/**
* Starts a chain for a Jasmine expectation.
*
* It is passed an Object that is the actual value and should chain to one of the many
* jasmine.Matchers functions.
*
* @param {Object} actual Actual value to test against and expected value
*/
var expect = function(actual) {
return jasmine.getEnv().currentSpec.expect(actual);
};
if (isCommonJS) exports.expect = expect;
/**
* Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
*
* @param {Function} func Function that defines part of a jasmine spec.
*/
var runs = function(func) {
jasmine.getEnv().currentSpec.runs(func);
};
if (isCommonJS) exports.runs = runs;
/**
* Waits a fixed time period before moving to the next block.
*
* @deprecated Use waitsFor() instead
* @param {Number} timeout milliseconds to wait
*/
var waits = function(timeout) {
jasmine.getEnv().currentSpec.waits(timeout);
};
if (isCommonJS) exports.waits = waits;
/**
* Waits for the latchFunction to return true before proceeding to the next block.
*
* @param {Function} latchFunction
* @param {String} optional_timeoutMessage
* @param {Number} optional_timeout
*/
var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
};
if (isCommonJS) exports.waitsFor = waitsFor;
/**
* A function that is called before each spec in a suite.
*
* Used for spec setup, including validating assumptions.
*
* @param {Function} beforeEachFunction
*/
var beforeEach = function(beforeEachFunction) {
jasmine.getEnv().beforeEach(beforeEachFunction);
};
if (isCommonJS) exports.beforeEach = beforeEach;
/**
* A function that is called after each spec in a suite.
*
* Used for restoring any state that is hijacked during spec execution.
*
* @param {Function} afterEachFunction
*/
var afterEach = function(afterEachFunction) {
jasmine.getEnv().afterEach(afterEachFunction);
};
if (isCommonJS) exports.afterEach = afterEach;
/**
* Defines a suite of specifications.
*
* Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
* are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
* of setup in some tests.
*
* @example
* // TODO: a simple suite
*
* // TODO: a simple suite with a nested describe block
*
* @param {String} description A string, usually the class under test.
* @param {Function} specDefinitions function that defines several specs.
*/
var describe = function(description, specDefinitions) {
return jasmine.getEnv().describe(description, specDefinitions);
};
if (isCommonJS) exports.describe = describe;
/**
* Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
*
* @param {String} description A string, usually the class under test.
* @param {Function} specDefinitions function that defines several specs.
*/
var xdescribe = function(description, specDefinitions) {
return jasmine.getEnv().xdescribe(description, specDefinitions);
};
if (isCommonJS) exports.xdescribe = xdescribe;
// Provide the XMLHttpRequest class for IE 5.x-6.x:
jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
function tryIt(f) {
try {
return f();
} catch(e) {
}
return null;
}
var xhr = tryIt(function() {
return new ActiveXObject("Msxml2.XMLHTTP.6.0");
}) ||
tryIt(function() {
return new ActiveXObject("Msxml2.XMLHTTP.3.0");
}) ||
tryIt(function() {
return new ActiveXObject("Msxml2.XMLHTTP");
}) ||
tryIt(function() {
return new ActiveXObject("Microsoft.XMLHTTP");
});
if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
return xhr;
} : XMLHttpRequest;
/**
* @namespace
*/
jasmine.util = {};
/**
* Declare that a child class inherit it's prototype from the parent class.
*
* @private
* @param {Function} childClass
* @param {Function} parentClass
*/
jasmine.util.inherit = function(childClass, parentClass) {
/**
* @private
*/
var subclass = function() {
};
subclass.prototype = parentClass.prototype;
childClass.prototype = new subclass();
};
jasmine.util.formatException = function(e) {
var lineNumber;
if (e.line) {
lineNumber = e.line;
}
else if (e.lineNumber) {
lineNumber = e.lineNumber;
}
var file;
if (e.sourceURL) {
file = e.sourceURL;
}
else if (e.fileName) {
file = e.fileName;
}
var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
if (file && lineNumber) {
message += ' in ' + file + ' (line ' + lineNumber + ')';
}
return message;
};
jasmine.util.htmlEscape = function(str) {
if (!str) return str;
return str.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
};
jasmine.util.argsToArray = function(args) {
var arrayOfArgs = [];
for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
return arrayOfArgs;
};
jasmine.util.extend = function(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
};
/**
* Environment for Jasmine
*
* @constructor
*/
jasmine.Env = function() {
this.currentSpec = null;
this.currentSuite = null;
this.currentRunner_ = new jasmine.Runner(this);
this.reporter = new jasmine.MultiReporter();
this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
this.lastUpdate = 0;
this.specFilter = function() {
return true;
};
this.nextSpecId_ = 0;
this.nextSuiteId_ = 0;
this.equalityTesters_ = [];
// wrap matchers
this.matchersClass = function() {
jasmine.Matchers.apply(this, arguments);
};
jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
};
jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
jasmine.Env.prototype.setInterval = jasmine.setInterval;
jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
/**
* @returns an object containing jasmine version build info, if set.
*/
jasmine.Env.prototype.version = function () {
if (jasmine.version_) {
return jasmine.version_;
} else {
throw new Error('Version not set');
}
};
/**
* @returns string containing jasmine version build info, if set.
*/
jasmine.Env.prototype.versionString = function() {
if (!jasmine.version_) {
return "version unknown";
}
var version = this.version();
var versionString = version.major + "." + version.minor + "." + version.build;
if (version.release_candidate) {
versionString += ".rc" + version.release_candidate;
}
versionString += " revision " + version.revision;
return versionString;
};
/**
* @returns a sequential integer starting at 0
*/
jasmine.Env.prototype.nextSpecId = function () {
return this.nextSpecId_++;
};
/**
* @returns a sequential integer starting at 0
*/
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.
*/
jasmine.Env.prototype.addReporter = function(reporter) {
this.reporter.addReporter(reporter);
};
jasmine.Env.prototype.execute = function() {
this.currentRunner_.execute();
};
jasmine.Env.prototype.describe = function(description, specDefinitions) {
var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
var parentSuite = this.currentSuite;
if (parentSuite) {
parentSuite.add(suite);
} else {
this.currentRunner_.add(suite);
}
this.currentSuite = suite;
var declarationError = null;
try {
specDefinitions.call(suite);
} catch(e) {
declarationError = e;
}
if (declarationError) {
this.it("encountered a declaration exception", function() {
throw declarationError;
});
}
this.currentSuite = parentSuite;
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() {
}
};
};
jasmine.Env.prototype.it = function(description, func) {
var spec = new jasmine.Spec(this, this.currentSuite, description);
this.currentSuite.add(spec);
this.currentSpec = spec;
if (func) {
spec.runs(func);
}
return spec;
};
jasmine.Env.prototype.xit = function(desc, func) {
return {
id: this.nextSpecId(),
runs: function() {
}
};
};
jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
return true;
}
a.__Jasmine_been_here_before__ = b;
b.__Jasmine_been_here_before__ = a;
var hasKey = function(obj, keyName) {
return obj !== null && obj[keyName] !== jasmine.undefined;
};
for (var property in b) {
if (!hasKey(a, property) && hasKey(b, property)) {
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
}
}
for (property in a) {
if (!hasKey(b, property) && hasKey(a, property)) {
mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
}
}
for (property in b) {
if (property == '__Jasmine_been_here_before__') continue;
if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
}
}
if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
mismatchValues.push("arrays were not the same length");
}
delete a.__Jasmine_been_here_before__;
delete b.__Jasmine_been_here_before__;
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
};
jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
mismatchKeys = mismatchKeys || [];
mismatchValues = mismatchValues || [];
for (var i = 0; i < this.equalityTesters_.length; i++) {
var equalityTester = this.equalityTesters_[i];
var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
if (result !== jasmine.undefined) return result;
}
if (a === b) return true;
if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
return (a == jasmine.undefined && b == jasmine.undefined);
}
if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
return a === b;
}
if (a instanceof Date && b instanceof Date) {
return a.getTime() == b.getTime();
}
if (a.jasmineMatches) {
return a.jasmineMatches(b);
}
if (b.jasmineMatches) {
return b.jasmineMatches(a);
}
if (a instanceof jasmine.Matchers.ObjectContaining) {
return a.matches(b);
}
if (b instanceof jasmine.Matchers.ObjectContaining) {
return b.matches(a);
}
if (jasmine.isString_(a) && jasmine.isString_(b)) {
return (a == b);
}
if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
return (a == b);
}
if (typeof a === "object" && typeof b === "object") {
return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
}
//Straight check
return (a === b);
};
jasmine.Env.prototype.contains_ = function(haystack, needle) {
if (jasmine.isArray_(haystack)) {
for (var i = 0; i < haystack.length; i++) {
if (this.equals_(haystack[i], needle)) return true;
}
return false;
}
return haystack.indexOf(needle) >= 0;
};
jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
this.equalityTesters_.push(equalityTester);
};
/** 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) {
};
/**
* Blocks are functions with executable code that make up a spec.
*
* @constructor
* @param {jasmine.Env} env
* @param {Function} func
* @param {jasmine.Spec} spec
*/
jasmine.Block = function(env, func, spec) {
this.env = env;
this.func = func;
this.spec = spec;
};
jasmine.Block.prototype.execute = function(onComplete) {
try {
this.func.apply(this.spec);
} catch (e) {
this.spec.fail(e);
}
onComplete();
};
/** JavaScript API reporter.
*
* @constructor
*/
jasmine.JsApiReporter = function() {
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));
}
};
jasmine.JsApiReporter.prototype.suites = function() {
return this.suites_;
};
jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
var isSuite = suiteOrSpec instanceof jasmine.Suite;
var summary = {
id: suiteOrSpec.id,
name: suiteOrSpec.description,
type: isSuite ? 'suite' : 'spec',
children: []
};
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_;
};
jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
return this.results_[specId];
};
//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(spec) {
this.results_[spec.id] = {
messages: spec.results().getItems(),
result: spec.results().failedCount > 0 ? "failed" : "passed"
};
};
//noinspection JSUnusedLocalSymbols
jasmine.JsApiReporter.prototype.log = function(str) {
};
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];
summaryMessages.push({
text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
passed: resultMessage.passed ? resultMessage.passed() : true,
type: resultMessage.type,
message: resultMessage.message,
trace: {
stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
}
});
}
return {
result : result.result,
messages : summaryMessages
};
};
/**
* @constructor
* @param {jasmine.Env} env
* @param actual
* @param {jasmine.Spec} spec
*/
jasmine.Matchers = function(env, actual, spec, opt_isNot) {
this.env = env;
this.actual = actual;
this.spec = spec;
this.isNot = opt_isNot || false;
this.reportWasCalled_ = false;
};
// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
jasmine.Matchers.pp = function(str) {
throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
};
// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
jasmine.Matchers.prototype.report = function(result, failing_message, details) {
throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
};
jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
for (var methodName in prototype) {
if (methodName == 'report') continue;
var orig = prototype[methodName];
matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
}
};
jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
return function() {
var matcherArgs = jasmine.util.argsToArray(arguments);
var result = matcherFunction.apply(this, arguments);
if (this.isNot) {
result = !result;
}
if (this.reportWasCalled_) return result;
var message;
if (!result) {
if (this.message) {
message = this.message.apply(this, arguments);
if (jasmine.isArray_(message)) {
message = message[this.isNot ? 1 : 0];
}
} else {
var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
if (matcherArgs.length > 0) {
for (var i = 0; i < matcherArgs.length; i++) {
if (i > 0) message += ",";
message += " " + jasmine.pp(matcherArgs[i]);
}
}
message += ".";
}
}
var expectationResult = new jasmine.ExpectationResult({
matcherName: matcherName,
passed: result,
expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
actual: this.actual,
message: message
});
this.spec.addMatcherResult(expectationResult);
return jasmine.undefined;
};
};
/**
* toBe: compares the actual to the expected using ===
* @param expected
*/
jasmine.Matchers.prototype.toBe = function(expected) {
return this.actual === expected;
};
/**
* toNotBe: compares the actual to the expected using !==
* @param expected
* @deprecated as of 1.0. Use not.toBe() instead.
*/
jasmine.Matchers.prototype.toNotBe = function(expected) {
return this.actual !== expected;
};
/**
* toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
*
* @param expected
*/
jasmine.Matchers.prototype.toEqual = function(expected) {
return this.env.equals_(this.actual, expected);
};
/**
* toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
* @param expected
* @deprecated as of 1.0. Use not.toEqual() instead.
*/
jasmine.Matchers.prototype.toNotEqual = function(expected) {
return !this.env.equals_(this.actual, expected);
};
/**
* Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
* a pattern or a String.
*
* @param expected
*/
jasmine.Matchers.prototype.toMatch = function(expected) {
return new RegExp(expected).test(this.actual);
};
/**
* Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
* @param expected
* @deprecated as of 1.0. Use not.toMatch() instead.
*/
jasmine.Matchers.prototype.toNotMatch = function(expected) {
return !(new RegExp(expected).test(this.actual));
};
/**
* Matcher that compares the actual to jasmine.undefined.
*/
jasmine.Matchers.prototype.toBeDefined = function() {
return (this.actual !== jasmine.undefined);
};
/**
* Matcher that compares the actual to jasmine.undefined.
*/
jasmine.Matchers.prototype.toBeUndefined = function() {
return (this.actual === jasmine.undefined);
};
/**
* Matcher that compares the actual to null.
*/
jasmine.Matchers.prototype.toBeNull = function() {
return (this.actual === null);
};
/**
* Matcher that boolean not-nots the actual.
*/
jasmine.Matchers.prototype.toBeTruthy = function() {
return !!this.actual;
};
/**
* Matcher that boolean nots the actual.
*/
jasmine.Matchers.prototype.toBeFalsy = function() {
return !this.actual;
};
/**
* Matcher that checks to see if the actual, a Jasmine spy, was called.
*/
jasmine.Matchers.prototype.toHaveBeenCalled = function() {
if (arguments.length > 0) {
throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
}
if (!jasmine.isSpy(this.actual)) {
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
}
this.message = function() {
return [
"Expected spy " + this.actual.identity + " to have been called.",
"Expected spy " + this.actual.identity + " not to have been called."
];
};
return this.actual.wasCalled;
};
/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
/**
* Matcher that checks to see if the actual, a Jasmine spy, was not called.
*
* @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
*/
jasmine.Matchers.prototype.wasNotCalled = function() {
if (arguments.length > 0) {
throw new Error('wasNotCalled does not take arguments');
}
if (!jasmine.isSpy(this.actual)) {
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
}
this.message = function() {
return [
"Expected spy " + this.actual.identity + " to not have been called.",
"Expected spy " + this.actual.identity + " to have been called."
];
};
return !this.actual.wasCalled;
};
/**
* Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
*
* @example
*
*/
jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
var expectedArgs = jasmine.util.argsToArray(arguments);
if (!jasmine.isSpy(this.actual)) {
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
}
this.message = function() {
if (this.actual.callCount === 0) {
// todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
return [
"Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
"Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
];
} else {
return [
"Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
"Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
];
}
};
return this.env.contains_(this.actual.argsForCall, expectedArgs);
};
/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
jasmine.Matchers.prototype.wasNotCalledWith = function() {
var expectedArgs = jasmine.util.argsToArray(arguments);
if (!jasmine.isSpy(this.actual)) {
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
}
this.message = function() {
return [
"Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
"Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
];
};
return !this.env.contains_(this.actual.argsForCall, expectedArgs);
};
/**
* Matcher that checks that the expected item is an element in the actual Array.
*
* @param {Object} expected
*/
jasmine.Matchers.prototype.toContain = function(expected) {
return this.env.contains_(this.actual, expected);
};
/**
* Matcher that checks that the expected item is NOT an element in the actual Array.
*
* @param {Object} expected
* @deprecated as of 1.0. Use not.toContain() instead.
*/
jasmine.Matchers.prototype.toNotContain = function(expected) {
return !this.env.contains_(this.actual, expected);
};
jasmine.Matchers.prototype.toBeLessThan = function(expected) {
return this.actual < expected;
};
jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
return this.actual > expected;
};
/**
* Matcher that checks that the expected item is equal to the actual item
* up to a given level of decimal precision (default 2).
*
* @param {Number} expected
* @param {Number} precision
*/
jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
if (!(precision === 0)) {
precision = precision || 2;
}
var multiplier = Math.pow(10, precision);
var actual = Math.round(this.actual * multiplier);
expected = Math.round(expected * multiplier);
return expected == actual;
};
/**
* Matcher that checks that the expected exception was thrown by the actual.
*
* @param {String} expected
*/
jasmine.Matchers.prototype.toThrow = function(expected) {
var result = false;
var exception;
if (typeof this.actual != 'function') {
throw new Error('Actual is not a function');
}
try {
this.actual();
} catch (e) {
exception = e;
}
if (exception) {
result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
}
var not = this.isNot ? "not " : "";
this.message = function() {
if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
} else {
return "Expected function to throw an exception.";
}
};
return result;
};
jasmine.Matchers.Any = function(expectedClass) {
this.expectedClass = expectedClass;
};
jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
if (this.expectedClass == String) {
return typeof other == 'string' || other instanceof String;
}
if (this.expectedClass == Number) {
return typeof other == 'number' || other instanceof Number;
}
if (this.expectedClass == Function) {
return typeof other == 'function' || other instanceof Function;
}
if (this.expectedClass == Object) {
return typeof other == 'object';
}
return other instanceof this.expectedClass;
};
jasmine.Matchers.Any.prototype.jasmineToString = function() {
return '<jasmine.any(' + this.expectedClass + ')>';
};
jasmine.Matchers.ObjectContaining = function (sample) {
this.sample = sample;
};
jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
mismatchKeys = mismatchKeys || [];
mismatchValues = mismatchValues || [];
var env = jasmine.getEnv();
var hasKey = function(obj, keyName) {
return obj != null && obj[keyName] !== jasmine.undefined;
};
for (var property in this.sample) {
if (!hasKey(other, property) && hasKey(this.sample, property)) {
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
}
else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
}
}
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
};
jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
};
// Mock setTimeout, clearTimeout
// Contributed by Pivotal Computer Systems, www.pivotalsf.com
jasmine.FakeTimer = function() {
this.reset();
var self = this;
self.setTimeout = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
return self.timeoutsMade;
};
self.setInterval = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
return self.timeoutsMade;
};
self.clearTimeout = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
self.clearInterval = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
};
jasmine.FakeTimer.prototype.reset = function() {
this.timeoutsMade = 0;
this.scheduledFunctions = {};
this.nowMillis = 0;
};
jasmine.FakeTimer.prototype.tick = function(millis) {
var oldMillis = this.nowMillis;
var newMillis = oldMillis + millis;
this.runFunctionsWithinRange(oldMillis, newMillis);
this.nowMillis = newMillis;
};
jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
var scheduledFunc;
var funcsToRun = [];
for (var timeoutKey in this.scheduledFunctions) {
scheduledFunc = this.scheduledFunctions[timeoutKey];
if (scheduledFunc != jasmine.undefined &&
scheduledFunc.runAtMillis >= oldMillis &&
scheduledFunc.runAtMillis <= nowMillis) {
funcsToRun.push(scheduledFunc);
this.scheduledFunctions[timeoutKey] = jasmine.undefined;
}
}
if (funcsToRun.length > 0) {
funcsToRun.sort(function(a, b) {
return a.runAtMillis - b.runAtMillis;
});
for (var i = 0; i < funcsToRun.length; ++i) {
try {
var funcToRun = funcsToRun[i];
this.nowMillis = funcToRun.runAtMillis;
funcToRun.funcToCall();
if (funcToRun.recurring) {
this.scheduleFunction(funcToRun.timeoutKey,
funcToRun.funcToCall,
funcToRun.millis,
true);
}
} catch(e) {
}
}
this.runFunctionsWithinRange(oldMillis, nowMillis);
}
};
jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
this.scheduledFunctions[timeoutKey] = {
runAtMillis: this.nowMillis + millis,
funcToCall: funcToCall,
recurring: recurring,
timeoutKey: timeoutKey,
millis: millis
};
};
/**
* @namespace
*/
jasmine.Clock = {
defaultFakeTimer: new jasmine.FakeTimer(),
reset: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.reset();
},
tick: function(millis) {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.tick(millis);
},
runFunctionsWithinRange: function(oldMillis, nowMillis) {
jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
},
scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
},
useMock: function() {
if (!jasmine.Clock.isInstalled()) {
var spec = jasmine.getEnv().currentSpec;
spec.after(jasmine.Clock.uninstallMock);
jasmine.Clock.installMock();
}
},
installMock: function() {
jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
},
uninstallMock: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.installed = jasmine.Clock.real;
},
real: {
setTimeout: jasmine.getGlobal().setTimeout,
clearTimeout: jasmine.getGlobal().clearTimeout,
setInterval: jasmine.getGlobal().setInterval,
clearInterval: jasmine.getGlobal().clearInterval
},
assertInstalled: function() {
if (!jasmine.Clock.isInstalled()) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
isInstalled: function() {
return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
if (jasmine.Clock.installed.setTimeout.apply) {
return jasmine.Clock.installed.setTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.setTimeout(funcToCall, millis);
}
};
jasmine.getGlobal().setInterval = function(funcToCall, millis) {
if (jasmine.Clock.installed.setInterval.apply) {
return jasmine.Clock.installed.setInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.setInterval(funcToCall, millis);
}
};
jasmine.getGlobal().clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
jasmine.getGlobal().clearInterval = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearInterval(timeoutKey);
}
};
/**
* @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);
}
})();
/**
* Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
*
* @constructor
*/
jasmine.NestedResults = function() {
/**
* The total count of results
*/
this.totalCount = 0;
/**
* Number of passed results
*/
this.passedCount = 0;
/**
* Number of failed results
*/
this.failedCount = 0;
/**
* Was this suite/spec skipped?
*/
this.skipped = false;
/**
* @ignore
*/
this.items_ = [];
};
/**
* Roll up the result counts.
*
* @param result
*/
jasmine.NestedResults.prototype.rollupCounts = function(result) {
this.totalCount += result.totalCount;
this.passedCount += result.passedCount;
this.failedCount += result.failedCount;
};
/**
* Adds a log message.
* @param values Array of message parts which will be concatenated later.
*/
jasmine.NestedResults.prototype.log = function(values) {
this.items_.push(new jasmine.MessageResult(values));
};
/**
* Getter for the results: message & results.
*/
jasmine.NestedResults.prototype.getItems = function() {
return this.items_;
};
/**
* Adds a result, tracking counts (total, passed, & failed)
* @param {jasmine.ExpectationResult|jasmine.NestedResults} result
*/
jasmine.NestedResults.prototype.addResult = function(result) {
if (result.type != 'log') {
if (result.items_) {
this.rollupCounts(result);
} else {
this.totalCount++;
if (result.passed()) {
this.passedCount++;
} else {
this.failedCount++;
}
}
}
this.items_.push(result);
};
/**
* @returns {Boolean} True if <b>everything</b> below passed
*/
jasmine.NestedResults.prototype.passed = function() {
return this.passedCount === this.totalCount;
};
/**
* Base class for pretty printing for expectation results.
*/
jasmine.PrettyPrinter = function() {
this.ppNestLevel_ = 0;
};
/**
* Formats a value in a nice, human-readable string.
*
* @param value
*/
jasmine.PrettyPrinter.prototype.format = function(value) {
if (this.ppNestLevel_ > 40) {
throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
}
this.ppNestLevel_++;
try {
if (value === jasmine.undefined) {
this.emitScalar('undefined');
} else if (value === null) {
this.emitScalar('null');
} else if (value === jasmine.getGlobal()) {
this.emitScalar('<global>');
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString());
} else if (typeof value === 'string') {
this.emitString(value);
} else if (jasmine.isSpy(value)) {
this.emitScalar("spy on " + value.identity);
} else if (value instanceof RegExp) {
this.emitScalar(value.toString());
} else if (typeof value === 'function') {
this.emitScalar('Function');
} else if (typeof value.nodeType === 'number') {
this.emitScalar('HTMLNode');
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (value.__Jasmine_been_here_before__) {
this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
} else if (jasmine.isArray_(value) || typeof value == 'object') {
value.__Jasmine_been_here_before__ = true;
if (jasmine.isArray_(value)) {
this.emitArray(value);
} else {
this.emitObject(value);
}
delete value.__Jasmine_been_here_before__;
} else {
this.emitScalar(value.toString());
}
} finally {
this.ppNestLevel_--;
}
};
jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
for (var property in obj) {
if (property == '__Jasmine_been_here_before__') continue;
fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
obj.__lookupGetter__(property) !== null) : false);
}
};
jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
jasmine.StringPrettyPrinter = function() {
jasmine.PrettyPrinter.call(this);
this.string = '';
};
jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
this.append(value);
};
jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
this.append("'" + value + "'");
};
jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
this.append('[ ');
for (var i = 0; i < array.length; i++) {
if (i > 0) {
this.append(', ');
}
this.format(array[i]);
}
this.append(' ]');
};
jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
var self = this;
this.append('{ ');
var first = true;
this.iterateObject(obj, function(property, isGetter) {
if (first) {
first = false;
} else {
self.append(', ');
}
self.append(property);
self.append(' : ');
if (isGetter) {
self.append('<getter>');
} else {
self.format(obj[property]);
}
});
this.append(' }');
};
jasmine.StringPrettyPrinter.prototype.append = function(value) {
this.string += value;
};
jasmine.Queue = function(env) {
this.env = env;
this.blocks = [];
this.running = false;
this.index = 0;
this.offset = 0;
this.abort = false;
};
jasmine.Queue.prototype.addBefore = function(block) {
this.blocks.unshift(block);
};
jasmine.Queue.prototype.add = function(block) {
this.blocks.push(block);
};
jasmine.Queue.prototype.insertNext = function(block) {
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.next_ = function() {
var self = this;
var goAgain = true;
while (goAgain) {
goAgain = false;
if (self.index < self.blocks.length && !this.abort) {
var calledSynchronously = true;
var completedSynchronously = false;
var onComplete = function () {
if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
completedSynchronously = true;
return;
}
if (self.blocks[self.index].abort) {
self.abort = true;
}
self.offset = 0;
self.index++;
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(onComplete);
calledSynchronously = false;
if (completedSynchronously) {
onComplete();
}
} else {
self.running = false;
if (self.onComplete) {
self.onComplete();
}
}
}
};
jasmine.Queue.prototype.results = function() {
var results = new jasmine.NestedResults();
for (var i = 0; i < this.blocks.length; i++) {
if (this.blocks[i].results) {
results.addResult(this.blocks[i].results());
}
}
return results;
};
/**
* Runner
*
* @constructor
* @param {jasmine.Env} env
*/
jasmine.Runner = function(env) {
var self = this;
self.env = env;
self.queue = new jasmine.Queue(env);
self.before_ = [];
self.after_ = [];
self.suites_ = [];
};
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);
};
jasmine.Runner.prototype.add = function(block) {
if (block instanceof jasmine.Suite) {
this.addSuite(block);
}
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;
};
jasmine.Runner.prototype.results = function() {
return this.queue.results();
};
/**
* Internal representation of a Jasmine specification, or test.
*
* @constructor
* @param {jasmine.Env} env
* @param {jasmine.Suite} suite
* @param {String} description
*/
jasmine.Spec = function(env, suite, description) {
if (!env) {
throw new Error('jasmine.Env() required');
}
if (!suite) {
throw new Error('jasmine.Suite() required');
}
var spec = this;
spec.id = env.nextSpecId ? env.nextSpecId() : null;
spec.env = env;
spec.suite = suite;
spec.description = description;
spec.queue = new jasmine.Queue(env);
spec.afterCallbacks = [];
spec.spies_ = [];
spec.results_ = new jasmine.NestedResults();
spec.results_.description = description;
spec.matchersClass = null;
};
jasmine.Spec.prototype.getFullName = function() {
return this.suite.getFullName() + ' ' + this.description + '.';
};
jasmine.Spec.prototype.results = function() {
return this.results_;
};
/**
* All parameters are pretty-printed and concatenated together, then written to the spec's output.
*
* Be careful not to leave calls to <code>jasmine.log</code> in production code.
*/
jasmine.Spec.prototype.log = function() {
return this.results_.log(arguments);
};
jasmine.Spec.prototype.runs = function (func) {
var block = new jasmine.Block(this.env, func, this);
this.addToQueue(block);
return this;
};
jasmine.Spec.prototype.addToQueue = function (block) {
if (this.queue.isRunning()) {
this.queue.insertNext(block);
} else {
this.queue.add(block);
}
};
/**
* @param {jasmine.ExpectationResult} result
*/
jasmine.Spec.prototype.addMatcherResult = function(result) {
this.results_.addResult(result);
};
jasmine.Spec.prototype.expect = function(actual) {
var positive = new (this.getMatchersClass_())(this.env, actual, this);
positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
return positive;
};
/**
* Waits a fixed time period before moving to the next block.
*
* @deprecated Use waitsFor() instead
* @param {Number} timeout milliseconds to wait
*/
jasmine.Spec.prototype.waits = function(timeout) {
var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
this.addToQueue(waitsFunc);
return this;
};
/**
* Waits for the latchFunction to return true before proceeding to the next block.
*
* @param {Function} latchFunction
* @param {String} optional_timeoutMessage
* @param {Number} optional_timeout
*/
jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
var latchFunction_ = null;
var optional_timeoutMessage_ = null;
var optional_timeout_ = null;
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
switch (typeof arg) {
case 'function':
latchFunction_ = arg;
break;
case 'string':
optional_timeoutMessage_ = arg;
break;
case 'number':
optional_timeout_ = arg;
break;
}
}
var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
this.addToQueue(waitsForFunc);
return this;
};
jasmine.Spec.prototype.fail = function (e) {
var expectationResult = new jasmine.ExpectationResult({
passed: false,
message: e ? jasmine.util.formatException(e) : 'Exception',
trace: { stack: e.stack }
});
this.results_.addResult(expectationResult);
};
jasmine.Spec.prototype.getMatchersClass_ = function() {
return this.matchersClass || this.env.matchersClass;
};
jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
var parent = this.getMatchersClass_();
var newMatchersClass = function() {
parent.apply(this, arguments);
};
jasmine.util.inherit(newMatchersClass, parent);
jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
this.matchersClass = newMatchersClass;
};
jasmine.Spec.prototype.finishCallback = function() {
this.env.reporter.reportSpecResults(this);
};
jasmine.Spec.prototype.finish = function(onComplete) {
this.removeAllSpies();
this.finishCallback();
if (onComplete) {
onComplete();
}
};
jasmine.Spec.prototype.after = function(doAfter) {
if (this.queue.isRunning()) {
this.queue.add(new jasmine.Block(this.env, doAfter, this));
} else {
this.afterCallbacks.unshift(doAfter);
}
};
jasmine.Spec.prototype.execute = function(onComplete) {
var spec = this;
if (!spec.env.specFilter(spec)) {
spec.results_.skipped = true;
spec.finish(onComplete);
return;
}
this.env.reporter.reportSpecStarting(this);
spec.env.currentSpec = spec;
spec.addBeforesAndAftersToQueue();
spec.queue.start(function () {
spec.finish(onComplete);
});
};
jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
var runner = this.env.currentRunner();
var i;
for (var suite = this.suite; suite; suite = suite.parentSuite) {
for (i = 0; i < suite.before_.length; i++) {
this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
}
}
for (i = 0; i < runner.before_.length; i++) {
this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
}
for (i = 0; i < this.afterCallbacks.length; i++) {
this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
}
for (suite = this.suite; suite; suite = suite.parentSuite) {
for (i = 0; i < suite.after_.length; i++) {
this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
}
}
for (i = 0; i < runner.after_.length; i++) {
this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
}
};
jasmine.Spec.prototype.explodes = function() {
throw 'explodes function should not have been called';
};
jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
if (obj == jasmine.undefined) {
throw "spyOn could not find an object to spy upon for " + methodName + "()";
}
if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
throw methodName + '() method does not exist';
}
if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
throw new Error(methodName + ' has already been spied upon');
}
var spyObj = jasmine.createSpy(methodName);
this.spies_.push(spyObj);
spyObj.baseObj = obj;
spyObj.methodName = methodName;
spyObj.originalValue = obj[methodName];
obj[methodName] = spyObj;
return spyObj;
};
jasmine.Spec.prototype.removeAllSpies = function() {
for (var i = 0; i < this.spies_.length; i++) {
var spy = this.spies_[i];
spy.baseObj[spy.methodName] = spy.originalValue;
}
this.spies_ = [];
};
/**
* Internal representation of a Jasmine suite.
*
* @constructor
* @param {jasmine.Env} env
* @param {String} description
* @param {Function} specDefinitions
* @param {jasmine.Suite} parentSuite
*/
jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
var self = this;
self.id = env.nextSuiteId ? env.nextSuiteId() : null;
self.description = description;
self.queue = new jasmine.Queue(env);
self.parentSuite = parentSuite;
self.env = env;
self.before_ = [];
self.after_ = [];
self.children_ = [];
self.suites_ = [];
self.specs_ = [];
};
jasmine.Suite.prototype.getFullName = function() {
var fullName = this.description;
for (var parentSuite = this.parentSuite; parentSuite; parentSuite = 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.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.unshift(beforeEachFunction);
};
jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
afterEachFunction.typeName = 'afterEach';
this.after_.unshift(afterEachFunction);
};
jasmine.Suite.prototype.results = function() {
return this.queue.results();
};
jasmine.Suite.prototype.add = function(suiteOrSpec) {
this.children_.push(suiteOrSpec);
if (suiteOrSpec instanceof jasmine.Suite) {
this.suites_.push(suiteOrSpec);
this.env.currentRunner().addSuite(suiteOrSpec);
} else {
this.specs_.push(suiteOrSpec);
}
this.queue.add(suiteOrSpec);
};
jasmine.Suite.prototype.specs = function() {
return this.specs_;
};
jasmine.Suite.prototype.suites = function() {
return this.suites_;
};
jasmine.Suite.prototype.children = function() {
return this.children_;
};
jasmine.Suite.prototype.execute = function(onComplete) {
var self = this;
this.queue.start(function () {
self.finish(onComplete);
});
};
jasmine.WaitsBlock = function(env, timeout, spec) {
this.timeout = timeout;
jasmine.Block.call(this, env, null, spec);
};
jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
jasmine.WaitsBlock.prototype.execute = function (onComplete) {
if (jasmine.VERBOSE) {
this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
}
this.env.setTimeout(function () {
onComplete();
}, this.timeout);
};
/**
* A block which waits for some condition to become true, with timeout.
*
* @constructor
* @extends jasmine.Block
* @param {jasmine.Env} env The Jasmine environment.
* @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
* @param {Function} latchFunction A function which returns true when the desired condition has been met.
* @param {String} message The message to display if the desired condition hasn't been met within the given time period.
* @param {jasmine.Spec} spec The Jasmine spec.
*/
jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
this.timeout = timeout || env.defaultTimeoutInterval;
this.latchFunction = latchFunction;
this.message = message;
this.totalTimeSpentWaitingForLatch = 0;
jasmine.Block.call(this, env, null, spec);
};
jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
if (jasmine.VERBOSE) {
this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
}
var latchFunctionResult;
try {
latchFunctionResult = this.latchFunction.apply(this.spec);
} catch (e) {
this.spec.fail(e);
onComplete();
return;
}
if (latchFunctionResult) {
onComplete();
} else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
this.spec.fail({
name: 'timeout',
message: message
});
this.abort = true;
onComplete();
} else {
this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
var self = this;
this.env.setTimeout(function() {
self.execute(onComplete);
}, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
}
};
jasmine.version_= {
"major": 1,
"minor": 2,
"build": 0,
"revision": 1337005947
};
...@@ -5,19 +5,14 @@ ...@@ -5,19 +5,14 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>ember.js + require.js • TodoMVC</title> <title>ember.js + require.js • TodoMVC</title>
<link rel="stylesheet" href="../../assets/base.css"> <link rel="stylesheet" href="../../assets/base.css">
<link rel="stylesheet" href="../../assets/jasmine/jasmine.css">
<link rel="stylesheet" href="css/app.css"> <link rel="stylesheet" href="css/app.css">
<!--[if IE]> <!--[if IE]>
<script src="../../assets/ie.js"></script> <script src="../../assets/ie.js"></script>
<![endif]--> <![endif]-->
</head> </head>
<body> <body>
<section id="todoapp"> <section id="todoapp"></section>
<header id="header">
<h1>todos</h1>
</header>
<section id="main"></section>
<footer id="footer"></footer>
</section>
<footer id="info"> <footer id="info">
<p>Double-click to edit a todo</p> <p>Double-click to edit a todo</p>
<p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p> <p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p>
......
...@@ -3,64 +3,37 @@ require.config({ ...@@ -3,64 +3,37 @@ require.config({
baseUrl: 'js/', baseUrl: 'js/',
paths: { paths: {
jquery: '../../../assets/jquery.min', jquery: '../../../assets/jquery.min',
ember: 'lib/ember-0.9.8.1.min', // ember: 'http://cloud.github.com/downloads/emberjs/ember.js/ember-latest.min',
ember: 'lib/ember-latest',
text: 'lib/require/text', text: 'lib/require/text',
mocha: 'lib/mocha', jasmine: '../../../assets/jasmine/jasmine',
chai: 'lib/chai' jasmine_html: '../../../assets/jasmine/jasmine-html'
} }
}); });
// Load our app // Load our app
define( 'app', [ define( 'app', [
'jquery', 'app/router',
'app/models/store', 'app/models/store',
'app/controllers/todos', 'app/controllers/entries',
'ember', 'app/views/application',
], function( $, Store, TodosController ) { 'jquery',
'ember'
], function( Router, Store, EntriesController, ApplicationView ) {
var App = Ember.Application.create({ var App = Ember.Application.create({
VERSION: '0.2',
VERSION: '0.2-omfg', rootElement: '#todoapp',
// Load routes
// Sets up mocha to run some integration tests Router: Router,
specsRunner: function( chai ) { // Extend to inherit outlet support
// Create placeholder for mocha output ApplicationController: Ember.Controller.extend(),
// TODO: Make this shit look better and inside body ApplicationView: ApplicationView,
$( document.body ).before( '<div id="mocha"></div>' ); entriesController: EntriesController.create(
{ store: new Store( 'todos-emberjs' ) }
// Setup mocha and expose chai matchers )
window.expect = chai.expect;
mocha.setup('bdd');
// Load testsuite
require([
'app/specs/models/store',
'app/specs/views/basic_acceptance',
'app/specs/controllers/todos'
], function() {
mocha.run().globals( [ '$', 'Ember', 'Todos' ] );
}
);
},
// Constructor
init: function() {
this._super();
// Initiate main controller
this.set(
'todosController',
TodosController.create({
store: new Store( 'todos-emberjs' )
})
);
// Run specs if asked
if ( location.hash.match( /specs/ ) ) {
require( [ 'chai', 'mocha' ], this.specsRunner );
}
}
}); });
App.initialize();
// Expose the application globally // Expose the application globally
return window.Todos = App; return window.Todos = App;
} }
......
define('app/controllers/entries', ['ember'], define('app/controllers/entries', [ 'ember' ],
/** /**
* Entries controller * Entries controller
* *
...@@ -23,7 +23,6 @@ define('app/controllers/entries', ['ember'], ...@@ -23,7 +23,6 @@ define('app/controllers/entries', ['ember'],
}, },
removeObject: function( item ) { removeObject: function( item ) {
item = item.get( 'todo' ) || item;
this.get( 'store' ).remove( item ); this.get( 'store' ).remove( item );
return this._super( item ); return this._super( item );
}, },
...@@ -46,6 +45,10 @@ define('app/controllers/entries', ['ember'], ...@@ -46,6 +45,10 @@ define('app/controllers/entries', ['ember'],
return this.filterProperty( 'completed', true ).get( 'length' ); return this.filterProperty( 'completed', true ).get( 'length' );
}.property( '@each.completed' ), }.property( '@each.completed' ),
noneLeft: function() {
return this.get( 'total' ) === 0;
}.property( 'total' ),
allAreDone: function( key, value ) { allAreDone: function( key, value ) {
if ( value !== undefined ) { if ( value !== undefined ) {
this.setEach( 'completed', value ); this.setEach( 'completed', value );
......
define('app/controllers/todos', [ define('app/controllers/todos', [ 'ember' ],
'app/controllers/entries',
'text!app/views/clear_button.html',
'text!app/views/items.html'
],
/** /**
* Todos controller * Todos controller
* *
* Main controller inherits the `Entries` class
* which is an `ArrayProxy` linked with the `Store` model
*
* @param Class Entries, the Entries class
* @param String button_html, the html view for the clearCompletedButton
* @param String items_html, the html view for the `Todos` items
* @returns Class * @returns Class
*/ */
function( Entries, button_html, items_html ) { function() {
return Entries.extend({ return Ember.Controller.extend({
// New todo input entries: function() {
inputView: Ember.TextField.create({ var filter = this.getPath( 'content.filterBy' );
placeholder: 'What needs to be done?',
elementId: 'new-todo',
storageBinding: 'Todos.todosController',
// Bind this to newly inserted line
insertNewline: function() {
var value = this.get( 'value' );
if ( value ) {
this.get( 'storage' ).createNew( value );
this.set( 'value', '' );
}
}
}),
// Stats report
statsView: Ember.View.create({
elementId: 'todo-count',
tagName: 'span',
contentBinding: 'Todos.todosController',
remainingBinding: 'Todos.todosController.remaining',
template: Ember.Handlebars.compile(
'<strong>{{remaining}}</strong> {{remainingString}} left'
),
remainingString: function() {
var remaining = this.get( 'remaining' );
return ( remaining === 1 ? ' item' : ' items' );
}.property( 'remaining' )
}),
// Handle visibility of some elements as items totals change
visibilityObserver: function() {
$( '#main, #footer' ).toggle( !!this.get( 'total' ) );
}.observes( 'total' ),
// Clear completed tasks button if ( Ember.empty( filter ) ) {
clearCompletedButton: Ember.Button.create({ return this.get( 'content' );
template: Ember.Handlebars.compile( button_html ),
target: 'Todos.todosController',
action: 'clearCompleted',
completedCountBinding: 'Todos.todosController.completed',
elementId: 'clear-completed',
classNameBindings: 'buttonClass',
// Observer to update class if completed value changes
buttonClass: function () {
if ( !this.get( 'completedCount' ) )
return 'hidden';
}.property( 'completedCount' )
}),
// Checkbox to mark all todos done.
allDoneCheckbox: Ember.Checkbox.create({
elementId: 'toggle-all',
checkedBinding: 'Todos.todosController.allAreDone'
}),
// Compile and render the todos view
todosView: Ember.View.create({
template: Ember.Handlebars.compile( items_html )
}),
// Todo list item view
todoView: Ember.View.extend({
classNames: [ 'view' ],
doubleClick: function() {
this.get( 'content' ).set( 'editing', true );
} }
}),
// Todo list item editing view if ( !Ember.compare( filter, 'completed' ) ) {
todoEditor: Ember.TextField.extend({ return this.get( 'content' ).filterProperty( 'completed', true );
storageBinding: 'Todos.todosController',
classNames: [ 'edit' ],
whenDone: function() {
this.get( 'todo' ).set( 'editing', false );
if ( !this.get( 'todo' ).get( 'title' ).trim() ) {
this.get( 'storage' ).removeObject( this.get( 'todo' ) );
} }
},
focusOut: function() {
this.whenDone();
},
didInsertElement: function() {
this.$().focus();
},
insertNewline: function() {
this.whenDone();
}
}),
// Activates the views and other initializations if ( !Ember.compare( filter, 'active' ) ) {
init: function() { return this.get( 'content' ).filterProperty( 'completed', false );
this._super();
this.get( 'inputView' ).appendTo( 'header' );
this.get( 'allDoneCheckbox' ).appendTo( '#main' );
this.get( 'todosView' ).appendTo( '#main' );
this.get( 'statsView' ).appendTo( '#footer' );
this.get( 'clearCompletedButton' ).appendTo( '#footer' );
} }
}.property( 'content.remaining' )
}); });
} }
); );
define('app/router', [ 'ember' ],
/**
* Todos Router
*
* Defined routes represent filters according to specs
*
* @returns Class
*/
function() {
return Ember.Router.extend({
root: Ember.Route.extend({
showAll: Ember.Route.transitionTo( 'index' ),
showActive: Ember.Route.transitionTo( 'active' ),
showCompleted: Ember.Route.transitionTo( 'completed' ),
index: Ember.Route.extend({
route: '/',
connectOutlets: function( router ) {
var controller = router.get( 'applicationController' );
var context = controller.namespace.entriesController;
context.set( 'filterBy', '' );
// This require was left here exclusively for design purposes
// Loads decoupled controller/view based on current route
require([ 'app/controllers/todos', 'app/views/items' ],
function( TodosController, ItemsView ) {
controller.connectOutlet({
viewClass: ItemsView,
controller: TodosController.create(),
context: context
});
}
);
}
}),
active: Ember.Route.extend({
route: '/active',
connectOutlets: function( router ) {
var controller = router.get( 'applicationController' );
var context = controller.namespace.entriesController;
context.set( 'filterBy', 'active' );
// This require was left here exclusively for design purposes
// Loads decoupled controller/view based on current route
require([ 'app/controllers/todos', 'app/views/items' ],
function( TodosController, ItemsView ) {
controller.connectOutlet({
viewClass: ItemsView,
controller: TodosController.create(),
context: context
});
}
);
}
}),
completed: Ember.Route.extend({
route: '/completed',
connectOutlets: function( router ) {
var controller = router.get( 'applicationController' );
var context = controller.namespace.entriesController;
context.set( 'filterBy', 'completed' );
// This require was left here exclusively for design purposes
// Loads decoupled controller/view based on current route
require([ 'app/controllers/todos', 'app/views/items' ],
function( TodosController, ItemsView ) {
controller.connectOutlet({
viewClass: ItemsView,
controller: TodosController.create(),
context: context
});
}
);
}
}),
specs: Ember.Route.extend({
route: '/specs',
connectOutlets: function() {
require( [ 'app/specs/helper' ] );
}
})
})
});
}
);
define( 'app/specs/helper', [ 'jasmine', 'jasmine_html' ],
/**
* Specs Runner
*/
function() {
// Load testsuite
require([
'app/specs/todoMVC',
], function() {
var jasmineEnv = jasmine.getEnv();
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter( htmlReporter );
jasmineEnv.execute();
});
}
);
/**
* TodoMVC Project Specs
*
* Use `runs` and `waits` to make sure results are run synchroneously
*/
describe( 'TodoMVC features.', function(){
var enterEvent = $.Event('keyup', { keyCode: 13 });
var todoTitle = 'Foo Bar Todo';
describe( 'Todo creation:', function() {
beforeEach( function(){
// Make sure we are always on the main screen
window.location.hash = '#/';
});
it( 'should allow creating a new todo' , function() {
runs( function(){
$( '#new-todo' ).val( todoTitle ).trigger( enterEvent );
});
waits( 100 );
runs( function() {
!!$( '#todo-list li' ).text().match( todoTitle );
});
});
it( 'should not allow adding an empty todo' , function() {
var ourTodo,
beforeCount = $( '#todo-list li' ).length;
runs( function(){
$( '#new-todo' ).val( ' ' ).trigger( enterEvent );
});
waits( 100 );
runs( function(){
expect( $( '#todo-list li' ).length ).toEqual( beforeCount );
});
});
});
describe( 'Todo completion:', function() {
it( 'should allow marking a todo complete' , function() {
var ourTodo,
beforeCount = $( '#todo-list li.completed' ).length,
postTitle = ' to be completed';
runs( function(){
$( '#new-todo' ).val( todoTitle + postTitle ).trigger( enterEvent );
});
waits( 100 );
runs( function() {
ourTodo = $( '#todo-list li:last-child' );
expect( ourTodo.text() ).toMatch( postTitle );
ourTodo.find( '.toggle' ).click();
expect( $( '#todo-list li.completed' ).length ).toEqual( beforeCount + 1 );
});
});
it( 'should allow clearing completed todos' , function() {
var ourTodo,
beforeCount = $( '#todo-list li.completed' ).length,
postTitle = ' to be completed';
runs( function(){
$( '#new-todo' ).val( todoTitle + postTitle ).trigger( enterEvent );
});
waits( 100 );
runs( function() {
ourTodo = $( '#todo-list li:last-child' );
expect( ourTodo.text() ).toMatch( postTitle );
ourTodo.find( '.toggle' ).click();
$( '#clear-completed' ).click();
expect( $( '#todo-list li.completed' ).length ).toEqual( 0 );
});
});
});
describe( 'Todo deletion:', function() {
it( 'should allow deleting a todo' , function() {
var ourTodo,
beforeCount = $( '#todo-list li' ).length,
postTitle = ' to be deleted';
runs( function(){
$( '#new-todo' ).val( todoTitle + postTitle ).trigger( enterEvent );
});
waits( 100 );
runs( function() {
ourTodo = $( '#todo-list li:last-child' );
expect( ourTodo.text() ).toMatch( postTitle );
ourTodo.find( '.destroy' ).click();
expect( $( '#todo-list li' ).length ).toEqual( beforeCount );
});
});
});
});
{{#with view}}
<button id="clear-completed" {{action "clearCompleted" target="entries"}} >
Clear completed ({{entries.completed}})
</button>
{{/with}}
<ul id="filters">
<li>
<a {{action showAll href=true}}>All</a>
</li>
<li>
<a {{action showActive href=true}}>Active</a>
</li>
<li>
<a {{action showCompleted href=true}}>Completed</a>
</li>
</ul>
{{#unless view.content.editing}}
{{view Ember.Checkbox checkedBinding="view.content.completed" class="toggle"}}
<label>{{view.content.title}}</label>
<button {{action removeItem}} class="destroy" ></button>
{{else}}
{{view view.ItemEditorView contentBinding="view.content"}}
{{/unless}}
{{#with view}}
{{#if oneLeft }}
<strong>{{entries.remaining}}</strong> item left
{{else}}
<strong>{{entries.remaining}}</strong> items left
{{/if}}
{{/with}}
define('app/views/application', [
'app/views/stats',
'app/views/filters',
'app/views/clear_button',
'ember'
],
/**
* Main application view
*
* @param Class StatsView, stats view class
* @param Class FiltersView, filters view class
* @param Class ClearBtnView, clear button view class
* @returns Class
*/
function( StatsView, FiltersView, ClearBtnView ) {
return Ember.ContainerView.extend({
childViews: [ 'headerView', 'mainView', 'footerView' ],
headerView: Ember.ContainerView.create({
childViews: [ 'titleView', 'createTodoView' ],
elementId: 'header',
tagName: 'header',
titleView: Ember.View.create({
tagName: 'h1',
template: function() {
return 'todos';
}
}),
createTodoView: Ember.TextField.create({
entriesBinding: 'controller.namespace.entriesController',
placeholder: 'What needs to be done?',
elementId: 'new-todo',
insertNewline: function() {
var value = this.get( 'value' );
if ( value ) {
this.get( 'entries' ).createNew( value );
this.set( 'value', '' );
}
}
}),
}),
mainView: Em.ContainerView.create({
elementId: 'main',
tagName: 'section',
visibilityBinding: 'controller.namespace.entriesController.noneLeft',
classNameBindings: [ 'visibility:hidden' ],
childViews: [ 'outletView', 'markAllChkbox' ],
outletView: Ember.View.create({
template: Ember.Handlebars.compile( '{{outlet}}' ),
}),
markAllChkbox: Ember.Checkbox.create({
entriesBinding: 'controller.namespace.entriesController',
elementId: 'toggle-all',
checkedBinding: 'entries.allAreDone'
})
}),
footerView: Ember.ContainerView.create({
elementId: 'footer',
tagName: 'footer',
visibilityBinding: 'controller.namespace.entriesController.noneLeft',
classNameBindings: [ 'visibility:hidden' ],
childViews: [
StatsView.create(),
FiltersView.create(),
ClearBtnView.create()
]
})
})
}
);
Clear completed ({{completedCount}})
\ No newline at end of file
define('app/views/clear_button', [
'text!app/templates/clear_button.html',
'ember'
],
/**
* View to clear completed tasks
*
* @param String button_html, the html for view
* @returns Class
*/
function( button_html ) {
return Ember.View.extend({
entriesBinding: 'controller.namespace.entriesController',
template: Ember.Handlebars.compile( button_html ),
classNameBindings: 'buttonClass',
buttonClass: function () {
if ( !this.getPath( 'entries.completed' ) )
return 'hidden';
}.property( 'entries.completed' )
})
}
);
define('app/views/filters', [
'text!app/templates/filters.html',
'ember'
],
/**
* View to render filter links
*
* @param String filters_html, filter links html view
* @returns Class
*/
function( filters_html ) {
return Ember.View.extend({
template: Ember.Handlebars.compile( filters_html )
})
}
);
{{#collection id="todo-list" contentBinding="Todos.todosController" tagName="ul" itemClassBinding="content.completed content.editing" }}
{{#unless content.editing}}
{{#view Todos.todosController.todoView contentBinding="content" }}
{{view Ember.Checkbox valueBinding="content.completed" class="toggle"}}
{{#view Ember.View tagName="label" todoBinding="content"}}
{{todo.title}}
{{/view}}
{{view Ember.Button target="Todos.todosController" action="removeObject" class="destroy" todoBinding="content"}}
{{/view}}
{{else}}
{{view Todos.todosController.todoEditor todoBinding="content" valueBinding="content.title"}}
{{/unless}}
{{/collection}}
\ No newline at end of file
define('app/views/items', [
'text!app/templates/items.html',
'ember'
],
/**
* View to render todos items
*
* @param String items_html, the html view for the `Todos` items
* @returns Class
*/
function( items_html ) {
return Ember.CollectionView.extend({
contentBinding: 'controller.entries',
tagName: 'ul',
elementId: 'todo-list',
itemViewClass: Ember.View.extend({
template: Ember.Handlebars.compile( items_html ),
classNames: [ 'view' ],
classNameBindings: ['content.completed', 'content.editing'],
doubleClick: function() {
this.get( 'content' ).set( 'editing', true );
},
removeItem: function() {
this.getPath( 'controller.content' ).removeObject( this.get( 'content' ) );
},
ItemEditorView: Ember.TextField.extend({
valueBinding: 'content.title',
classNames: [ 'edit' ],
change: function() {
if ( Ember.empty( this.getPath( 'content.title' ) ) ) {
this.getPath( 'controller.content' ).removeObject( this.get( 'content' ) );
}
},
whenDone: function() {
this.get( 'content' ).set( 'editing', false );
},
focusOut: function() {
this.whenDone();
},
didInsertElement: function() {
this.$().focus();
},
insertNewline: function() {
this.whenDone();
}
})
})
})
}
);
define('app/views/stats', [
'text!app/templates/stats.html',
'ember'
],
/**
* View to render todos stats
*
* @param String stats_html, stats indicator view
* @returns Class
*/
function( stats_html ) {
return Ember.View.extend({
entriesBinding: 'controller.namespace.entriesController',
elementId: 'todo-count',
tagName: 'span',
template: Ember.Handlebars.compile( stats_html ),
oneLeft: function() {
return this.getPath( 'entries.remaining' ) === 1;
}.property( 'entries.remaining' )
})
}
);
/*!
* chai
* http://chaijs.com
* Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
* MIT Licensed
*/
!function(i,g){"function"==typeof define&&"object"==typeof define.amd?define(g):this[i]=g()}("chai",function(){function i(g){var h=i.resolve(g),e=i.modules[h];if(!e)throw Error('failed to require "'+g+'"');e.exports||(e.exports={},e.call(e.exports,e,e.exports,i.relative(h)));return e.exports}i.modules={};i.resolve=function(g){var h=g+".js",e=g+"/index.js";return i.modules[h]&&h||i.modules[e]&&e||g};i.register=function(g,h){i.modules[g]=h};i.relative=function(g){return function(h){if("."!=h[0])return i(h);
var e=g.split("/"),h=h.split("/");e.pop();for(var c=0;c<h.length;c++){var j=h[c];".."==j?e.pop():"."!=j&&e.push(j)}return i(e.join("/"))}};i.register("assertion.js",function(g,h,e){function c(a,b,c){d(this,"ssfi",c||arguments.callee);d(this,"object",a);d(this,"message",b)}var j=e("./browser/error"),f=Object.prototype.toString,b=e("./utils"),d=b.flag;g.exports=c;c.includeStack=!1;c.addProperty=function(a,d){b.addProperty(this.prototype,a,d)};c.addMethod=function(a,d){b.addMethod(this.prototype,a,d)};
c.overwriteProperty=function(a,d){b.overwriteProperty(this.prototype,a,d)};c.overwriteMethod=function(a,d){b.overwriteMethod(this.prototype,a,d)};c.prototype.assert=function(a,f,e,h,r){var f=b.getMessage(this,arguments),m=b.getActual(this,arguments);if(!b.test(this,arguments))throw new j({message:f,actual:m,expected:h,stackStartFunction:c.includeStack?this.assert:d(this,"ssfi")});};Object.defineProperty(c.prototype,"_obj",{get:function(){return d(this,"object")},set:function(a){d(this,"object",a)}});
"to be been is and have with".split(" ").forEach(function(a){Object.defineProperty(c.prototype,a,{get:function(){return this},configurable:!0})});Object.defineProperty(c.prototype,"not",{get:function(){d(this,"negate",!0);return this},configurable:!0});Object.defineProperty(c.prototype,"deep",{get:function(){d(this,"deep",!0);return this},configurable:!0});g=function(){var a=function(a){var b=d(this,"object"),c=a.charAt(0).toUpperCase(),e=c+a.slice(1),c=~["A","E","I","O","U"].indexOf(c)?"an ":"a ";
this.assert("[object "+e+"]"===f.call(b),"expected #{this} to be "+c+a,"expected #{this} not to be "+c+a,"[object "+e+"]",f.call(b));return this};a.__proto__=this;return a};Object.defineProperty(c.prototype,"an",{get:g,configurable:!0});Object.defineProperty(c.prototype,"a",{get:g,configurable:!0});g=function(){d(this,"contains",!0);var a=function(a){this.assert(~d(this,"object").indexOf(a),"expected #{this} to include "+b.inspect(a),"expected #{this} to not include "+b.inspect(a));return this};a.__proto__=
this;return a};Object.defineProperty(c.prototype,"contain",{get:g,configurable:!0});Object.defineProperty(c.prototype,"include",{get:g,configurable:!0});Object.defineProperty(c.prototype,"ok",{get:function(){this.assert(d(this,"object"),"expected #{this} to be truthy","expected #{this} to be falsy");return this},configurable:!0});Object.defineProperty(c.prototype,"true",{get:function(){this.assert(!0===d(this,"object"),"expected #{this} to be true","expected #{this} to be false",this.negate?!1:!0);
return this},configurable:!0});Object.defineProperty(c.prototype,"false",{get:function(){this.assert(!1===d(this,"object"),"expected #{this} to be false","expected #{this} to be true",this.negate?!0:!1);return this},configurable:!0});Object.defineProperty(c.prototype,"null",{get:function(){this.assert(null===d(this,"object"),"expected #{this} to be null","expected #{this} not to be null",this.negate?!1:!0);return this},configurable:!0});Object.defineProperty(c.prototype,"undefined",{get:function(){this.assert(void 0===
d(this,"object"),"expected #{this} to be undefined","expected #{this} not to be undefined",this.negate?!1:!0);return this},configurable:!0});Object.defineProperty(c.prototype,"exist",{get:function(){this.assert(null!=d(this,"object"),"expected #{this} to exist","expected #{this} to not exist");return this},configurable:!0});Object.defineProperty(c.prototype,"empty",{get:function(){var a=d(this,"object"),b=a;Array.isArray(a)||"string"===typeof object?b=a.length:"object"===typeof a&&(b=Object.keys(a).length);
this.assert(!b,"expected #{this} to be empty","expected #{this} not to be empty");return this},configurable:!0});Object.defineProperty(c.prototype,"arguments",{get:function(){var a=d(this,"object");this.assert("[object Arguments]"==Object.prototype.toString.call(a),"expected #{this} to be arguments","expected #{this} to not be arguments","[object Arguments]",Object.prototype.toString.call(a));return this},configurable:!0});c.prototype.equal=function(a){var b=d(this,"object");d(this,"deep")?(new c(b)).to.eql(a):
this.assert(a===b,"expected #{this} to equal #{exp}","expected #{this} to not equal #{exp}",a);return this};c.prototype.eql=function(a){this.assert(b.eql(a,d(this,"object")),"expected #{this} to equal #{exp}","expected #{this} to not equal #{exp}",a);return this};c.prototype.above=function(a){this.assert(d(this,"object")>a,"expected #{this} to be above "+a,"expected #{this} to be below "+a);return this};c.prototype.below=function(a){this.assert(d(this,"object")<a,"expected #{this} to be below "+a,
"expected #{this} to be above "+a);return this};c.prototype.within=function(a,b){var c=d(this,"object"),f=a+".."+b;this.assert(c>=a&&c<=b,"expected #{this} to be within "+f,"expected #{this} to not be within "+f);return this};c.prototype.instanceOf=function(a){var c=b.getName(a);this.assert(d(this,"object")instanceof a,"expected #{this} to be an instance of "+c,"expected #{this} to not be an instance of "+c);return this};c.prototype.property=function(a,c){var f=d(this,"object"),e=d(this,"deep")?b.getPathValue(a,
f):f[a],h=d(this,"deep")?"deep property ":"property ";if(d(this,"negate")&&void 0!==c){if(void 0===e)throw Error(b.inspect(f)+" has no "+h+b.inspect(a));}else this.assert(void 0!==e,"expected #{this} to have a "+h+b.inspect(a),"expected #{this} to not have "+h+b.inspect(a));void 0!==c&&this.assert(c===e,"expected #{this} to have a "+h+b.inspect(a)+" of #{exp}, but got #{act}","expected #{this} to not have a "+h+b.inspect(a)+" of #{act}",c,e);d(this,"object",e);return this};c.prototype.ownProperty=
function(a){this.assert(d(this,"object").hasOwnProperty(a),"expected #{this} to have own property "+b.inspect(a),"expected #{this} to not have own property "+b.inspect(a));return this};c.prototype.length=function(a){var b=d(this,"object");(new c(b)).to.have.property("length");b=b.length;this.assert(b==a,"expected #{this} to have a length of #{exp} but got #{act}","expected #{this} to not have a length of #{act}",a,b);return this};c.prototype.match=function(a){var b=d(this,"object");this.assert(a.exec(b),
"expected #{this} to match "+a,"expected #{this} not to match "+a);return this};c.prototype.string=function(a){var f=d(this,"object");(new c(f)).is.a("string");this.assert(~f.indexOf(a),"expected #{this} to contain "+b.inspect(a),"expected #{this} to not contain "+b.inspect(a));return this};c.prototype.keys=function(a){var c=d(this,"object"),f,e=!0,a=a instanceof Array?a:Array.prototype.slice.call(arguments);if(!a.length)throw Error("keys required");var h=Object.keys(c),m=a.length,e=a.every(function(a){return~h.indexOf(a)});
!d(this,"negate")&&!d(this,"contains")&&(e=e&&a.length==h.length);1<m?(a=a.map(function(a){return b.inspect(a)}),f=a.pop(),f=a.join(", ")+", and "+f):f=b.inspect(a[0]);f=(d(this,"contains")?"contain ":"have ")+((1<m?"keys ":"key ")+f);this.assert(e,"expected #{this} to "+f,"expected #{this} to not "+f,a,Object.keys(c));return this};c.prototype.Throw=function(a,f){var e=d(this,"object");(new c(e)).is.a("function");var h=!1,g=null,m=null;0===arguments.length?a=f=null:a&&(a instanceof RegExp||"string"===
typeof a)?(f=a,a=null):a&&a instanceof Error?(g=a,f=a=null):"function"===typeof a?m=(new a).name:a=null;try{e()}catch(j){if(g)return this.assert(j===g,"expected #{this} to throw "+b.inspect(g)+" but "+b.inspect(j)+" was thrown","expected #{this} to not throw "+b.inspect(g)),this;if(a&&(this.assert(j instanceof a,"expected #{this} to throw "+m+" but a "+j.name+" was thrown","expected #{this} to not throw "+m),!f))return this;if(j.message&&f&&f instanceof RegExp)return this.assert(f.exec(j.message),
"expected #{this} to throw error matching "+f+" but got "+b.inspect(j.message),"expected #{this} to throw error not matching "+f),this;if(j.message&&f&&"string"===typeof f)return this.assert(~j.message.indexOf(f),"expected #{this} to throw error including #{exp} but got #{act}","expected #{this} to throw error not including #{act}",f,j.message),this;h=!0}e=m?m:g?b.inspect(g):"an error";this.assert(!0===h,"expected #{this} to throw "+e,"expected #{this} to not throw "+e);return this};c.prototype.respondTo=
function(a){var c=d(this,"object"),c="function"===typeof c?c.prototype[a]:c[a];this.assert("function"===typeof c,"expected #{this} to respond to "+b.inspect(a),"expected #{this} to not respond to "+b.inspect(a),"function",typeof c);return this};c.prototype.satisfy=function(a){var c=d(this,"object");this.assert(a(c),"expected #{this} to satisfy "+b.inspect(a),"expected #{this} to not satisfy"+b.inspect(a),this.negate?!1:!0,a(c));return this};c.prototype.closeTo=function(a,b){var c=d(this,"object");
this.assert(c-b===a||c+b===a,"expected #{this} to be close to "+a+" +/- "+b,"expected #{this} not to be close to "+a+" +/- "+b);return this};(function n(b,d){c.prototype[d]=c.prototype[b];return n})("equal","eq")("above","gt")("below","lt")("length","lengthOf")("keys","key")("ownProperty","haveOwnProperty")("above","greaterThan")("below","lessThan")("Throw","throws")("Throw","throw")("instanceOf","instanceof")});i.register("browser/error.js",function(g){function h(e){e=e||{};this.message=e.message;
this.actual=e.actual;this.expected=e.expected;this.operator=e.operator;e.stackStartFunction&&Error.captureStackTrace&&Error.captureStackTrace(this,e.stackStartFunction)}g.exports=h;h.prototype=Object.create(Error.prototype);h.prototype.name="AssertionError";h.prototype.constructor=h;h.prototype.toString=function(){return this.message}});i.register("chai.js",function(g,h,e){var c=[],h=g.exports={};h.version="1.0.1";h.Assertion=e("./assertion");h.AssertionError=e("./browser/error");var j=e("./utils");
h.use=function(f){~c.indexOf(f)||(f(this,j),c.push(f));return this};g=e("./interface/expect");h.use(g);g=e("./interface/should");h.use(g);e=e("./interface/assert");h.use(e)});i.register("interface/assert.js",function(g){g.exports=function(h,e){var c=h.Assertion,g=e.flag,f=h.assert=function(b,d){(new c(null)).assert(b,d,"[ negation message unavailable ]")};f.fail=function(b,d,a,c){throw new h.AssertionError({actual:b,expected:d,message:a,operator:c,stackStartFunction:f.fail});};f.ok=function(b,d){(new c(b,
d)).is.ok};f.equal=function(b,d,a){a=new c(b,a);a.assert(d==g(a,"object"),"expected #{this} to equal #{exp}","expected #{this} to not equal #{act}",d,b)};f.notEqual=function(b,d,a){a=new c(b,a);a.assert(d!=g(a,"object"),"expected #{this} to not equal #{exp}","expected #{this} to equal #{act}",d,b)};f.strictEqual=function(b,d,a){(new c(b,a)).to.equal(d)};f.notStrictEqual=function(b,d,a){(new c(b,a)).to.not.equal(d)};f.deepEqual=function(b,d,a){(new c(b,a)).to.eql(d)};f.notDeepEqual=function(b,d,a){(new c(b,
a)).to.not.eql(d)};f.isTrue=function(b,d){(new c(b,d)).is["true"]};f.isFalse=function(b,d){(new c(b,d)).is["false"]};f.isNull=function(b,d){(new c(b,d)).to.equal(null)};f.isNotNull=function(b,d){(new c(b,d)).to.not.equal(null)};f.isUndefined=function(b,d){(new c(b,d)).to.equal(void 0)};f.isDefined=function(b,d){(new c(b,d)).to.not.equal(void 0)};f.isFunction=function(b,d){(new c(b,d)).to.be.a("function")};f.isNotFunction=function(b,d){(new c(b,d)).to.not.be.a("function")};f.isObject=function(b,d){(new c(b,
d)).to.be.a("object")};f.isNotObject=function(b,d){(new c(b,d)).to.not.be.a("object")};f.isArray=function(b,d){(new c(b,d)).to.be.an("array")};f.isNotArray=function(b,d){(new c(b,d)).to.not.be.an("array")};f.isString=function(b,d){(new c(b,d)).to.be.a("string")};f.isNotString=function(b,d){(new c(b,d)).to.not.be.a("string")};f.isNumber=function(b,d){(new c(b,d)).to.be.a("number")};f.isNotNumber=function(b,d){(new c(b,d)).to.not.be.a("number")};f.isBoolean=function(b,d){(new c(b,d)).to.be.a("boolean")};
f.isNotBoolean=function(b,d){(new c(b,d)).to.not.be.a("boolean")};f.typeOf=function(b,d,a){(new c(b,a)).to.be.a(d)};f.notTypeOf=function(b,d,a){(new c(b,a)).to.not.be.a(d)};f.instanceOf=function(b,d,a){(new c(b,a)).to.be.instanceOf(d)};f.notInstanceOf=function(b,d,a){(new c(b,a)).to.not.be.instanceOf(d)};f.include=function(b,d,a){a=new c(b,a);Array.isArray(b)?a.to.include(d):"string"===typeof b&&a.to.contain.string(d)};f.match=function(b,d,a){(new c(b,a)).to.match(d)};f.notMatch=function(b,d,a){(new c(b,
a)).to.not.match(d)};f.property=function(b,d,a){(new c(b,a)).to.have.property(d)};f.notProperty=function(b,d,a){(new c(b,a)).to.not.have.property(d)};f.deepProperty=function(b,d,a){(new c(b,a)).to.have.deep.property(d)};f.notDeepProperty=function(b,d,a){(new c(b,a)).to.not.have.deep.property(d)};f.propertyVal=function(b,d,a,f){(new c(b,f)).to.have.property(d,a)};f.propertyNotVal=function(b,d,a,f){(new c(b,f)).to.not.have.property(d,a)};f.deepPropertyVal=function(b,d,a,f){(new c(b,f)).to.have.deep.property(d,
a)};f.deepPropertyNotVal=function(b,d,a,f){(new c(b,f)).to.not.have.deep.property(d,a)};f.lengthOf=function(b,d,a){(new c(b,a)).to.have.length(d)};f.Throw=function(b,d,a){"string"===typeof d&&(a=d,d=null);(new c(b,a)).to.Throw(d)};f.doesNotThrow=function(b,d,a){"string"===typeof d&&(a=d,d=null);(new c(b,a)).to.not.Throw(d)};f.operator=function(b,d,a,f){if(!~"== === > >= < <= != !==".split(" ").indexOf(d))throw Error('Invalid operator "'+d+'"');f=new c(eval(b+d+a),f);f.assert(!0===g(f,"object"),"expected "+
e.inspect(b)+" to be "+d+" "+e.inspect(a),"expected "+e.inspect(b)+" to not be "+d+" "+e.inspect(a))};f.ifError=function(b,d){(new c(b,d)).to.not.be.ok};(function d(a,c){f[c]=f[a];return d})("Throw","throw")("Throw","throws")}});i.register("interface/expect.js",function(g){g.exports=function(h){h.expect=function(e,c){return new h.Assertion(e,c)}}});i.register("interface/should.js",function(g){g.exports=function(h){function e(){Object.defineProperty(Object.prototype,"should",{set:function(){},get:function(){return this instanceof
String||this instanceof Number?new c(this.constructor(this)):this instanceof Boolean?new c(!0==this):new c(this)},configurable:!0});var e={equal:function(f,b){(new c(f)).to.equal(b)},Throw:function(f,b,d){(new c(f)).to.Throw(b,d)},exist:function(f){(new c(f)).to.exist},not:{}};e.not.equal=function(f,b){(new c(f)).to.not.equal(b)};e.not.Throw=function(f,b,d){(new c(f)).to.not.Throw(b,d)};e.not.exist=function(f){(new c(f)).to.not.exist};e["throw"]=e.Throw;e.not["throw"]=e.not.Throw;return e}var c=h.Assertion;
h.should=e;h.Should=e}});i.register("utils/addMethod.js",function(g){g.exports=function(h,e,c){h[e]=function(){var e=c.apply(this,arguments);return void 0===e?this:e}}});i.register("utils/addProperty.js",function(g){g.exports=function(h,e,c){Object.defineProperty(h,e,{get:function(){var e=c.call(this);return void 0===e?this:e},configurable:!0})}});i.register("utils/eql.js",function(g){function h(f,b){if(f===b)return!0;if(j.isBuffer(f)&&j.isBuffer(b)){if(f.length!=b.length)return!1;for(var d=0;d<f.length;d++)if(f[d]!==
b[d])return!1;return!0}return f instanceof Date&&b instanceof Date?f.getTime()===b.getTime():"object"!=typeof f&&"object"!=typeof b?f===b:c(f,b)}function e(c){return"[object Arguments]"==Object.prototype.toString.call(c)}function c(c,b){if(null===c||void 0===c||(null===b||void 0===b)||c.prototype!==b.prototype)return!1;if(e(c)){if(!e(b))return!1;c=pSlice.call(c);b=pSlice.call(b);return h(c,b)}try{var d=Object.keys(c),a=Object.keys(b),g}catch(j){return!1}if(d.length!=a.length)return!1;d.sort();a.sort();
for(g=d.length-1;0<=g;g--)if(d[g]!=a[g])return!1;for(g=d.length-1;0<=g;g--)if(a=d[g],!h(c[a],b[a]))return!1;return!0}g.exports=h;if(!j)var j={isBuffer:function(){return!1}}});i.register("utils/flag.js",function(g){g.exports=function(h,e,c){var g=h.__flags||(h.__flags=Object.create(null));if(3===arguments.length)g[e]=c;else return g[e]}});i.register("utils/getActual.js",function(g){g.exports=function(h,e){var c=e[4];return"undefined"!==c?c:h.obj}});i.register("utils/getMessage.js",function(g,h,e){var c=
e("./flag"),j=e("./getActual"),f=e("./inspect");g.exports=function(b,d){var a=c(b,"negate"),e=c(b,"object"),h=d[3],g=j(b,d),a=a?d[2]:d[1],r=c(b,"message"),a=(a||"").replace(/#{this}/g,f(e)).replace(/#{act}/g,f(g)).replace(/#{exp}/g,f(h));return r?r+": "+a:a}});i.register("utils/getName.js",function(g){g.exports=function(h){return h.name?h.name:(h=/^\s?function ([^(]*)\(/.exec(h))&&h[1]?h[1]:""}});i.register("utils/getPathValue.js",function(g){function h(e){return e.split(".").filter(Boolean).map(function(c){var e=
/([A-Za-z0-9]+)\[(\d+)\]$/.exec(c),f;e&&(f={p:e[1],i:parseFloat(e[2])});return f||c})}g.exports=function(e,c){for(var g=h(e),f=c,b,d=0,a=g.length;d<a;d++){var i=g[d];f?(f="object"===typeof i&&f[i.p]?f[i.p][i.i]:f[i],d==a-1&&(b=f)):b=void 0}return b}});i.register("utils/index.js",function(g,h,e){h=g.exports={};h.test=e("./test");h.getMessage=e("./getMessage");h.getActual=e("./getActual");h.inspect=e("./inspect");h.flag=e("./flag");h.eql=e("./eql");h.getPathValue=e("./getPathValue");h.getName=e("./getName");
h.addProperty=e("./addProperty");h.addMethod=e("./addMethod");h.overwriteProperty=e("./overwriteProperty");h.overwriteMethod=e("./overwriteMethod")});i.register("utils/inspect.js",function(g,h,e){function c(c,e,g){if(e&&"function"===typeof e.inspect&&e.inspect!==h.inspect&&!(e.constructor&&e.constructor.prototype===e))return e.inspect(g);var k=i(c,e);if(k)return k;var s=Object.keys(e),l=c.showHidden?Object.getOwnPropertyNames(e):s;if(0===l.length||q(e)&&(1===l.length&&"stack"===l[0]||2===l.length&&
"description"===l[0]&&"stack"===l[1])){if("function"===typeof e)return k=t(e),c.stylize("[Function"+(k?": "+k:"")+"]","special");if(a(e))return c.stylize(RegExp.prototype.toString.call(e),"regexp");if(n(e))return c.stylize(Date.prototype.toUTCString.call(e),"date");if(q(e))return"["+Error.prototype.toString.call(e)+"]"}var k="",o=!1,p=["{","}"];if(Array.isArray(e)||"object"===typeof e&&"[object Array]"===Object.prototype.toString.call(e))o=!0,p=["[","]"];"function"===typeof e&&(k=" [Function"+(e.name?
": "+e.name:"")+"]");a(e)&&(k=" "+RegExp.prototype.toString.call(e));n(e)&&(k=" "+Date.prototype.toUTCString.call(e));q(e)&&(k=" "+("["+Error.prototype.toString.call(e)+"]"));if(0===l.length&&(!o||0==e.length))return p[0]+k+p[1];if(0>g)return a(e)?c.stylize(RegExp.prototype.toString.call(e),"regexp"):c.stylize("[Object]","special");c.seen.push(e);l=o?f(c,e,g,s,l):l.map(function(a){return b(c,e,g,s,a,o)});c.seen.pop();return d(l,k,p)}function i(a,b){switch(typeof b){case "undefined":return a.stylize("undefined",
"undefined");case "string":var c="'"+JSON.stringify(b).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return a.stylize(c,"string");case "number":return a.stylize(""+b,"number");case "boolean":return a.stylize(""+b,"boolean")}if(null===b)return a.stylize("null","null")}function f(a,c,d,e,f){for(var h=[],g=0,i=c.length;g<i;++g)Object.prototype.hasOwnProperty.call(c,""+g)?h.push(b(a,c,d,e,""+g,!0)):h.push("");f.forEach(function(f){f.match(/^\d+$/)||h.push(b(a,c,d,e,f,!0))});return h}
function b(a,b,d,e,f,h){var g,i;b.__lookupGetter__&&(b.__lookupGetter__(f)?i=b.__lookupSetter__(f)?a.stylize("[Getter/Setter]","special"):a.stylize("[Getter]","special"):b.__lookupSetter__(f)&&(i=a.stylize("[Setter]","special")));0>e.indexOf(f)&&(g="["+f+"]");i||(0>a.seen.indexOf(b[f])?(i=null===d?c(a,b[f],null):c(a,b[f],d-1),-1<i.indexOf("\n")&&(i=h?i.split("\n").map(function(a){return" "+a}).join("\n").substr(2):"\n"+i.split("\n").map(function(a){return" "+a}).join("\n"))):i=a.stylize("[Circular]",
"special"));if("undefined"===typeof g){if(h&&f.match(/^\d+$/))return i;g=JSON.stringify(""+f);g.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(g=g.substr(1,g.length-2),g=a.stylize(g,"name")):(g=g.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),g=a.stylize(g,"string"))}return g+": "+i}function d(a,b,c){var d=0;return 60<a.reduce(function(a,b){d++;0<=b.indexOf("\n")&&d++;return a+b.length+1},0)?c[0]+(""===b?"":b+"\n ")+" "+a.join(",\n ")+" "+c[1]:c[0]+b+" "+a.join(", ")+" "+c[1]}function a(a){return"object"===
typeof a&&"[object RegExp]"===Object.prototype.toString.call(a)}function n(a){return"object"===typeof a&&"[object Date]"===Object.prototype.toString.call(a)}function q(a){return"object"===typeof a&&"[object Error]"===Object.prototype.toString.call(a)}var t=e("./getName");g.exports=function(a,b,d){return c({showHidden:b,seen:[],stylize:function(a){return a}},a,"undefined"===typeof d?2:d)}});i.register("utils/overwriteMethod.js",function(g){g.exports=function(g,e,c){var i=g[e],f=function(){return this};
i&&"function"===typeof i&&(f=i);g[e]=function(){var b=c(f).apply(this,arguments);return void 0===b?this:b}}});i.register("utils/overwriteProperty.js",function(g){g.exports=function(g,e,c){var i=Object.getOwnPropertyDescriptor(g,e),f=function(){};i&&"function"===typeof i.get&&(f=i.get);Object.defineProperty(g,e,{get:function(){var b=c(f).call(this);return b===void 0?this:b},configurable:!0})}});i.register("utils/test.js",function(g,h,e){var c=e("./flag");g.exports=function(e,f){var b=c(e,"negate"),
d=f[0];return b?!d:d}});return i("chai")});
\ No newline at end of file
(function(){function j(i){var e=j.resolve(i),a=j.modules[e];if(!a)throw Error('failed to require "'+i+'"');a.exports||(a.exports={},a.call(a.exports,a,a.exports,j.relative(e)));return a.exports}j.modules={};j.resolve=function(i){var e=i+".js",a=i+"/index.js";return j.modules[e]&&e||j.modules[a]&&a||i};j.register=function(i,e){j.modules[i]=e};j.relative=function(i){return function(e){if("."!=e.charAt(0))return j(e);var a=i.split("/"),e=e.split("/");a.pop();for(var b=0;b<e.length;b++){var h=e[b];".."==
h?a.pop():"."!=h&&a.push(h)}return j(a.join("/"))}};j.register("browser/debug.js",function(i){i.exports=function(){return function(){}}});j.register("browser/diff.js",function(){});j.register("browser/events.js",function(i,e){function a(a){return"[object Array]"=={}.toString.call(a)}function b(){}e.EventEmitter=b;b.prototype.on=function(b,g){this.$events||(this.$events={});this.$events[b]?a(this.$events[b])?this.$events[b].push(g):this.$events[b]=[this.$events[b],g]:this.$events[b]=g;return this};
b.prototype.addListener=b.prototype.on;b.prototype.once=function(a,b){function d(){f.removeListener(a,d);b.apply(this,arguments)}var f=this;d.listener=b;this.on(a,d);return this};b.prototype.removeListener=function(b,g){if(this.$events&&this.$events[b]){var d=this.$events[b];if(a(d)){for(var f=-1,c=0,k=d.length;c<k;c++)if(d[c]===g||d[c].listener&&d[c].listener===g){f=c;break}if(0>f)return this;d.splice(f,1);d.length||delete this.$events[b]}else(d===g||d.listener&&d.listener===g)&&delete this.$events[b]}return this};
b.prototype.removeAllListeners=function(b){if(void 0===b)return this.$events={},this;this.$events&&this.$events[b]&&(this.$events[b]=null);return this};b.prototype.listeners=function(b){this.$events||(this.$events={});this.$events[b]||(this.$events[b]=[]);a(this.$events[b])||(this.$events[b]=[this.$events[b]]);return this.$events[b]};b.prototype.emit=function(b){if(!this.$events)return!1;var g=this.$events[b];if(!g)return!1;var d=[].slice.call(arguments,1);if("function"==typeof g)g.apply(this,d);
else if(a(g))for(var g=g.slice(),f=0,c=g.length;f<c;f++)g[f].apply(this,d);else return!1;return!0}});j.register("browser/fs.js",function(){});j.register("browser/path.js",function(){});j.register("browser/progress.js",function(i){function e(){this.percent=0;this.size(0);this.fontSize(11);this.font("helvetica, arial, sans-serif")}i.exports=e;e.prototype.size=function(a){this._size=a;return this};e.prototype.text=function(a){this._text=a;return this};e.prototype.fontSize=function(a){this._fontSize=
a;return this};e.prototype.font=function(a){this._font=a;return this};e.prototype.update=function(a){this.percent=a;return this};e.prototype.draw=function(a){var b=Math.min(this.percent,100),e=this._size,g=e/2,d=g-1,f=this._fontSize;a.font=f+"px "+this._font;var c=2*Math.PI*(b/100);a.clearRect(0,0,e,e);a.strokeStyle="#9f9f9f";a.beginPath();a.arc(g,g,d,0,c,!1);a.stroke();a.strokeStyle="#eee";a.beginPath();a.arc(g,g,d-1,0,c,!0);a.stroke();b=this._text||(b|0)+"%";e=a.measureText(b).width;a.fillText(b,
g-e/2+1,g+f/2-1);return this}});j.register("browser/tty.js",function(i,e){e.isatty=function(){return!0};e.getWindowSize=function(){return[window.innerHeight,window.innerWidth]}});j.register("context.js",function(i){function e(){}i.exports=e;e.prototype.test=function(a){this._test=a;return this};e.prototype.timeout=function(a){this._test.timeout(a);return this};e.prototype.inspect=function(){return JSON.stringify(this,function(a,b){return"_test"==a?void 0:b},2)}});j.register("hook.js",function(i,e,
a){function b(b,d){h.call(this,b,d);this.type="hook"}var h=a("./runnable");i.exports=b;b.prototype=new h;b.prototype.constructor=b});j.register("interfaces/bdd.js",function(i,e,a){var b=a("../suite"),h=a("../test");i.exports=function(a){var d=[a];a.on("pre-require",function(f){f.xdescribe=function(){};f.xit=function(){};f.before=function(c){d[0].beforeAll(c)};f.after=function(c){d[0].afterAll(c)};f.beforeEach=function(c){d[0].beforeEach(c)};f.afterEach=function(c){d[0].afterEach(c)};f.describe=function(c,
f){var a=b.create(d[0],c);d.unshift(a);f();d.shift()};f.it=function(c,f){d[0].addTest(new h(c,f))}})}});j.register("interfaces/exports.js",function(i,e,a){var b=a("../suite"),h=a("../test");i.exports=function(a){function d(c){var a,g;for(g in c)if("function"==typeof c[g])switch(a=c[g],g){case "before":f[0].beforeAll(a);break;case "after":f[0].afterAll(a);break;case "beforeEach":f[0].beforeEach(a);break;case "afterEach":f[0].afterEach(a);break;default:f[0].addTest(new h(g,a))}else a=b.create(f[0],
g),f.unshift(a),d(c[g]),f.shift()}var f=[a];a.on("require",d)}});j.register("interfaces/index.js",function(i,e,a){e.bdd=a("./bdd");e.tdd=a("./tdd");e.qunit=a("./qunit");e.exports=a("./exports")});j.register("interfaces/qunit.js",function(i,e,a){var b=a("../suite"),h=a("../test");i.exports=function(a){var d=[a];a.on("pre-require",function(f){f.before=function(c){d[0].beforeAll(c)};f.after=function(c){d[0].afterAll(c)};f.beforeEach=function(c){d[0].beforeEach(c)};f.afterEach=function(c){d[0].afterEach(c)};
f.suite=function(c){1<d.length&&d.shift();c=b.create(d[0],c);d.unshift(c)};f.test=function(c,f){d[0].addTest(new h(c,f))}})}});j.register("interfaces/tdd.js",function(i,e,a){var b=a("../suite"),h=a("../test");i.exports=function(a){var d=[a];a.on("pre-require",function(f){f.setup=function(c){d[0].beforeEach(c)};f.teardown=function(c){d[0].afterEach(c)};f.suiteSetup=function(c){d[0].beforeAll(c)};f.suiteTeardown=function(c){d[0].afterAll(c)};f.suite=function(c,f){var a=b.create(d[0],c);d.unshift(a);
f();d.shift()};f.test=function(c,f){d[0].addTest(new h(c,f))}})}});j.register("mocha.js",function(i,e,a){e.version="0.14.0";e.utils=a("./utils");e.interfaces=a("./interfaces");e.reporters=a("./reporters");e.Runnable=a("./runnable");e.Context=a("./context");e.Runner=a("./runner");e.Suite=a("./suite");e.Hook=a("./hook");e.Test=a("./test")});j.register("reporters/base.js",function(i,e,a){function b(c){var d=this.stats={suites:0,tests:0,passes:0,failures:0},f=this.failures=[];c&&(this.runner=c,c.on("start",
function(){d.start=new Date}),c.on("suite",function(c){d.suites=d.suites||0;c.root||d.suites++}),c.on("test end",function(){d.tests=d.tests||0;d.tests++}),c.on("pass",function(c){d.passes=d.passes||0;var f=e.slow/2;c.speed=c.duration>e.slow?"slow":c.duration>f?"medium":"fast";d.passes++}),c.on("fail",function(c,a){d.failures=d.failures||0;d.failures++;c.err=a;f.push(c)}),c.on("end",function(){d.end=new Date;d.duration=new Date-d.start}))}function h(c,d){return f["diff"+d](c.actual,c.expected).map(function(c){return c.added?
g("diff added",c.value):c.removed?g("diff removed",c.value):c.value}).join("")}function g(d,f){return f.split("\n").map(function(f){return c(d,f)}).join("\n")}var d=a("browser/tty"),f=a("browser/diff"),a=d.isatty(1)&&d.isatty(2),e=i.exports=b;e.useColors=a;e.colors={pass:90,fail:31,"bright pass":92,"bright fail":91,"bright yellow":93,pending:36,suite:0,"error title":0,"error message":31,"error stack":90,checkmark:32,fast:90,medium:33,slow:31,green:32,light:90,"diff gutter":90,"diff added":42,"diff removed":41};
var c=e.color=function(c,d){return!e.useColors?d:"\u001b["+e.colors[c]+"m"+d+"\u001b[0m"};e.window={width:a?process.stdout.getWindowSize?process.stdout.getWindowSize(1)[0]:d.getWindowSize()[1]:75};e.cursor={hide:function(){process.stdout.write("\u001b[?25l")},show:function(){process.stdout.write("\u001b[?25h")},deleteLine:function(){process.stdout.write("\u001b[2K")},beginningOfLine:function(){process.stdout.write("\u001b[0G")},CR:function(){e.cursor.deleteLine();e.cursor.beginningOfLine()}};e.slow=
75;e.list=function(d){console.error();d.forEach(function(d,f){var a=c("error title"," %s) %s:\n")+c("error message"," %s")+c("error stack","\n%s\n"),b=d.err,g=b.message||"",e=b.stack||g,g=e.indexOf(g)+g.length,k=e.slice(0,g),i=b.actual,j=b.expected;if("string"==typeof i&&"string"==typeof j){k=20>Math.max(i.length,j.length)?h(b,"Chars"):h(b,"Words");a=k.split("\n");if(4<a.length)var r=(""+a.length).length,k=a.map(function(c,d){var f=++d,f=""+f;return Array(r-f.length+1).join(" ")+f+" | "+c}).join("\n");
k="\n"+c("diff removed","actual")+" "+c("diff added","expected")+"\n\n"+k+"\n";k=k.replace(/^/gm," ");a=c("error title"," %s) %s:\n%s")+c("error stack","\n%s\n")}e=e.slice(g+1).replace(/^/gm," ");console.error(a,f+1,d.fullTitle(),k,e)})};b.prototype.epilogue=function(){var d=this.stats,f;console.log();d.failures?(f=c("bright fail"," \u2716")+c("fail"," %d of %d tests failed")+c("light",":"),console.error(f,d.failures,this.runner.total),b.list(this.failures),console.error()):(f=c("bright pass",
" \u2714")+c("green"," %d tests complete")+c("light"," (%dms)"),console.log(f,d.tests||0,d.duration),console.log())}});j.register("reporters/doc.js",function(i,e,a){function b(d){var d=d.replace(/^function *\(.*\) *{/,"").replace(/\s+\}$/,""),f=d.match(/^\n?( *)/)[1].length;return d=d.replace(RegExp("^ {"+f+"}","gm"),"")}var h=a("./base"),g=a("../utils");i.exports=function(d){function f(){return Array(c).join(" ")}h.call(this,d);var c=2;d.on("suite",function(d){d.root||(++c,console.log('%s<section class="suite">',
f()),++c,console.log("%s<h1>%s</h1>",f(),d.title),console.log("%s<dl>",f()))});d.on("suite end",function(d){d.root||(console.log("%s</dl>",f()),--c,console.log("%s</section>",f()),--c)});d.on("pass",function(c){console.log("%s <dt>%s</dt>",f(),c.title);c=g.escape(b(c.fn.toString()));console.log("%s <dd><pre><code>%s</code></pre></dd>",f(),c)})}});j.register("reporters/dot.js",function(i,e,a){function b(d){h.call(this,d);var f=this,c=0.75*h.window.width|0,a=0;d.on("start",function(){process.stdout.write("\n ")});
d.on("pending",function(){process.stdout.write(g("pending","."))});d.on("pass",function(d){0==++a%c&&process.stdout.write("\n ");"slow"==d.speed?process.stdout.write(g("bright yellow",".")):process.stdout.write(g(d.speed,"."))});d.on("fail",function(){0==++a%c&&process.stdout.write("\n ");process.stdout.write(g("fail","."))});d.on("end",function(){console.log();f.epilogue()})}var h=a("./base"),g=h.color;i.exports=b;b.prototype=new h;b.prototype.constructor=b});j.register("reporters/html-cov.js",
function(i,e,a){function b(d){return 75<=d?"high":50<=d?"medium":25<=d?"low":"terrible"}var h=a("./json-cov"),g=a("browser/fs");i.exports=function(d){var f=a("jade"),c=__dirname+"/templates/coverage.jade",e=g.readFileSync(c,"utf8"),l=f.compile(e,{filename:c}),u=this;h.call(this,d,!1);d.on("end",function(){process.stdout.write(l({cov:u.cov,coverageClass:b}))})}});j.register("reporters/html.js",function(i,e,a){function b(c){var d=arguments,f=document.createElement("div"),a=1;f.innerHTML=c.replace(/%([se])/g,
function(c,f){switch(f){case "s":return""+d[a++];case "e":return k(d[a++])}});return f.firstChild}function h(c,d){c.textContent?c.textContent=d:c.innerText=d}function g(c,d,f){c.addEventListener?c.addEventListener(d,f,!1):c.attachEvent("on"+d,f)}function d(c){var c=c.replace(/^function *\(.*\) *{/,"").replace(/\s+\}$/,""),d=c.match(/^\n?( *)/)[1].length;return c=c.replace(RegExp("^ {"+d+"}","gm"),"").replace(/^\s+/,"")}var f=a("./base"),e=a("../utils"),c=a("../browser/progress"),k=e.escape;i.exports=
function(a){f.call(this,a);var e=this.stats,k=a.total,i=document.getElementById("mocha"),j=b(l),n=j.getElementsByTagName("li"),v=n[1].getElementsByTagName("em")[0],w=n[2].getElementsByTagName("em")[0],r=n[3].getElementsByTagName("em")[0],n=j.getElementsByTagName("canvas")[0],p=[i],q,t;n.getContext&&(t=n.getContext("2d"),q=new c);i?(i.appendChild(j),q&&q.size(40),a.on("suite",function(c){if(!c.root){c=b('<div class="suite"><h1>%s</h1></div>',c.title);p[0].appendChild(c);p.unshift(document.createElement("div"));
c.appendChild(p[0])}}),a.on("suite end",function(c){c.root||p.shift()}),a.on("fail",function(c,d){d.uncaught&&a.emit("test end",c)}),a.on("test end",function(c){var f=e.tests/k*100|0;q&&q.update(f).draw(t);f=new Date-e.start;h(v,e.passes);h(w,e.failures);h(r,(f/1E3).toFixed(2));if("passed"==c.state)f=b('<div class="test pass"><h2>%e</h2></div>',c.title);else if(c.pending)f=b('<div class="test pass pending"><h2>%e</h2></div>',c.title);else{var f=b('<div class="test fail"><h2>%e</h2></div>',c.title),
a=c.err.stack||c.err;if("[object Error]"==a)a=c.err.message;f.appendChild(b('<pre class="error">%e</pre>',a))}a=f.getElementsByTagName("h2")[0];g(a,"click",function(){l.style.display="none"==l.style.display?"block":"none"});if(!c.pending){var l=b("<pre><code>%e</code></pre>",d(c.fn.toString()));f.appendChild(l);l.style.display="none"}p[0].appendChild(f)})):document.body.appendChild(b('<div id="error">%s</div>',"#mocha div missing, add it to your document"))};var l='<ul id="stats"><li class="progress"><canvas width="40" height="40"></canvas></li><li class="passes">passes: <em>0</em></li><li class="failures">failures: <em>0</em></li><li class="duration">duration: <em>0</em>s</li></ul>'});
j.register("reporters/index.js",function(i,e,a){e.Base=a("./base");e.Dot=a("./dot");e.Doc=a("./doc");e.TAP=a("./tap");e.JSON=a("./json");e.HTML=a("./html");e.List=a("./list");e.Spec=a("./spec");e.Progress=a("./progress");e.Landing=a("./landing");e.JSONCov=a("./json-cov");e.HTMLCov=a("./html-cov");e.JSONStream=a("./json-stream");e.XUnit=a("./xunit")});j.register("reporters/json-cov.js",function(i,e,a){function b(d,f){var c={filename:d,coverage:0,hits:0,misses:0,sloc:0,source:{}};f.source.forEach(function(d,
a){a++;0===f[a]?(c.misses++,c.sloc++):void 0!==f[a]&&(c.hits++,c.sloc++);c.source[a]={source:d,coverage:void 0===f[a]?"":f[a]}});c.coverage=100*(c.hits/c.sloc);return c}function h(d){return{title:d.title,fullTitle:d.fullTitle(),duration:d.duration}}var g=a("./base");i.exports=function(d,f){var c=this,f=1==arguments.length?!0:f;g.call(this,d);var a=[],e=[],i=[];d.on("test end",function(c){a.push(c)});d.on("pass",function(c){i.push(c)});d.on("fail",function(c){e.push(c)});d.on("end",function(){var d=
global._$jscoverage||{},g={instrumentation:"node-jscoverage",sloc:0,hits:0,misses:0,coverage:0,files:[]},j;for(j in d){var m=b(j,d[j]);g.files.push(m);g.hits+=m.hits;g.misses+=m.misses;g.sloc+=m.sloc}0<g.sloc&&(g.coverage=100*(g.hits/g.sloc));d=c.cov=g;d.stats=c.stats;d.tests=a.map(h);d.failures=e.map(h);d.passes=i.map(h);f&&process.stdout.write(JSON.stringify(d,null,2))})}});j.register("reporters/json-stream.js",function(i,e,a){function b(a){return{title:a.title,fullTitle:a.fullTitle(),duration:a.duration}}
var h=a("./base");i.exports=function(a){h.call(this,a);var d=this,f=a.total;a.on("start",function(){console.log(JSON.stringify(["start",{total:f}]))});a.on("pass",function(c){console.log(JSON.stringify(["pass",b(c)]))});a.on("fail",function(c){console.log(JSON.stringify(["fail",b(c)]))});a.on("end",function(){process.stdout.write(JSON.stringify(["end",d.stats]))})}});j.register("reporters/json.js",function(i,e,a){function b(a){return{title:a.title,fullTitle:a.fullTitle(),duration:a.duration}}var h=
a("./base");i.exports=function(a){var d=this;h.call(this,a);var f=[],c=[],e=[];a.on("test end",function(c){f.push(c)});a.on("pass",function(c){e.push(c)});a.on("fail",function(d){c.push(d)});a.on("end",function(){var a={stats:d.stats,tests:f.map(b),failures:c.map(b),passes:e.map(b)};process.stdout.write(JSON.stringify(a,null,2))})}});j.register("reporters/landing.js",function(i,e,a){function b(a){function c(){var c=Array(e).join("-");return" "+d("runway",c)}h.call(this,a);var b=this,e=0.75*h.window.width|
0,i=a.total,j=process.stdout,s=d("plane","\u2708"),o=-1,m=0;a.on("start",function(){j.write("\n ");g.hide()});a.on("test end",function(a){var f=-1==o?e*++m/i|0:o;"failed"==a.state&&(s=d("plane crash","\u2708"),o=f);j.write("\u001b[4F\n\n");j.write(c());j.write("\n ");j.write(d("runway",Array(f).join("\u22c5")));j.write(s);j.write(d("runway",Array(e-f).join("\u22c5")+"\n"));j.write(c());j.write("\u001b[0m")});a.on("end",function(){g.show();console.log();b.epilogue()})}var h=a("./base"),g=h.cursor,
d=h.color;i.exports=b;h.colors.plane=0;h.colors["plane crash"]=31;h.colors.runway=90;b.prototype=new h;b.prototype.constructor=b});j.register("reporters/list.js",function(i,e,a){function b(a){h.call(this,a);var c=0;a.on("start",function(){console.log()});a.on("test",function(c){process.stdout.write(d("pass"," "+c.fullTitle()+": "))});a.on("pending",function(c){var a=d("checkmark"," -")+d("pending"," %s");console.log(a,c.fullTitle())});a.on("pass",function(c){var a=d("checkmark"," \u2713")+d("pass",
" %s: ")+d(c.speed,"%dms");g.CR();console.log(a,c.fullTitle(),c.duration)});a.on("fail",function(a){g.CR();console.log(d("fail"," %d) %s"),++c,a.fullTitle())});a.on("end",this.epilogue.bind(this))}var h=a("./base"),g=h.cursor,d=h.color;i.exports=b;b.prototype=new h;b.prototype.constructor=b});j.register("reporters/progress.js",function(i,e,a){function b(a,c){h.call(this,a);var b=this,c=c||{},e=0.5*h.window.width|0,i=a.total,j=0;c.open=c.open||"[";c.complete=c.complete||"\u25ac";c.incomplete=c.incomplete||
"\u22c5";c.close=c.close||"]";c.verbose=!1;a.on("start",function(){console.log();g.hide()});a.on("test end",function(){var a=j++/i,a=e*a|0,f=e-a;g.CR();process.stdout.write("\u001b[J");process.stdout.write(d("progress"," "+c.open));process.stdout.write(Array(a).join(c.complete));process.stdout.write(Array(f).join(c.incomplete));process.stdout.write(d("progress",c.close));c.verbose&&process.stdout.write(d("progress"," "+j+" of "+i))});a.on("end",function(){g.show();console.log();b.epilogue()})}var h=
a("./base"),g=h.cursor,d=h.color;i.exports=b;h.colors.progress=90;b.prototype=new h;b.prototype.constructor=b});j.register("reporters/spec.js",function(i,e,a){function b(a){function c(){return Array(b).join(" ")}h.call(this,a);var b=0,e=0;a.on("start",function(){console.log()});a.on("suite",function(a){++b;console.log(d("suite","%s%s"),c(),a.title)});a.on("suite end",function(){--b;1==b&&console.log()});a.on("test",function(a){process.stdout.write(c()+d("pass"," \u25e6 "+a.title+": "))});a.on("pending",
function(a){var f=c()+d("pending"," - %s");console.log(f,a.title)});a.on("pass",function(a){if("fast"==a.speed){var f=c()+d("checkmark"," \u2713")+d("pass"," %s ");g.CR();console.log(f,a.title)}else f=c()+d("checkmark"," \u2713")+d("pass"," %s ")+d(a.speed,"(%dms)"),g.CR(),console.log(f,a.title,a.duration)});a.on("fail",function(a){g.CR();console.log(c()+d("fail"," %d) %s"),++e,a.title)});a.on("end",this.epilogue.bind(this))}var h=a("./base"),g=h.cursor,d=h.color;i.exports=b;b.prototype=new h;
b.prototype.constructor=b});j.register("reporters/tap.js",function(i,e,a){var b=a("./base");i.exports=function(a){b.call(this,a);var e=a.total,d=1;a.on("start",function(){console.log("%d..%d",1,e)});a.on("test end",function(){++d});a.on("pending",function(a){console.log("ok %d %s # SKIP -",d,a.fullTitle().replace(/#/g,""))});a.on("pass",function(a){console.log("ok %d %s",d,a.fullTitle().replace(/#/g,""))});a.on("fail",function(a,c){console.log("not ok %d %s",d,a.fullTitle().replace(/#/g,""));console.log(c.stack.replace(/^/gm,
" "))})}});j.register("reporters/teamcity.js",function(i,e,a){function b(a){return a.replace(/'/g,"|'")}var h=a("./base");i.exports=function(a){h.call(this,a);var d=this.stats;a.on("start",function(){console.log("##teamcity[testSuiteStarted name='mocha.suite']")});a.on("test",function(a){console.log("##teamcity[testStarted name='%s']",b(a.fullTitle()))});a.on("fail",function(a,c){console.log("##teamcity[testFailed name='%s' message='%s']",b(a.fullTitle()),b(c.message))});a.on("pending",function(a){console.log("##teamcity[testIgnored name='%s' message='pending']",
b(a.fullTitle()))});a.on("test end",function(a){console.log("##teamcity[testFinished name='%s' duration='%s']",b(a.fullTitle()),a.duration)});a.on("end",function(){console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='%s']",d.duration)})}});j.register("reporters/xunit.js",function(i,e,a){function b(c){d.call(this,c);var a=this.stats,f=[];c.on("test end",function(c){f.push(c)});c.on("end",function(){console.log(g("testsuite",{name:"Mocha Tests",tests:a.tests,failures:a.failures,errors:a.failures,
skip:a.tests-a.failures-a.passes,timestamp:(new Date).toUTCString(),time:a.duration/1E3},!1));f.forEach(h);console.log("</testsuite>")})}function h(c){var a={classname:c.parent.fullTitle(),name:c.title,time:c.duration/1E3};"failed"==c.state?(c=c.err,a.message=f(c.message),console.log(g("testcase",a,!1,g("failure",a,!1,"<![CDATA["+f(c.stack)+"]]\>")))):c.pending?console.log(g("testcase",a,!1,g("skipped",{},!0))):console.log(g("testcase",a,!0))}function g(c,a,d,b){var d=d?"/>":">",e=[],g;for(g in a)e.push(g+
'="'+f(a[g])+'"');a="<"+c+(e.length?" "+e.join(" "):"")+d;b&&(a+=b+"</"+c+d);return a}var d=a("./base"),f=a("../utils").escape;i.exports=b;b.prototype=new d;b.prototype.constructor=b});j.register("runnable.js",function(i,e,a){function b(a,d){this.title=a;this.async=(this.fn=d)&&d.length;this.sync=!this.async;this._timeout=2E3;this.timedOut=!1}var e=a("browser/events").EventEmitter,h=a("browser/debug")("runnable");i.exports=b;b.prototype=new e;b.prototype.constructor=b;b.prototype.timeout=function(a){if(0==
arguments.length)return this._timeout;h("timeout %d",a);this._timeout=a;this.timer&&this.resetTimeout();return this};b.prototype.fullTitle=function(){return this.parent.fullTitle()+" "+this.title};b.prototype.clearTimeout=function(){clearTimeout(this.timer)};b.prototype.resetTimeout=function(){var a=this,d=this.timeout();this.clearTimeout();d&&(this.timer=setTimeout(function(){a.callback(Error("timeout of "+d+"ms exceeded"));a.timedOut=!0},d))};b.prototype.run=function(a){function d(c){if(!f.timedOut){if(h){var d;
i?d=void 0:(i=!0,f.emit("error",Error("done() called multiple times")));return d}f.clearTimeout();f.duration=new Date-b;h=!0;a(c)}}var f=this,c=this.timeout(),b=new Date,e=this.ctx,h,i;this.async&&c&&(this.timer=setTimeout(function(){d(Error("timeout of "+c+"ms exceeded"));f.timedOut=!0},c));this.callback=d;if(this.async)try{this.fn.call(e,function(c){if(c instanceof Error)return d(c);if(null!=c)return d(Error("done() invoked with non-Error: "+c));d()})}catch(j){d(j)}else try{this.pending||this.fn.call(e),
this.duration=new Date-b,a()}catch(o){a(o)}}});j.register("runner.js",function(i,e,a){function b(a){var f=this;this._globals=[];this.suite=a;this.total=a.total();this.failures=0;this.on("test end",function(c){f.checkGlobals(c)});this.on("hook end",function(c){f.checkGlobals(c)});this.grep(/.*/);this.globals(g.keys(global).concat(["errno"]))}var e=a("browser/events").EventEmitter,h=a("browser/debug")("runner");a("./test");var g=a("./utils");i.exports=b;b.prototype=new e;b.prototype.constructor=b;b.prototype.grep=
function(a){h("grep %s",a);this._grep=a;return this};b.prototype.globals=function(a){if(0==arguments.length)return this._globals;h("globals %j",a);g.forEach(a,function(a){this._globals.push(a)},this);return this};b.prototype.checkGlobals=function(a){if(!this.ignoreLeaks){var f=g.filter(g.keys(global),function(a){return!~g.indexOf(this._globals,a)&&(!global.navigator||"onerror"!==a)},this);this._globals=this._globals.concat(f);1<f.length?this.fail(a,Error("global leaks detected: "+f.join(", ")+"")):
f.length&&this.fail(a,Error("global leak detected: "+f[0]))}};b.prototype.fail=function(a,f){++this.failures;a.state="failed";this.emit("fail",a,f)};b.prototype.failHook=function(a,f){this.fail(a,f);this.emit("end")};b.prototype.hook=function(a,f){function c(a){var d=b[a];if(!d)return f();e.currentRunnable=d;d.ctx.test(e.test);e.emit("hook",d);d.on("error",function(a){e.failHook(d,a)});d.run(function(b){d.removeAllListeners("error");if(b)return e.failHook(d,b);e.emit("hook end",d);c(++a)})}var b=
this.suite["_"+a],e=this;process.nextTick(function(){c(0)})};b.prototype.hooks=function(a,b,c){function e(i){g.suite=i;if(!i)return g.suite=h,c();g.hook(a,function(a){if(a)return g.suite=h,c(a);e(b.pop())})}var g=this,h=this.suite;e(b.pop())};b.prototype.hookUp=function(a,b){var c=[this.suite].concat(this.parents()).reverse();this.hooks(a,c,b)};b.prototype.hookDown=function(a,b){var c=[this.suite].concat(this.parents());this.hooks(a,c,b)};b.prototype.parents=function(){for(var a=this.suite,b=[];a=
a.parent;)b.push(a);return b};b.prototype.runTest=function(a){var b=this.test,c=this;try{b.ctx.test(b),b.on("error",function(a){c.fail(b,a)}),b.run(a)}catch(e){a(e)}};b.prototype.runTests=function(a,b){function c(){if(e.failures&&a._bail)return b();h=g.shift();if(!h)return b();if(!e._grep.test(h.fullTitle()))return c();if(h.pending)return e.emit("pending",h),e.emit("test end",h),c();e.emit("test",e.test=h);e.hookDown("beforeEach",function(){e.currentRunnable=e.test;e.runTest(function(a){h=e.test;
if(a)return e.fail(h,a),e.emit("test end",h),e.hookUp("afterEach",c);h.state="passed";e.emit("pass",h);e.emit("test end",h);e.hookUp("afterEach",c)})})}var e=this,g=a.tests,h;this.next=c;c()};b.prototype.runSuite=function(a,b){function c(){var b=a.suites[i++];if(!b)return e();g.runSuite(b,c)}function e(){g.suite=a;g.hook("afterAll",function(){g.emit("suite end",a);b()})}var g=this,i=0;h("run suite %s",a.fullTitle());this.emit("suite",this.suite=a);this.hook("beforeAll",function(){g.runTests(a,c)})};
b.prototype.uncaught=function(a){h("uncaught exception");var b=this.currentRunnable;"failed"!=b.state&&(b.clearTimeout(),a.uncaught=!0,this.fail(b,a),"test"==b.type?(this.emit("test end",b),this.hookUp("afterEach",this.next)):this.emit("end"))};b.prototype.run=function(a){var b=this,a=a||function(){};h("start");this.on("end",function(){h("end");process.removeListener("uncaughtException",this.uncaught);a(b.failures)});this.emit("start");this.runSuite(this.suite,function(){h("finished running");b.emit("end")});
process.on("uncaughtException",function(a){b.uncaught(a)});return this}});j.register("suite.js",function(i,e,a){function b(a,d){this.title=a;this.ctx=d;this.suites=[];this.tests=[];this._beforeEach=[];this._beforeAll=[];this._afterEach=[];this._afterAll=[];this.root=!a;this._timeout=2E3;this._bail=!1}var h=a("browser/events").EventEmitter,g=a("browser/debug")("suite"),d=a("./utils"),f=a("./hook"),e=i.exports=b;e.create=function(a,d){var e=new b(d,a.ctx);e.parent=a;e.fullTitle();a.addSuite(e);return e};
b.prototype=new h;b.prototype.constructor=b;b.prototype.clone=function(){var a=new b(this.title);g("clone");a.ctx=this.ctx;a.timeout(this.timeout());a.bail(this.bail());return a};b.prototype.timeout=function(a){if(0==arguments.length)return this._timeout;(""+a).match(/s$/)&&(a=1E3*parseFloat(a));g("timeout %d",a);this._timeout=parseInt(a,10);return this};b.prototype.bail=function(a){if(0==arguments.length)return this._bail;g("bail %s",a);this._bail=a;return this};b.prototype.beforeAll=function(a){a=
new f('"before all" hook',a);a.parent=this;a.timeout(this.timeout());a.ctx=this.ctx;this._beforeAll.push(a);this.emit("beforeAll",a);return this};b.prototype.afterAll=function(a){a=new f('"after all" hook',a);a.parent=this;a.timeout(this.timeout());a.ctx=this.ctx;this._afterAll.push(a);this.emit("afterAll",a);return this};b.prototype.beforeEach=function(a){a=new f('"before each" hook',a);a.parent=this;a.timeout(this.timeout());a.ctx=this.ctx;this._beforeEach.push(a);this.emit("beforeEach",a);return this};
b.prototype.afterEach=function(a){a=new f('"after each" hook',a);a.parent=this;a.timeout(this.timeout());a.ctx=this.ctx;this._afterEach.push(a);this.emit("afterEach",a);return this};b.prototype.addSuite=function(a){a.parent=this;a.timeout(this.timeout());a.bail(this.bail());this.suites.push(a);this.emit("suite",a);return this};b.prototype.addTest=function(a){a.parent=this;a.timeout(this.timeout());a.ctx=this.ctx;this.tests.push(a);this.emit("test",a);return this};b.prototype.fullTitle=function(){if(this.parent){var a=
this.parent.fullTitle();if(a)return a+" "+this.title}return this.title};b.prototype.total=function(){return d.reduce(this.suites,function(a,d){return a+d.total()},0)+this.tests.length}});j.register("test.js",function(i,e,a){function b(a,d){h.call(this,a,d);this.pending=!d;this.type="test"}var h=a("./runnable");i.exports=b;b.prototype=new h;b.prototype.constructor=b;b.prototype.inspect=function(){return JSON.stringify(this,function(a,d){return"_"==a[0]?void 0:"parent"==a?"#<Suite>":d},2)}});j.register("utils.js",
function(i,e,a){function b(a){return!~f.indexOf(a)}var h=a("browser/fs"),g=a("browser/path").join,d=a("browser/debug")("watch"),f=["node_modules",".git"];e.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")};e.forEach=function(a,d,b){for(var e=0,f=a.length;e<f;e++)d.call(b,a[e],e)};e.indexOf=function(a,d,b){for(var b=b||0,e=a.length;b<e;b++)if(a[b]===d)return b;return-1};e.reduce=function(a,d,b,e){for(var f=0,g=a.length;f<g;f++)b=
d.call(e,b,a[f],f,a);return b};e.filter=function(a,d,b){for(var e=[],f=0,g=a.length;f<g;f++){var h=a[f];d.call(b,h,f,a)&&e.push(h)}return e};e.keys=Object.keys||function(a){var d=[],b=Object.prototype.hasOwnProperty,e;for(e in a)b.call(a,e)&&d.push(e);return d};e.watch=function(a,b){var e={interval:100};a.forEach(function(a){d("file %s",a);h.watchFile(a,e,function(c,d){d.mtime<c.mtime&&b(a)})})};e.files=function(a,d){d=d||[];h.readdirSync(a).filter(b).forEach(function(b){b=g(a,b);h.statSync(b).isDirectory()?
e.files(b,d):b.match(/\.(js|coffee)$/)&&d.push(b)});return d}});process={exit:function(){},stdout:{}};global=window;process.nextTick=function(){if(window.ActiveXObject||!window.postMessage)return function(e){e()};var i=[];return function(e){i.push(e);window.postMessage("mocha-zero-timeout","*");window.addEventListener("message",function(a){a.source==window&&"mocha-zero-timeout"==a.data&&(a.stopPropagation&&a.stopPropagation(),i.length&&i.shift()())},!0)}}();process.removeListener=function(i){"uncaughtException"==
i&&(window.onerror=null)};process.on=function(i,e){"uncaughtException"==i&&(window.onerror=e)};window.mocha=j("mocha");(function(){function i(){for(var a=document.getElementsByTagName("code"),b=0,d=a.length;b<d;++b)a[b].innerHTML=a[b].innerHTML.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\/\/(.*)/gm,'<span class="comment">//$1</span>').replace(/('.*?')/gm,'<span class="string">$1</span>').replace(/(\d+\.\d+)/gm,'<span class="number">$1</span>').replace(/(\d+)/gm,'<span class="number">$1</span>').replace(/\bnew *(\w+)/gm,
'<span class="keyword">new</span> <span class="init">$1</span>').replace(/\b(function|new|throw|return|var|if|else)\b/gm,'<span class="keyword">$1</span>')}function e(a){return b.reduce(a.replace("?","").split("&"),function(a,d){var b=d.indexOf("="),c=d.slice(0,b),b=d.slice(++b);a[c]=decodeURIComponent(b);return a},{})}var a=new mocha.Suite("",new mocha.Context),b=mocha.utils;mocha.setup=function(b){b=mocha.interfaces[b];if(!b)throw Error('invalid mocha interface "'+b+'"');b(a);a.emit("pre-require",
window)};mocha.run=function(b){a.emit("run");var g=new mocha.Runner(a),b=b||mocha.reporters.HTML;new b(g);b=e(window.location.search||"");b.grep&&g.grep(RegExp(b.grep));g.on("end",i);return g.run()}})()})();
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment