Merge branch 'beforeAll' into master

Conflicts:
	lib/jasmine-core/boot.js
	lib/jasmine-core/boot/boot.js
	lib/jasmine-core/jasmine.css
	lib/jasmine-core/jasmine.js
	spec/core/SpecSpec.js
	spec/core/SuiteSpec.js
	spec/core/integration/EnvSpec.js
	spec/node_suite.js
	src/core/Env.js
	src/core/requireCore.js
	src/core/util.js
This commit is contained in:
slackersoft
2014-09-24 20:19:47 -07:00
29 changed files with 2512 additions and 655 deletions

View File

@@ -54,7 +54,8 @@ getJasmineRequireObj().ConsoleReporter = function() {
red: '\x1B[31m', red: '\x1B[31m',
yellow: '\x1B[33m', yellow: '\x1B[33m',
none: '\x1B[0m' none: '\x1B[0m'
}; },
failedSuites = [];
this.jasmineStarted = function() { this.jasmineStarted = function() {
specCount = 0; specCount = 0;
@@ -89,9 +90,12 @@ getJasmineRequireObj().ConsoleReporter = function() {
printNewline(); printNewline();
var seconds = timer.elapsed() / 1000; var seconds = timer.elapsed() / 1000;
print('Finished in ' + seconds + ' ' + plural('second', seconds)); print('Finished in ' + seconds + ' ' + plural('second', seconds));
printNewline(); printNewline();
for(i = 0; i < failedSuites.length; i++) {
suiteFailureDetails(failedSuites[i]);
}
onComplete(failureCount === 0); onComplete(failureCount === 0);
}; };
@@ -116,6 +120,13 @@ getJasmineRequireObj().ConsoleReporter = function() {
} }
}; };
this.suiteDone = function(result) {
if (result.failedExpectations && result.failedExpectations.length > 0) {
failureCount++;
failedSuites.push(result);
}
};
return this; return this;
function printNewline() { function printNewline() {
@@ -160,6 +171,17 @@ getJasmineRequireObj().ConsoleReporter = function() {
printNewline(); printNewline();
} }
function suiteFailureDetails(result) {
for (var i = 0; i < result.failedExpectations.length; i++) {
printNewline();
print(colored('red', 'An error was thrown in an afterAll'));
printNewline();
print(colored('red', 'AfterAll ' + result.failedExpectations[i].message));
}
printNewline();
}
} }
return ConsoleReporter; return ConsoleReporter;

View File

@@ -46,7 +46,8 @@ jasmineRequire.HtmlReporter = function(j$) {
failureCount = 0, failureCount = 0,
pendingSpecCount = 0, pendingSpecCount = 0,
htmlReporterMain, htmlReporterMain,
symbols; symbols,
failedSuites = [];
this.initialize = function() { this.initialize = function() {
clearPrior(); clearPrior();
@@ -83,6 +84,10 @@ jasmineRequire.HtmlReporter = function(j$) {
}; };
this.suiteDone = function(result) { this.suiteDone = function(result) {
if (result.failedExpectations && result.failedExpectations.length > 0) {
failedSuites.push(result);
}
if (currentParent == topResults) { if (currentParent == topResults) {
return; return;
} }
@@ -178,6 +183,15 @@ jasmineRequire.HtmlReporter = function(j$) {
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage)); alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage));
for(i = 0; i < failedSuites.length; i++) {
var failedSuite = failedSuites[i];
for(var j = 0; j < failedSuite.failedExpectations.length; j++) {
var errorBarMessage = 'AfterAll ' + failedSuite.failedExpectations[j].message;
var errorBarClassName = 'bar errored';
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessage));
}
}
var results = find('.results'); var results = find('.results');
results.appendChild(summary); results.appendChild(summary);

View File

@@ -30,6 +30,7 @@ body { overflow-y: scroll; }
.jasmine_html-reporter .bar.failed { background-color: #ca3a11; } .jasmine_html-reporter .bar.failed { background-color: #ca3a11; }
.jasmine_html-reporter .bar.passed { background-color: #007069; } .jasmine_html-reporter .bar.passed { background-color: #007069; }
.jasmine_html-reporter .bar.skipped { background-color: #bababa; } .jasmine_html-reporter .bar.skipped { background-color: #bababa; }
.jasmine_html-reporter .bar.errored { background-color: #ca3a11; }
.jasmine_html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; } .jasmine_html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; }
.jasmine_html-reporter .bar.menu a { color: #333333; } .jasmine_html-reporter .bar.menu a { color: #333333; }
.jasmine_html-reporter .bar a { color: white; } .jasmine_html-reporter .bar a { color: white; }

View File

@@ -55,6 +55,7 @@ getJasmineRequireObj = (function (jasmineGlobal) {
j$.QueueRunner = jRequire.QueueRunner(j$); j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher(); j$.ReportDispatcher = jRequire.ReportDispatcher();
j$.Spec = jRequire.Spec(j$); j$.Spec = jRequire.Spec(j$);
j$.SpyRegistry = jRequire.SpyRegistry(j$);
j$.SpyStrategy = jRequire.SpyStrategy(); j$.SpyStrategy = jRequire.SpyStrategy();
j$.Suite = jRequire.Suite(); j$.Suite = jRequire.Suite();
j$.Timer = jRequire.Timer(); j$.Timer = jRequire.Timer();
@@ -242,6 +243,21 @@ getJasmineRequireObj().util = function() {
return false; return false;
}; };
util.clone = function(obj) {
if (Object.prototype.toString.apply(obj) === '[object Array]') {
return obj.slice();
}
var cloned = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
cloned[prop] = obj[prop];
}
}
return cloned;
};
return util; return util;
}; };
@@ -251,17 +267,16 @@ getJasmineRequireObj().Spec = function(j$) {
this.resultCallback = attrs.resultCallback || function() {}; this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id; this.id = attrs.id;
this.description = attrs.description || ''; this.description = attrs.description || '';
this.fn = attrs.fn; this.queueableFn = attrs.queueableFn;
this.beforeFns = attrs.beforeFns || function() { return []; }; this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return {befores: [], afters: []}; };
this.afterFns = attrs.afterFns || function() { return []; }; this.userContext = attrs.userContext || function() { return {}; };
this.onStart = attrs.onStart || function() {}; this.onStart = attrs.onStart || function() {};
this.exceptionFormatter = attrs.exceptionFormatter || function() {};
this.getSpecName = attrs.getSpecName || function() { return ''; }; this.getSpecName = attrs.getSpecName || function() { return ''; };
this.expectationResultFactory = attrs.expectationResultFactory || function() { }; this.expectationResultFactory = attrs.expectationResultFactory || function() { };
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
if (!this.fn) { if (!this.queueableFn.fn) {
this.pend(); this.pend();
} }
@@ -297,30 +312,16 @@ getJasmineRequireObj().Spec = function(j$) {
return; return;
} }
var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()); var fns = this.beforeAndAfterFns();
var allFns = fns.befores.concat(this.queueableFn).concat(fns.afters);
this.queueRunnerFactory({ this.queueRunnerFactory({
fns: allFns, queueableFns: allFns,
onException: onException, onException: function() { self.onException.apply(self, arguments); },
onComplete: complete, onComplete: complete,
enforceTimeout: function() { return true; } userContext: this.userContext()
}); });
function onException(e) {
if (Spec.isPendingSpecException(e)) {
self.pend();
return;
}
self.addExpectationResult(false, {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: e
});
}
function complete() { function complete() {
self.result.status = self.status(); self.result.status = self.status();
self.resultCallback(self.result); self.resultCallback(self.result);
@@ -331,6 +332,21 @@ getJasmineRequireObj().Spec = function(j$) {
} }
}; };
Spec.prototype.onException = function onException(e) {
if (Spec.isPendingSpecException(e)) {
this.pend();
return;
}
this.addExpectationResult(false, {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: e
});
};
Spec.prototype.disable = function() { Spec.prototype.disable = function() {
this.disabled = true; this.disabled = true;
}; };
@@ -355,6 +371,10 @@ getJasmineRequireObj().Spec = function(j$) {
} }
}; };
Spec.prototype.isExecutable = function() {
return !this.disabled && !this.markedPending;
};
Spec.prototype.getFullName = function() { Spec.prototype.getFullName = function() {
return this.getSpecName(this); return this.getSpecName(this);
}; };
@@ -388,11 +408,19 @@ getJasmineRequireObj().Env = function(j$) {
this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler(), new j$.MockDate(global)); this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler(), new j$.MockDate(global));
var runnableLookupTable = {}; var runnableLookupTable = {};
var runnableResources = {};
var spies = [];
var currentSpec = null; var currentSpec = null;
var currentSuite = null; var currentlyExecutingSuites = [];
var currentDeclarationSuite = null;
var currentSuite = function() {
return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
};
var currentRunnable = function() {
return currentSpec || currentSuite();
};
var reporter = new j$.ReportDispatcher([ var reporter = new j$.ReportDispatcher([
'jasmineStarted', 'jasmineStarted',
@@ -407,11 +435,21 @@ getJasmineRequireObj().Env = function(j$) {
return true; return true;
}; };
var equalityTesters = [];
var customEqualityTesters = [];
this.addCustomEqualityTester = function(tester) { this.addCustomEqualityTester = function(tester) {
customEqualityTesters.push(tester); if(!currentRunnable()) {
throw new Error('Custom Equalities must be added in a before function or a spec');
}
runnableResources[currentRunnable().id].customEqualityTesters.push(tester);
};
this.addMatchers = function(matchersToAdd) {
if(!currentRunnable()) {
throw new Error('Matchers must be added in a before function or a spec');
}
var customMatchers = runnableResources[currentRunnable().id].customMatchers;
for (var matcherName in matchersToAdd) {
customMatchers[matcherName] = matchersToAdd[matcherName];
}
}; };
j$.Expectation.addCoreMatchers(j$.matchers); j$.Expectation.addCoreMatchers(j$.matchers);
@@ -429,7 +467,8 @@ getJasmineRequireObj().Env = function(j$) {
var expectationFactory = function(actual, spec) { var expectationFactory = function(actual, spec) {
return j$.Expectation.Factory({ return j$.Expectation.Factory({
util: j$.matchersUtil, util: j$.matchersUtil,
customEqualityTesters: customEqualityTesters, customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
customMatchers: runnableResources[spec.id].customMatchers,
actual: actual, actual: actual,
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
}); });
@@ -439,30 +478,44 @@ getJasmineRequireObj().Env = function(j$) {
} }
}; };
var specStarted = function(spec) { var defaultResourcesForRunnable = function(id, parentRunnableId) {
currentSpec = spec; var resources = {spies: [], customEqualityTesters: [], customMatchers: {}};
reporter.specStarted(spec.result);
if(runnableResources[parentRunnableId]){
resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters);
resources.customMatchers = j$.util.clone(runnableResources[parentRunnableId].customMatchers);
}
runnableResources[id] = resources;
}; };
var beforeFns = function(suite) { var clearResourcesForRunnable = function(id) {
spyRegistry.clearSpies();
delete runnableResources[id];
};
var beforeAndAfterFns = function(suite, runnablesExplictlySet) {
return function() { return function() {
var befores = []; var befores = [],
afters = [],
beforeAlls = [],
afterAlls = [];
while(suite) { while(suite) {
befores = befores.concat(suite.beforeFns); befores = befores.concat(suite.beforeFns);
suite = suite.parentSuite;
}
return befores.reverse();
};
};
var afterFns = function(suite) {
return function() {
var afters = [];
while(suite) {
afters = afters.concat(suite.afterFns); afters = afters.concat(suite.afterFns);
if (runnablesExplictlySet()) {
beforeAlls = beforeAlls.concat(suite.beforeAllFns);
afterAlls = afterAlls.concat(suite.afterAllFns);
}
suite = suite.parentSuite; suite = suite.parentSuite;
} }
return afters; return {
befores: beforeAlls.reverse().concat(befores.reverse()),
afters: afters.concat(afterAlls)
};
}; };
}; };
@@ -520,65 +573,54 @@ getJasmineRequireObj().Env = function(j$) {
id: getNextSuiteId(), id: getNextSuiteId(),
description: 'Jasmine__TopLevel__Suite', description: 'Jasmine__TopLevel__Suite',
queueRunner: queueRunnerFactory, queueRunner: queueRunnerFactory,
resultCallback: function() {} // TODO - hook this up resultCallback: function(attrs) {
reporter.suiteDone(attrs);
}
}); });
runnableLookupTable[topSuite.id] = topSuite; runnableLookupTable[topSuite.id] = topSuite;
currentSuite = topSuite; defaultResourcesForRunnable(topSuite.id);
currentDeclarationSuite = topSuite;
this.topSuite = function() { this.topSuite = function() {
return topSuite; return topSuite;
}; };
this.execute = function(runnablesToRun) { this.execute = function(runnablesToRun) {
runnablesToRun = runnablesToRun || [topSuite.id]; if(runnablesToRun) {
runnablesExplictlySet = true;
} else if (focusedRunnables.length) {
runnablesExplictlySet = true;
runnablesToRun = focusedRunnables;
} else {
runnablesToRun = [topSuite.id];
}
var allFns = []; var allFns = [];
for(var i = 0; i < runnablesToRun.length; i++) { for(var i = 0; i < runnablesToRun.length; i++) {
var runnable = runnableLookupTable[runnablesToRun[i]]; var runnable = runnableLookupTable[runnablesToRun[i]];
allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable)); allFns.push((function(runnable) { return { fn: function(done) { runnable.execute(done); } }; })(runnable));
} }
reporter.jasmineStarted({ reporter.jasmineStarted({
totalSpecsDefined: totalSpecsDefined totalSpecsDefined: totalSpecsDefined
}); });
queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone}); queueRunnerFactory({queueableFns: allFns, onComplete: reporter.jasmineDone});
}; };
this.addReporter = function(reporterToAdd) { this.addReporter = function(reporterToAdd) {
reporter.addReporter(reporterToAdd); reporter.addReporter(reporterToAdd);
}; };
this.addMatchers = function(matchersToAdd) { var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
j$.Expectation.addMatchers(matchersToAdd); if(!currentRunnable()) {
}; throw new Error('Spies must be created in a before function or a spec');
this.spyOn = function(obj, methodName) {
if (j$.util.isUndefined(obj)) {
throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
} }
return runnableResources[currentRunnable().id].spies;
}});
if (j$.util.isUndefined(obj[methodName])) { this.spyOn = function() {
throw new Error(methodName + '() method does not exist'); return spyRegistry.spyOn.apply(spyRegistry, arguments);
}
if (obj[methodName] && j$.isSpy(obj[methodName])) {
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
throw new Error(methodName + ' has already been spied upon');
}
var spy = j$.createSpy(methodName, obj[methodName]);
spies.push({
spy: spy,
baseObj: obj,
methodName: methodName,
originalValue: obj[methodName]
});
obj[methodName] = spy;
return spy;
}; };
var suiteFactory = function(description) { var suiteFactory = function(description) {
@@ -586,40 +628,33 @@ getJasmineRequireObj().Env = function(j$) {
env: self, env: self,
id: getNextSuiteId(), id: getNextSuiteId(),
description: description, description: description,
parentSuite: currentSuite, parentSuite: currentDeclarationSuite,
queueRunner: queueRunnerFactory, queueRunner: queueRunnerFactory,
onStart: suiteStarted, onStart: suiteStarted,
expectationFactory: expectationFactory,
expectationResultFactory: expectationResultFactory,
resultCallback: function(attrs) { resultCallback: function(attrs) {
if (!suite.disabled) {
clearResourcesForRunnable(suite.id);
currentlyExecutingSuites.pop();
}
reporter.suiteDone(attrs); reporter.suiteDone(attrs);
} }
}); });
runnableLookupTable[suite.id] = suite; runnableLookupTable[suite.id] = suite;
return suite; return suite;
function suiteStarted(suite) {
currentlyExecutingSuites.push(suite);
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
reporter.suiteStarted(suite.result);
}
}; };
this.describe = function(description, specDefinitions) { this.describe = function(description, specDefinitions) {
var suite = suiteFactory(description); var suite = suiteFactory(description);
addSpecsToSuite(suite, specDefinitions);
var parentSuite = currentSuite;
parentSuite.addChild(suite);
currentSuite = suite;
var declarationError = null;
try {
specDefinitions.call(suite);
} catch (e) {
declarationError = e;
}
if (declarationError) {
this.it('encountered a declaration exception', function() {
throw declarationError;
});
}
currentSuite = parentSuite;
return suite; return suite;
}; };
@@ -629,15 +664,75 @@ getJasmineRequireObj().Env = function(j$) {
return suite; return suite;
}; };
var focusedRunnables = [];
this.fdescribe = function(description, specDefinitions) {
var suite = suiteFactory(description);
suite.isFocused = true;
focusedRunnables.push(suite.id);
unfocusAncestor();
addSpecsToSuite(suite, specDefinitions);
return suite;
};
function addSpecsToSuite(suite, specDefinitions) {
var parentSuite = currentDeclarationSuite;
parentSuite.addChild(suite);
currentDeclarationSuite = suite;
var declarationError = null;
try {
specDefinitions.call(suite);
} catch (e) {
declarationError = e;
}
if (declarationError) {
self.it('encountered a declaration exception', function() {
throw declarationError;
});
}
currentDeclarationSuite = parentSuite;
}
function findFocusedAncestor(suite) {
while (suite) {
if (suite.isFocused) {
return suite.id;
}
suite = suite.parentSuite;
}
return null;
}
function unfocusAncestor() {
var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
if (focusedAncestor) {
for (var i = 0; i < focusedRunnables.length; i++) {
if (focusedRunnables[i] === focusedAncestor) {
focusedRunnables.splice(i, 1);
break;
}
}
}
}
var runnablesExplictlySet = false;
var runnablesExplictlySetGetter = function(){
return runnablesExplictlySet;
};
var specFactory = function(description, fn, suite) { var specFactory = function(description, fn, suite) {
totalSpecsDefined++; totalSpecsDefined++;
var spec = new j$.Spec({ var spec = new j$.Spec({
id: getNextSpecId(), id: getNextSpecId(),
beforeFns: beforeFns(suite), beforeAndAfterFns: beforeAndAfterFns(suite, runnablesExplictlySetGetter),
afterFns: afterFns(suite),
expectationFactory: expectationFactory, expectationFactory: expectationFactory,
exceptionFormatter: exceptionFormatter,
resultCallback: specResultCallback, resultCallback: specResultCallback,
getSpecName: function(spec) { getSpecName: function(spec) {
return getSpecName(spec, suite); return getSpecName(spec, suite);
@@ -646,7 +741,8 @@ getJasmineRequireObj().Env = function(j$) {
description: description, description: description,
expectationResultFactory: expectationResultFactory, expectationResultFactory: expectationResultFactory,
queueRunnerFactory: queueRunnerFactory, queueRunnerFactory: queueRunnerFactory,
fn: fn userContext: function() { return suite.clonedSharedUserContext(); },
queueableFn: { fn: fn, type: 'it', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } }
}); });
runnableLookupTable[spec.id] = spec; runnableLookupTable[spec.id] = spec;
@@ -657,30 +753,22 @@ getJasmineRequireObj().Env = function(j$) {
return spec; return spec;
function removeAllSpies() {
for (var i = 0; i < spies.length; i++) {
var spyEntry = spies[i];
spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
}
spies = [];
}
function specResultCallback(result) { function specResultCallback(result) {
removeAllSpies(); clearResourcesForRunnable(spec.id);
j$.Expectation.resetMatchers();
customEqualityTesters = [];
currentSpec = null; currentSpec = null;
reporter.specDone(result); reporter.specDone(result);
} }
};
var suiteStarted = function(suite) { function specStarted(spec) {
reporter.suiteStarted(suite.result); currentSpec = spec;
defaultResourcesForRunnable(spec.id, suite.id);
reporter.specStarted(spec.result);
}
}; };
this.it = function(description, fn) { this.it = function(description, fn) {
var spec = specFactory(description, fn, currentSuite); var spec = specFactory(description, fn, currentDeclarationSuite);
currentSuite.addChild(spec); currentDeclarationSuite.addChild(spec);
return spec; return spec;
}; };
@@ -690,20 +778,36 @@ getJasmineRequireObj().Env = function(j$) {
return spec; return spec;
}; };
this.fit = function(description, fn ){
var spec = this.it(description, fn);
focusedRunnables.push(spec.id);
unfocusAncestor();
return spec;
};
this.expect = function(actual) { this.expect = function(actual) {
if (!currentSpec) { if (!currentRunnable()) {
throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out'); throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out');
} }
return currentSpec.expect(actual); return currentRunnable().expect(actual);
}; };
this.beforeEach = function(beforeEachFunction) { this.beforeEach = function(beforeEachFunction) {
currentSuite.beforeEach(beforeEachFunction); currentDeclarationSuite.beforeEach({ fn: beforeEachFunction, type: 'beforeEach', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } });
};
this.beforeAll = function(beforeAllFunction) {
currentDeclarationSuite.beforeAll({ fn: beforeAllFunction, type: 'beforeAll', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } });
}; };
this.afterEach = function(afterEachFunction) { this.afterEach = function(afterEachFunction) {
currentSuite.afterEach(afterEachFunction); currentDeclarationSuite.afterEach({ fn: afterEachFunction, type: 'afterEach', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } });
};
this.afterAll = function(afterAllFunction) {
currentDeclarationSuite.afterAll({ fn: afterAllFunction, type: 'afterAll', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } });
}; };
this.pending = function() { this.pending = function() {
@@ -1185,8 +1289,6 @@ getJasmineRequireObj().ExceptionFormatter = function() {
getJasmineRequireObj().Expectation = function() { getJasmineRequireObj().Expectation = function() {
var matchers = {};
function Expectation(options) { function Expectation(options) {
this.util = options.util || { buildFailureMessage: function() {} }; this.util = options.util || { buildFailureMessage: function() {} };
this.customEqualityTesters = options.customEqualityTesters || []; this.customEqualityTesters = options.customEqualityTesters || [];
@@ -1194,8 +1296,9 @@ getJasmineRequireObj().Expectation = function() {
this.addExpectationResult = options.addExpectationResult || function(){}; this.addExpectationResult = options.addExpectationResult || function(){};
this.isNot = options.isNot; this.isNot = options.isNot;
for (var matcherName in matchers) { var customMatchers = options.customMatchers || {};
this[matcherName] = matchers[matcherName]; for (var matcherName in customMatchers) {
this[matcherName] = Expectation.prototype.wrapCompare(matcherName, customMatchers[matcherName]);
} }
} }
@@ -1262,19 +1365,6 @@ getJasmineRequireObj().Expectation = function() {
} }
}; };
Expectation.addMatchers = function(matchersToAdd) {
for (var name in matchersToAdd) {
var matcher = matchersToAdd[name];
matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
}
};
Expectation.resetMatchers = function() {
for (var name in matchers) {
delete matchers[name];
}
};
Expectation.Factory = function(options) { Expectation.Factory = function(options) {
options = options || {}; options = options || {};
@@ -1605,31 +1695,31 @@ getJasmineRequireObj().QueueRunner = function(j$) {
} }
function QueueRunner(attrs) { function QueueRunner(attrs) {
this.fns = attrs.fns || []; this.queueableFns = attrs.queueableFns || [];
this.onComplete = attrs.onComplete || function() {}; this.onComplete = attrs.onComplete || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();}; this.clearStack = attrs.clearStack || function(fn) {fn();};
this.onException = attrs.onException || function() {}; this.onException = attrs.onException || function() {};
this.catchException = attrs.catchException || function() { return true; }; this.catchException = attrs.catchException || function() { return true; };
this.enforceTimeout = attrs.enforceTimeout || function() { return false; }; this.userContext = attrs.userContext || {};
this.userContext = {};
this.timer = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout}; this.timer = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
} }
QueueRunner.prototype.execute = function() { QueueRunner.prototype.execute = function() {
this.run(this.fns, 0); this.run(this.queueableFns, 0);
}; };
QueueRunner.prototype.run = function(fns, recursiveIndex) { QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
var length = fns.length, var length = queueableFns.length,
self = this, self = this,
iterativeIndex; iterativeIndex;
for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) { for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
var fn = fns[iterativeIndex]; var queueableFn = queueableFns[iterativeIndex];
if (fn.length > 0) { if (queueableFn.fn.length > 0) {
return attemptAsync(fn); return attemptAsync(queueableFn);
} else { } else {
attemptSync(fn); attemptSync(queueableFn);
} }
} }
@@ -1639,41 +1729,46 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.clearStack(this.onComplete); this.clearStack(this.onComplete);
} }
function attemptSync(fn) { function attemptSync(queueableFn) {
try { try {
fn.call(self.userContext); queueableFn.fn.call(self.userContext);
} catch (e) { } catch (e) {
handleException(e); handleException(e, queueableFn);
} }
} }
function attemptAsync(fn) { function attemptAsync(queueableFn) {
var clearTimeout = function () { var clearTimeout = function () {
Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeoutId]]); Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeoutId]]);
}, },
next = once(function () { next = once(function () {
clearTimeout(timeoutId); clearTimeout(timeoutId);
self.run(fns, iterativeIndex + 1); self.run(queueableFns, iterativeIndex + 1);
}), }),
timeoutId; timeoutId;
if (self.enforceTimeout()) { if (queueableFn.timeout) {
timeoutId = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() { timeoutId = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
self.onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.')); var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
onException(error, queueableFn);
next(); next();
}, j$.DEFAULT_TIMEOUT_INTERVAL]]); }, queueableFn.timeout()]]);
} }
try { try {
fn.call(self.userContext, next); queueableFn.fn.call(self.userContext, next);
} catch (e) { } catch (e) {
handleException(e); handleException(e, queueableFn);
next(); next();
} }
} }
function handleException(e) { function onException(e, queueableFn) {
self.onException(e); self.onException(e);
}
function handleException(e, queueableFn) {
onException(e, queueableFn);
if (!self.catchException(e)) { if (!self.catchException(e)) {
//TODO: set a var when we catch an exception and //TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way.. //use a finally block to close the loop in a nice way..
@@ -1721,6 +1816,52 @@ getJasmineRequireObj().ReportDispatcher = function() {
}; };
getJasmineRequireObj().SpyRegistry = function(j$) {
function SpyRegistry(options) {
options = options || {};
var currentSpies = options.currentSpies || function() { return []; };
this.spyOn = function(obj, methodName) {
if (j$.util.isUndefined(obj)) {
throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
}
if (j$.util.isUndefined(obj[methodName])) {
throw new Error(methodName + '() method does not exist');
}
if (obj[methodName] && j$.isSpy(obj[methodName])) {
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
throw new Error(methodName + ' has already been spied upon');
}
var spy = j$.createSpy(methodName, obj[methodName]);
currentSpies().push({
spy: spy,
baseObj: obj,
methodName: methodName,
originalValue: obj[methodName]
});
obj[methodName] = spy;
return spy;
};
this.clearSpies = function() {
var spies = currentSpies();
for (var i = 0; i < spies.length; i++) {
var spyEntry = spies[i];
spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
}
};
}
return SpyRegistry;
};
getJasmineRequireObj().SpyStrategy = function() { getJasmineRequireObj().SpyStrategy = function() {
function SpyStrategy(options) { function SpyStrategy(options) {
@@ -1790,9 +1931,13 @@ getJasmineRequireObj().Suite = function() {
this.onStart = attrs.onStart || function() {}; this.onStart = attrs.onStart || function() {};
this.resultCallback = attrs.resultCallback || function() {}; this.resultCallback = attrs.resultCallback || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();}; this.clearStack = attrs.clearStack || function(fn) {fn();};
this.expectationFactory = attrs.expectationFactory;
this.expectationResultFactory = attrs.expectationResultFactory;
this.beforeFns = []; this.beforeFns = [];
this.afterFns = []; this.afterFns = [];
this.beforeAllFns = [];
this.afterAllFns = [];
this.queueRunner = attrs.queueRunner || function() {}; this.queueRunner = attrs.queueRunner || function() {};
this.disabled = false; this.disabled = false;
@@ -1800,12 +1945,16 @@ getJasmineRequireObj().Suite = function() {
this.result = { this.result = {
id: this.id, id: this.id,
status: this.disabled ? 'disabled' : '',
description: this.description, description: this.description,
fullName: this.getFullName() fullName: this.getFullName(),
failedExpectations: []
}; };
} }
Suite.prototype.expect = function(actual) {
return this.expectationFactory(actual, this);
};
Suite.prototype.getFullName = function() { Suite.prototype.getFullName = function() {
var fullName = this.description; var fullName = this.description;
for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
@@ -1825,10 +1974,18 @@ getJasmineRequireObj().Suite = function() {
this.beforeFns.unshift(fn); this.beforeFns.unshift(fn);
}; };
Suite.prototype.beforeAll = function(fn) {
this.beforeAllFns.push(fn);
};
Suite.prototype.afterEach = function(fn) { Suite.prototype.afterEach = function(fn) {
this.afterFns.unshift(fn); this.afterFns.unshift(fn);
}; };
Suite.prototype.afterAll = function(fn) {
this.afterAllFns.push(fn);
};
Suite.prototype.addChild = function(child) { Suite.prototype.addChild = function(child) {
this.children.push(child); this.children.push(child);
}; };
@@ -1845,16 +2002,25 @@ getJasmineRequireObj().Suite = function() {
var allFns = []; var allFns = [];
for (var i = 0; i < this.children.length; i++) { if (this.isExecutable()) {
allFns.push(wrapChildAsAsync(this.children[i])); allFns = allFns.concat(this.beforeAllFns);
for (var i = 0; i < this.children.length; i++) {
allFns.push(wrapChildAsAsync(this.children[i]));
}
allFns = allFns.concat(this.afterAllFns);
} }
this.queueRunner({ this.queueRunner({
fns: allFns, queueableFns: allFns,
onComplete: complete onComplete: complete,
userContext: this.sharedUserContext(),
onException: function() { self.onException.apply(self, arguments); }
}); });
function complete() { function complete() {
self.result.status = self.disabled ? 'disabled' : 'finished';
self.resultCallback(self.result); self.resultCallback(self.result);
if (onComplete) { if (onComplete) {
@@ -1863,10 +2029,82 @@ getJasmineRequireObj().Suite = function() {
} }
function wrapChildAsAsync(child) { function wrapChildAsAsync(child) {
return function(done) { child.execute(done); }; return { fn: function(done) { child.execute(done); } };
} }
}; };
Suite.prototype.isExecutable = function() {
var foundActive = false;
for(var i = 0; i < this.children.length; i++) {
if(this.children[i].isExecutable()) {
foundActive = true;
break;
}
}
return foundActive;
};
Suite.prototype.sharedUserContext = function() {
if (!this.sharedContext) {
this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {};
}
return this.sharedContext;
};
Suite.prototype.clonedSharedUserContext = function() {
return clone(this.sharedUserContext());
};
Suite.prototype.onException = function() {
if(isAfterAll(this.children)) {
var data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: arguments[0]
};
this.result.failedExpectations.push(this.expectationResultFactory(data));
} else {
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
child.onException.apply(child, arguments);
}
}
};
Suite.prototype.addExpectationResult = function () {
if(isAfterAll(this.children) && isFailure(arguments)){
var data = arguments[1];
this.result.failedExpectations.push(this.expectationResultFactory(data));
} else {
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
child.addExpectationResult.apply(child, arguments);
}
}
};
function isAfterAll(children) {
return children && children[0].result.status;
}
function isFailure(args) {
return !args[0];
}
function clone(obj) {
var clonedObj = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
clonedObj[prop] = obj[prop];
}
}
return clonedObj;
}
return Suite; return Suite;
}; };
@@ -2568,6 +2806,14 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.afterEach(afterEachFunction); return env.afterEach(afterEachFunction);
}, },
beforeAll: function(beforeAllFunction) {
return env.beforeAll(beforeAllFunction);
},
afterAll: function(afterAllFunction) {
return env.afterAll(afterAllFunction);
},
expect: function(actual) { expect: function(actual) {
return env.expect(actual); return env.expect(actual);
}, },

View File

@@ -171,27 +171,44 @@ describe("ConsoleReporter", function() {
out.clear(); out.clear();
reporter.jasmineDone({}); reporter.jasmineDone();
expect(out.getOutput()).toMatch(/true to be false/); expect(out.getOutput()).toMatch(/true to be false/);
expect(out.getOutput()).toMatch(/foo bar baz/); expect(out.getOutput()).toMatch(/foo bar baz/);
}); });
it("calls the onComplete callback when the suite is done", function() { describe('onComplete callback', function(){
var onComplete = jasmine.createSpy('onComplete'), var onComplete, reporter;
beforeEach(function() {
onComplete = jasmine.createSpy('onComplete');
reporter = new j$.ConsoleReporter({ reporter = new j$.ConsoleReporter({
print: out.print, print: out.print,
onComplete: onComplete onComplete: onComplete
}); });
reporter.jasmineStarted();
});
reporter.jasmineDone({}); it("is called when the suite is done", function() {
reporter.jasmineDone();
expect(onComplete).toHaveBeenCalledWith(true);
});
expect(onComplete).toHaveBeenCalled(); it('calls it with false if there are spec failures', function() {
reporter.specDone({status: "failed", failedExpectations: []});
reporter.jasmineDone();
expect(onComplete).toHaveBeenCalledWith(false);
});
it('calls it with false if there are suite failures', function() {
reporter.specDone({status: "passed"});
reporter.suiteDone({failedExpectations: [{ message: 'bananas' }] });
reporter.jasmineDone();
expect(onComplete).toHaveBeenCalledWith(false);
});
}); });
describe("with color", function() { describe("with color", function() {
it("reports that the suite has started to the console", function() { it("reports that the suite has started to the console", function() {
var reporter = new j$.ConsoleReporter({ var reporter = new j$.ConsoleReporter({
print: out.print, print: out.print,
@@ -235,5 +252,19 @@ describe("ConsoleReporter", function() {
expect(out.getOutput()).toEqual("\x1B[31mF\x1B[0m"); expect(out.getOutput()).toEqual("\x1B[31mF\x1B[0m");
}); });
it("displays all afterAll exceptions", function() {
var reporter = new j$.ConsoleReporter({
print: out.print,
showColors: true
});
reporter.suiteDone({ failedExpectations: [{ message: 'After All Exception' }] });
reporter.suiteDone({ failedExpectations: [{ message: 'Some Other Exception' }] });
reporter.jasmineDone();
expect(out.getOutput()).toMatch(/After All Exception/);
expect(out.getOutput()).toMatch(/Some Other Exception/);
});
}); });
}); });

View File

@@ -5,68 +5,6 @@ describe("Env", function() {
env = new j$.Env(); env = new j$.Env();
}); });
it('removes all spies when env is executed', function(done) {
var originalFoo = function() {},
testObj = {
foo: originalFoo
},
firstSpec = jasmine.createSpy('firstSpec').and.callFake(function() {
env.spyOn(testObj, 'foo');
}),
secondSpec = jasmine.createSpy('secondSpec').and.callFake(function() {
expect(testObj.foo).toBe(originalFoo);
});
env.describe('test suite', function() {
env.it('spec 0', firstSpec);
env.it('spec 1', secondSpec);
});
var assertions = function() {
expect(firstSpec).toHaveBeenCalled();
expect(secondSpec).toHaveBeenCalled();
done();
};
env.addReporter({ jasmineDone: assertions });
env.execute();
});
describe("#spyOn", function() {
it("checks for the existence of the object", function() {
expect(function() {
env.spyOn(void 0, 'pants');
}).toThrowError(/could not find an object/);
});
it("checks for the existence of the method", function() {
var subject = {};
expect(function() {
env.spyOn(subject, 'pants');
}).toThrowError(/method does not exist/);
});
it("checks if it has already been spied upon", function() {
var subject = { spiedFunc: function() {} };
env.spyOn(subject, 'spiedFunc');
expect(function() {
env.spyOn(subject, 'spiedFunc');
}).toThrowError(/has already been spied upon/);
});
it("overrides the method on the object and returns the spy", function() {
var originalFunctionWasCalled = false;
var subject = { spiedFunc: function() { originalFunctionWasCalled = true; } };
var spy = env.spyOn(subject, 'spiedFunc');
expect(subject.spiedFunc).toEqual(spy);
});
});
describe("#pending", function() { describe("#pending", function() {
it("throws the Pending Spec exception", function() { it("throws the Pending Spec exception", function() {
expect(function() { expect(function() {
@@ -82,4 +20,3 @@ describe("Env", function() {
}); });
}); });
}); });

View File

@@ -1,14 +1,14 @@
describe("Expectation", function() { describe("Expectation", function() {
it(".addMatchers makes matchers available to any expectation", function() { it("makes custom matchers available to this expectation", function() {
var matchers = { var matchers = {
toFoo: function() {}, toFoo: function() {},
toBar: function() {} toBar: function() {}
}, },
expectation; expectation;
j$.Expectation.addMatchers(matchers); expectation = new j$.Expectation({
customMatchers: matchers
expectation = new j$.Expectation({}); });
expect(expectation.toFoo).toBeDefined(); expect(expectation.toFoo).toBeDefined();
expect(expectation.toBar).toBeDefined(); expect(expectation.toBar).toBeDefined();
@@ -27,25 +27,6 @@ describe("Expectation", function() {
expect(expectation.toQuux).toBeDefined(); expect(expectation.toQuux).toBeDefined();
}); });
it(".resetMatchers should keep only core matchers", function() {
var matchers = {
toFoo: function() {}
},
coreMatchers = {
toQuux: function() {}
},
expectation;
j$.Expectation.addCoreMatchers(coreMatchers);
j$.Expectation.addMatchers(matchers);
j$.Expectation.resetMatchers();
expectation = new j$.Expectation({});
expect(expectation.toQuux).toBeDefined();
expect(expectation.toFoo).toBeUndefined();
});
it("Factory builds an expectation/negative expectation", function() { it("Factory builds an expectation/negative expectation", function() {
var builtExpectation = j$.Expectation.Factory(); var builtExpectation = j$.Expectation.Factory();
@@ -65,10 +46,9 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"), addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
util: util, util: util,
customMatchers: matchers,
customEqualityTesters: customEqualityTesters, customEqualityTesters: customEqualityTesters,
actual: "an actual", actual: "an actual",
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
@@ -94,10 +74,9 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"), addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
util: util, util: util,
customMatchers: matchers,
actual: "an actual", actual: "an actual",
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
}); });
@@ -121,10 +100,8 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"), addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
matchers: matchers, customMatchers: matchers,
util: util, util: util,
actual: "an actual", actual: "an actual",
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
@@ -155,10 +132,8 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"), addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
matchers: matchers, customMatchers: matchers,
util: util, util: util,
actual: "an actual", actual: "an actual",
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
@@ -191,10 +166,9 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"), addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
actual: "an actual", actual: "an actual",
customMatchers: matchers,
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
}); });
@@ -225,10 +199,8 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"), addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
matchers: matchers, customMatchers: matchers,
actual: "an actual", actual: "an actual",
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
}); });
@@ -259,10 +231,8 @@ describe("Expectation", function() {
actual = "an actual", actual = "an actual",
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
matchers: matchers, customMatchers: matchers,
actual: "an actual", actual: "an actual",
addExpectationResult: addExpectationResult, addExpectationResult: addExpectationResult,
isNot: true isNot: true
@@ -294,10 +264,8 @@ describe("Expectation", function() {
actual = "an actual", actual = "an actual",
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
matchers: matchers, customMatchers: matchers,
actual: "an actual", actual: "an actual",
util: util, util: util,
addExpectationResult: addExpectationResult, addExpectationResult: addExpectationResult,
@@ -332,10 +300,8 @@ describe("Expectation", function() {
actual = "an actual", actual = "an actual",
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
matchers: matchers, customMatchers: matchers,
actual: "an actual", actual: "an actual",
addExpectationResult: addExpectationResult, addExpectationResult: addExpectationResult,
isNot: true isNot: true
@@ -365,10 +331,8 @@ describe("Expectation", function() {
actual = "an actual", actual = "an actual",
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
matchers: matchers, customMatchers: matchers,
actual: "an actual", actual: "an actual",
addExpectationResult: addExpectationResult, addExpectationResult: addExpectationResult,
isNot: true isNot: true
@@ -403,10 +367,8 @@ describe("Expectation", function() {
actual = "an actual", actual = "an actual",
expectation; expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({ expectation = new j$.Expectation({
matchers: matchers, customMatchers: matchers,
actual: "an actual", actual: "an actual",
addExpectationResult: addExpectationResult, addExpectationResult: addExpectationResult,
isNot: true isNot: true

View File

@@ -135,7 +135,9 @@ describe("j$.pp", function () {
}, },
env = new j$.Env(); env = new j$.Env();
env.spyOn(TestObject, 'someFunction'); var spyRegistry = new j$.SpyRegistry({currentSpies: function() {return [];}});
spyRegistry.spyOn(TestObject, 'someFunction');
expect(j$.pp(TestObject.someFunction)).toEqual("spy on someFunction"); expect(j$.pp(TestObject.someFunction)).toEqual("spy on someFunction");
expect(j$.pp(j$.createSpy("something"))).toEqual("spy on something"); expect(j$.pp(j$.createSpy("something"))).toEqual("spy on something");
@@ -158,4 +160,3 @@ describe("j$.pp", function () {
expect(j$.pp(obj)).toEqual("{ foo: 'bar' }"); expect(j$.pp(obj)).toEqual("{ foo: 'bar' }");
}); });
}); });

View File

@@ -2,15 +2,15 @@ describe("QueueRunner", function() {
it("runs all the functions it's passed", function() { it("runs all the functions it's passed", function() {
var calls = [], var calls = [],
fn1 = jasmine.createSpy('fn1'), queueableFn1 = { fn: jasmine.createSpy('fn1') },
fn2 = jasmine.createSpy('fn2'), queueableFn2 = { fn: jasmine.createSpy('fn2') },
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn1, fn2] queueableFns: [queueableFn1, queueableFn2]
}); });
fn1.and.callFake(function() { queueableFn1.fn.and.callFake(function() {
calls.push('fn1'); calls.push('fn1');
}); });
fn2.and.callFake(function() { queueableFn2.fn.and.callFake(function() {
calls.push('fn2'); calls.push('fn2');
}); });
@@ -20,19 +20,19 @@ describe("QueueRunner", function() {
}); });
it("calls each function with a consistent 'this'-- an empty object", function() { it("calls each function with a consistent 'this'-- an empty object", function() {
var fn1 = jasmine.createSpy('fn1'), var queueableFn1 = { fn: jasmine.createSpy('fn1') },
fn2 = jasmine.createSpy('fn2'), queueableFn2 = { fn: jasmine.createSpy('fn2') },
fn3 = function(done) { asyncContext = this; done(); }, queueableFn3 = { fn: function(done) { asyncContext = this; done(); } },
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn1, fn2, fn3] queueableFns: [queueableFn1, queueableFn2, queueableFn3]
}), }),
asyncContext; asyncContext;
queueRunner.execute(); queueRunner.execute();
var context = fn1.calls.first().object; var context = queueableFn1.fn.calls.first().object;
expect(context).toEqual({}); expect(context).toEqual({});
expect(fn2.calls.first().object).toBe(context); expect(queueableFn2.fn.calls.first().object).toBe(context);
expect(asyncContext).toBe(context); expect(asyncContext).toBe(context);
}); });
@@ -53,20 +53,20 @@ describe("QueueRunner", function() {
beforeCallback = jasmine.createSpy('beforeCallback'), beforeCallback = jasmine.createSpy('beforeCallback'),
fnCallback = jasmine.createSpy('fnCallback'), fnCallback = jasmine.createSpy('fnCallback'),
afterCallback = jasmine.createSpy('afterCallback'), afterCallback = jasmine.createSpy('afterCallback'),
fn1 = function(done) { queueableFn1 = { fn: function(done) {
beforeCallback(); beforeCallback();
setTimeout(done, 100); setTimeout(done, 100);
}, } },
fn2 = function(done) { queueableFn2 = { fn: function(done) {
fnCallback(); fnCallback();
setTimeout(done, 100); setTimeout(done, 100);
}, } },
fn3 = function(done) { queueableFn3 = { fn: function(done) {
afterCallback(); afterCallback();
setTimeout(done, 100); setTimeout(done, 100);
}, } },
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn1, fn2, fn3], queueableFns: [queueableFn1, queueableFn2, queueableFn3],
onComplete: onComplete onComplete: onComplete
}); });
@@ -94,54 +94,54 @@ describe("QueueRunner", function() {
}); });
it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() { it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() {
var beforeFn = function(done) { }, var timeout = 3,
fn = jasmine.createSpy('fn'), beforeFn = { fn: function(done) { }, type: 'before', timeout: function() { return timeout; } },
queueableFn = { fn: jasmine.createSpy('fn'), type: 'queueable' },
onComplete = jasmine.createSpy('onComplete'), onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'), onException = jasmine.createSpy('onException'),
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [beforeFn, fn], queueableFns: [beforeFn, queueableFn],
onComplete: onComplete, onComplete: onComplete,
onException: onException, onException: onException
enforceTimeout: function() { return true; }
}); });
queueRunner.execute(); queueRunner.execute();
expect(fn).not.toHaveBeenCalled(); expect(queueableFn.fn).not.toHaveBeenCalled();
jasmine.clock().tick(j$.DEFAULT_TIMEOUT_INTERVAL); jasmine.clock().tick(timeout);
expect(onException).toHaveBeenCalledWith(jasmine.any(Error)); expect(onException).toHaveBeenCalledWith(jasmine.any(Error));
expect(fn).toHaveBeenCalled(); expect(queueableFn.fn).toHaveBeenCalled();
expect(onComplete).toHaveBeenCalled(); expect(onComplete).toHaveBeenCalled();
}); });
it("by default does not set a timeout for asynchronous functions", function() { it("by default does not set a timeout for asynchronous functions", function() {
var beforeFn = function(done) { }, var beforeFn = { fn: function(done) { } },
fn = jasmine.createSpy('fn'), queueableFn = { fn: jasmine.createSpy('fn') },
onComplete = jasmine.createSpy('onComplete'), onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'), onException = jasmine.createSpy('onException'),
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [beforeFn, fn], queueableFns: [beforeFn, queueableFn],
onComplete: onComplete, onComplete: onComplete,
onException: onException, onException: onException,
}); });
queueRunner.execute(); queueRunner.execute();
expect(fn).not.toHaveBeenCalled(); expect(queueableFn.fn).not.toHaveBeenCalled();
jasmine.clock().tick(j$.DEFAULT_TIMEOUT_INTERVAL); jasmine.clock().tick(j$.DEFAULT_TIMEOUT_INTERVAL);
expect(onException).not.toHaveBeenCalled(); expect(onException).not.toHaveBeenCalled();
expect(fn).not.toHaveBeenCalled(); expect(queueableFn.fn).not.toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled(); expect(onComplete).not.toHaveBeenCalled();
}); });
it("clears the timeout when an async function throws an exception, to prevent additional onException calls", function() { it("clears the timeout when an async function throws an exception, to prevent additional exception reporting", function() {
var fn = function(done) { throw new Error("error!"); }, var queueableFn = { fn: function(done) { throw new Error("error!"); } },
onComplete = jasmine.createSpy('onComplete'), onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'), onException = jasmine.createSpy('onException'),
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn], queueableFns: [queueableFn],
onComplete: onComplete, onComplete: onComplete,
onException: onException onException: onException
}); });
@@ -156,11 +156,11 @@ describe("QueueRunner", function() {
}); });
it("clears the timeout when the done callback is called", function() { it("clears the timeout when the done callback is called", function() {
var fn = function(done) { done(); }, var queueableFn = { fn: function(done) { done(); } },
onComplete = jasmine.createSpy('onComplete'), onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'), onException = jasmine.createSpy('onException'),
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn], queueableFns: [queueableFn],
onComplete: onComplete, onComplete: onComplete,
onException: onException onException: onException
}); });
@@ -174,75 +174,78 @@ describe("QueueRunner", function() {
}); });
it("only moves to the next spec the first time you call done", function() { it("only moves to the next spec the first time you call done", function() {
var fn = function(done) {done(); done();}, var queueableFn = { fn: function(done) {done(); done();} },
nextFn = jasmine.createSpy('nextFn'); nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn, nextFn] queueableFns: [queueableFn, nextQueueableFn]
}); });
queueRunner.execute(); queueRunner.execute();
expect(nextFn.calls.count()).toEqual(1); expect(nextQueueableFn.fn.calls.count()).toEqual(1);
}); });
it("does not move to the next spec if done is called after an exception has ended the spec", function() { it("does not move to the next spec if done is called after an exception has ended the spec", function() {
var fn = function(done) { var queueableFn = { fn: function(done) {
setTimeout(done, 1); setTimeout(done, 1);
throw new Error('error!'); throw new Error('error!');
}, } },
nextFn = jasmine.createSpy('nextFn'); nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn, nextFn] queueableFns: [queueableFn, nextQueueableFn]
}); });
queueRunner.execute(); queueRunner.execute();
jasmine.clock().tick(1); jasmine.clock().tick(1);
expect(nextFn.calls.count()).toEqual(1); expect(nextQueueableFn.fn.calls.count()).toEqual(1);
}); });
}); });
it("calls an exception handler when an exception is thrown in a fn", function() { it("calls exception handlers when an exception is thrown in a fn", function() {
var fn = function() { var queueableFn = { type: 'queueable',
fn: function() {
throw new Error('fake error'); throw new Error('fake error');
}, } },
exceptionCallback = jasmine.createSpy('exception callback'), onExceptionCallback = jasmine.createSpy('on exception callback'),
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn], queueableFns: [queueableFn],
onException: exceptionCallback onException: onExceptionCallback
}); });
queueRunner.execute(); queueRunner.execute();
expect(exceptionCallback).toHaveBeenCalledWith(jasmine.any(Error)); expect(onExceptionCallback).toHaveBeenCalledWith(jasmine.any(Error));
}); });
it("rethrows an exception if told to", function() { it("rethrows an exception if told to", function() {
var fn = function() { var queueableFn = { fn: function() {
throw new Error('fake error'); throw new Error('fake error');
}, } },
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn], queueableFns: [queueableFn],
catchException: function(e) { return false; } catchException: function(e) { return false; }
}); });
expect(queueRunner.execute).toThrow(); expect(function() {
queueRunner.execute();
}).toThrowError('fake error');
}); });
it("continues running the functions even after an exception is thrown in an async spec", function() { it("continues running the functions even after an exception is thrown in an async spec", function() {
var fn = function(done) { throw new Error("error"); }, var queueableFn = { fn: function(done) { throw new Error("error"); } },
nextFn = jasmine.createSpy("nextFunction"), nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn, nextFn] queueableFns: [queueableFn, nextQueueableFn]
}); });
queueRunner.execute(); queueRunner.execute();
expect(nextFn).toHaveBeenCalled(); expect(nextQueueableFn.fn).toHaveBeenCalled();
}); });
it("calls a provided complete callback when done", function() { it("calls a provided complete callback when done", function() {
var fn = jasmine.createSpy('fn'), var queueableFn = { fn: jasmine.createSpy('fn') },
completeCallback = jasmine.createSpy('completeCallback'), completeCallback = jasmine.createSpy('completeCallback'),
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [fn], queueableFns: [queueableFn],
onComplete: completeCallback onComplete: completeCallback
}); });
@@ -252,12 +255,12 @@ describe("QueueRunner", function() {
}); });
it("calls a provided stack clearing function when done", function() { it("calls a provided stack clearing function when done", function() {
var asyncFn = function(done) { done() }, var asyncFn = { fn: function(done) { done() } },
afterFn = jasmine.createSpy('afterFn'), afterFn = { fn: jasmine.createSpy('afterFn') },
completeCallback = jasmine.createSpy('completeCallback'), completeCallback = jasmine.createSpy('completeCallback'),
clearStack = jasmine.createSpy('clearStack'), clearStack = jasmine.createSpy('clearStack'),
queueRunner = new j$.QueueRunner({ queueRunner = new j$.QueueRunner({
fns: [asyncFn, afterFn], queueableFns: [asyncFn, afterFn],
clearStack: clearStack, clearStack: clearStack,
onComplete: completeCallback onComplete: completeCallback
}); });
@@ -265,7 +268,7 @@ describe("QueueRunner", function() {
clearStack.and.callFake(function(fn) { fn(); }); clearStack.and.callFake(function(fn) { fn(); });
queueRunner.execute(); queueRunner.execute();
expect(afterFn).toHaveBeenCalled(); expect(afterFn.fn).toHaveBeenCalled();
expect(clearStack).toHaveBeenCalledWith(completeCallback); expect(clearStack).toHaveBeenCalledWith(completeCallback);
}); });
}); });

View File

@@ -29,7 +29,7 @@ describe("Spec", function() {
spec = new j$.Spec({ spec = new j$.Spec({
description: 'my test', description: 'my test',
id: 'some-id', id: 'some-id',
fn: function() {}, queueableFn: { fn: function() {} },
queueRunnerFactory: fakeQueueRunner queueRunnerFactory: fakeQueueRunner
}); });
@@ -44,7 +44,7 @@ describe("Spec", function() {
spec = new j$.Spec({ spec = new j$.Spec({
id: 123, id: 123,
description: 'foo bar', description: 'foo bar',
fn: function() {}, queueableFn: { fn: function() {} },
onStart: startCallback, onStart: startCallback,
queueRunnerFactory: fakeQueueRunner queueRunnerFactory: fakeQueueRunner
}); });
@@ -66,7 +66,7 @@ describe("Spec", function() {
expect(beforesWereCalled).toBe(false); expect(beforesWereCalled).toBe(false);
}), }),
spec = new j$.Spec({ spec = new j$.Spec({
fn: function() {}, queueableFn: { fn: function() {} },
beforeFns: function() { beforeFns: function() {
return [function() { return [function() {
beforesWereCalled = true beforesWereCalled = true
@@ -85,25 +85,22 @@ describe("Spec", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'), var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
before = jasmine.createSpy('before'), before = jasmine.createSpy('before'),
after = jasmine.createSpy('after'), after = jasmine.createSpy('after'),
fn = jasmine.createSpy('test body').and.callFake(function() { queueableFn = { fn: jasmine.createSpy('test body').and.callFake(function() {
expect(before).toHaveBeenCalled(); expect(before).toHaveBeenCalled();
expect(after).not.toHaveBeenCalled(); expect(after).not.toHaveBeenCalled();
}), }) },
spec = new j$.Spec({ spec = new j$.Spec({
fn: fn, queueableFn: queueableFn,
beforeFns: function() { beforeAndAfterFns: function() {
return [before] return {befores: [before], afters: [after]}
},
afterFns: function() {
return [after]
}, },
queueRunnerFactory: fakeQueueRunner queueRunnerFactory: fakeQueueRunner
}); });
spec.execute(); spec.execute();
var allSpecFns = fakeQueueRunner.calls.mostRecent().args[0].fns; var allSpecFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
expect(allSpecFns).toEqual([before, fn, after]); expect(allSpecFns).toEqual([before, queueableFn, after]);
}); });
it("is marked pending if created without a function body", function() { it("is marked pending if created without a function body", function() {
@@ -113,7 +110,7 @@ describe("Spec", function() {
resultCallback = jasmine.createSpy('resultCallback'), resultCallback = jasmine.createSpy('resultCallback'),
spec = new j$.Spec({ spec = new j$.Spec({
onStart: startCallback, onStart: startCallback,
fn: null, queueableFn: { fn: null },
resultCallback: resultCallback, resultCallback: resultCallback,
queueRunnerFactory: fakeQueueRunner queueRunnerFactory: fakeQueueRunner
}); });
@@ -129,7 +126,7 @@ describe("Spec", function() {
resultCallback = jasmine.createSpy('resultCallback'), resultCallback = jasmine.createSpy('resultCallback'),
spec = new j$.Spec({ spec = new j$.Spec({
onStart:startCallback, onStart:startCallback,
fn: specBody, queueableFn: { fn: specBody },
resultCallback: resultCallback, resultCallback: resultCallback,
queueRunnerFactory: fakeQueueRunner queueRunnerFactory: fakeQueueRunner
}); });
@@ -158,7 +155,8 @@ describe("Spec", function() {
getSpecName: function() { getSpecName: function() {
return "a suite with a spec" return "a suite with a spec"
}, },
queueRunnerFactory: fakeQueueRunner queueRunnerFactory: fakeQueueRunner,
queueableFn: { fn: null }
}); });
spec.pend(); spec.pend();
@@ -183,7 +181,7 @@ describe("Spec", function() {
it("should call the done callback on execution complete", function() { it("should call the done callback on execution complete", function() {
var done = jasmine.createSpy('done callback'), var done = jasmine.createSpy('done callback'),
spec = new j$.Spec({ spec = new j$.Spec({
fn: function() {}, queueableFn: { fn: function() {} },
catchExceptions: function() { return false; }, catchExceptions: function() { return false; },
resultCallback: function() {}, resultCallback: function() {},
queueRunnerFactory: function(attrs) { attrs.onComplete(); } queueRunnerFactory: function(attrs) { attrs.onComplete(); }
@@ -194,19 +192,19 @@ describe("Spec", function() {
expect(done).toHaveBeenCalled(); expect(done).toHaveBeenCalled();
}); });
it("#status returns passing by default", function(){ it("#status returns passing by default", function() {
var spec = new j$.Spec({ fn: function () {} }); var spec = new j$.Spec({queueableFn: { fn: jasmine.createSpy("spec body")} });
expect(spec.status()).toBe("passed"); expect(spec.status()).toBe('passed');
}); });
it("#status returns passed if all expectations in the spec have passed", function() { it("#status returns passed if all expectations in the spec have passed", function() {
var spec = new j$.Spec({fn: jasmine.createSpy("spec body")}); var spec = new j$.Spec({queueableFn: { fn: jasmine.createSpy("spec body")} });
spec.addExpectationResult(true); spec.addExpectationResult(true);
expect(spec.status()).toBe('passed'); expect(spec.status()).toBe('passed');
}); });
it("#status returns failed if any expectations in the spec have failed", function() { it("#status returns failed if any expectations in the spec have failed", function() {
var spec = new j$.Spec({ fn: jasmine.createSpy("spec body") }); var spec = new j$.Spec({queueableFn: { fn: jasmine.createSpy("spec body") } });
spec.addExpectationResult(true); spec.addExpectationResult(true);
spec.addExpectationResult(false); spec.addExpectationResult(false);
expect(spec.status()).toBe('failed'); expect(spec.status()).toBe('failed');
@@ -215,7 +213,7 @@ describe("Spec", function() {
it("keeps track of passed and failed expectations", function() { it("keeps track of passed and failed expectations", function() {
var resultCallback = jasmine.createSpy('resultCallback'), var resultCallback = jasmine.createSpy('resultCallback'),
spec = new j$.Spec({ spec = new j$.Spec({
fn: jasmine.createSpy("spec body"), queueableFn: { fn: jasmine.createSpy("spec body") },
expectationResultFactory: function (data) { return data; }, expectationResultFactory: function (data) { return data; },
queueRunnerFactory: function(attrs) { attrs.onComplete(); }, queueRunnerFactory: function(attrs) { attrs.onComplete(); },
resultCallback: resultCallback resultCallback: resultCallback
@@ -233,7 +231,8 @@ describe("Spec", function() {
var specNameSpy = jasmine.createSpy('specNameSpy').and.returnValue('expected val'); var specNameSpy = jasmine.createSpy('specNameSpy').and.returnValue('expected val');
var spec = new j$.Spec({ var spec = new j$.Spec({
getSpecName: specNameSpy getSpecName: specNameSpy,
queueableFn: { fn: null }
}); });
expect(spec.getFullName()).toBe('expected val'); expect(spec.getFullName()).toBe('expected val');
@@ -248,7 +247,7 @@ describe("Spec", function() {
spec = new j$.Spec({ spec = new j$.Spec({
description: 'my test', description: 'my test',
id: 'some-id', id: 'some-id',
fn: function() { }, queueableFn: { fn: function() { } },
queueRunnerFactory: fakeQueueRunner queueRunnerFactory: fakeQueueRunner
}); });

View File

@@ -0,0 +1,55 @@
describe("SpyRegistry", function() {
describe("#spyOn", function() {
it("checks for the existence of the object", function() {
var spyRegistry = new j$.SpyRegistry();
expect(function() {
spyRegistry.spyOn(void 0, 'pants');
}).toThrowError(/could not find an object/);
});
it("checks for the existence of the method", function() {
var spyRegistry = new j$.SpyRegistry(),
subject = {};
expect(function() {
spyRegistry.spyOn(subject, 'pants');
}).toThrowError(/method does not exist/);
});
it("checks if it has already been spied upon", function() {
var spies = [],
spyRegistry = new j$.SpyRegistry({currentSpies: function() { return spies; }}),
subject = { spiedFunc: function() {} };
spyRegistry.spyOn(subject, 'spiedFunc');
expect(function() {
spyRegistry.spyOn(subject, 'spiedFunc');
}).toThrowError(/has already been spied upon/);
});
it("overrides the method on the object and returns the spy", function() {
var originalFunctionWasCalled = false,
spyRegistry = new j$.SpyRegistry(),
subject = { spiedFunc: function() { originalFunctionWasCalled = true; } };
var spy = spyRegistry.spyOn(subject, 'spiedFunc');
expect(subject.spiedFunc).toEqual(spy);
});
});
describe("#clearSpies", function() {
it("restores the original functions on the spied-upon objects", function() {
var spies = [],
spyRegistry = new j$.SpyRegistry({currentSpies: function() { return spies; }}),
originalFunction = function() {},
subject = { spiedFunc: originalFunction };
spyRegistry.spyOn(subject, 'spiedFunc');
spyRegistry.clearSpies();
expect(subject.spiedFunc).toBe(originalFunction);
});
});
});

View File

@@ -52,6 +52,31 @@ describe("Suite", function() {
expect(suite.beforeFns).toEqual([innerBefore, outerBefore]); expect(suite.beforeFns).toEqual([innerBefore, outerBefore]);
}); });
it("runs beforeAll functions in order of needed execution", function() {
var env = new j$.Env(),
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
suite = new j$.Suite({
env: env,
description: "I am a suite",
queueRunner: fakeQueueRunner
}),
firstBefore = jasmine.createSpy('outerBeforeAll'),
lastBefore = jasmine.createSpy('insideBeforeAll'),
fakeIt = {execute: jasmine.createSpy('it'), isExecutable: function() { return true; } };
suite.beforeAll(firstBefore);
suite.beforeAll(lastBefore);
suite.addChild(fakeIt);
suite.execute();
var suiteFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
suiteFns[0]();
expect(firstBefore).toHaveBeenCalled();
suiteFns[1]();
expect(lastBefore).toHaveBeenCalled();
});
it("adds after functions in order of needed execution", function() { it("adds after functions in order of needed execution", function() {
var env = new j$.Env(), var env = new j$.Env(),
suite = new j$.Suite({ suite = new j$.Suite({
@@ -67,6 +92,31 @@ describe("Suite", function() {
expect(suite.afterFns).toEqual([innerAfter, outerAfter]); expect(suite.afterFns).toEqual([innerAfter, outerAfter]);
}); });
it("runs afterAll functions in order of needed execution", function() {
var env = new j$.Env(),
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
suite = new j$.Suite({
env: env,
description: "I am a suite",
queueRunner: fakeQueueRunner
}),
firstAfter = jasmine.createSpy('outerAfterAll'),
lastAfter = jasmine.createSpy('insideAfterAll'),
fakeIt = {execute: jasmine.createSpy('it'), isExecutable: function() { return true; } };
suite.afterAll(firstAfter);
suite.afterAll(lastAfter);
suite.addChild(fakeIt);
suite.execute();
var suiteFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
suiteFns[1]();
expect(firstAfter).toHaveBeenCalled();
suiteFns[2]();
expect(lastAfter).toHaveBeenCalled();
});
it("can be disabled, but still calls callbacks", function() { it("can be disabled, but still calls callbacks", function() {
var env = new j$.Env(), var env = new j$.Env(),
fakeQueueRunner = jasmine.createSpy('fake queue runner'), fakeQueueRunner = jasmine.createSpy('fake queue runner'),
@@ -93,7 +143,7 @@ describe("Suite", function() {
expect(onComplete).toHaveBeenCalled(); expect(onComplete).toHaveBeenCalled();
}); });
it("delegates execution of its specs and suites", function() { it("delegates execution of its specs, suites, beforeAlls, and afterAlls", function() {
var env = new j$.Env(), var env = new j$.Env(),
parentSuiteDone = jasmine.createSpy('parent suite done'), parentSuiteDone = jasmine.createSpy('parent suite done'),
fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'), fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'),
@@ -109,22 +159,57 @@ describe("Suite", function() {
queueRunner: fakeQueueRunner queueRunner: fakeQueueRunner
}), }),
fakeSpec1 = { fakeSpec1 = {
execute: jasmine.createSpy('fakeSpec1') execute: jasmine.createSpy('fakeSpec1'),
}; isExecutable: function() { return true; }
},
beforeAllFn = { fn: jasmine.createSpy('beforeAll') },
afterAllFn = { fn: jasmine.createSpy('afterAll') };
spyOn(suite, "execute"); spyOn(suite, "execute");
parentSuite.addChild(fakeSpec1); parentSuite.addChild(fakeSpec1);
parentSuite.addChild(suite); parentSuite.addChild(suite);
parentSuite.beforeAll(beforeAllFn);
parentSuite.afterAll(afterAllFn);
parentSuite.execute(parentSuiteDone); parentSuite.execute(parentSuiteDone);
var parentSuiteFns = fakeQueueRunnerForParent.calls.mostRecent().args[0].fns; var parentSuiteFns = fakeQueueRunnerForParent.calls.mostRecent().args[0].queueableFns;
parentSuiteFns[0](); parentSuiteFns[0].fn();
expect(beforeAllFn.fn).toHaveBeenCalled();
parentSuiteFns[1].fn();
expect(fakeSpec1.execute).toHaveBeenCalled(); expect(fakeSpec1.execute).toHaveBeenCalled();
parentSuiteFns[1](); parentSuiteFns[2].fn();
expect(suite.execute).toHaveBeenCalled(); expect(suite.execute).toHaveBeenCalled();
parentSuiteFns[3].fn();
expect(afterAllFn.fn).toHaveBeenCalled();
});
it("does not run beforeAll or afterAll if there are no child specs to run", function() {
var env = new j$.Env(),
fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'),
fakeQueueRunnerForChild = jasmine.createSpy('fake child queue runner'),
parentSuite = new j$.Suite({
env: env,
description: "I am a suite",
queueRunner: fakeQueueRunnerForParent
}),
childSuite = new j$.Suite({
env: env,
description: "I am a suite",
queueRunner: fakeQueueRunnerForChild,
parentSuite: parentSuite
}),
beforeAllFn = jasmine.createSpy('beforeAll'),
afterAllFn = jasmine.createSpy('afterAll');
parentSuite.addChild(childSuite);
parentSuite.beforeAll(beforeAllFn);
parentSuite.afterAll(afterAllFn);
parentSuite.execute();
expect(fakeQueueRunnerForParent).toHaveBeenCalledWith(jasmine.objectContaining({queueableFns: []}));
}); });
it("calls a provided onStart callback when starting", function() { it("calls a provided onStart callback when starting", function() {
@@ -138,7 +223,8 @@ describe("Suite", function() {
queueRunner: fakeQueueRunner queueRunner: fakeQueueRunner
}), }),
fakeSpec1 = { fakeSpec1 = {
execute: jasmine.createSpy('fakeSpec1') execute: jasmine.createSpy('fakeSpec1'),
isExecutable: function() { return true; }
}; };
suite.execute(); suite.execute();
@@ -182,9 +268,10 @@ describe("Suite", function() {
expect(suiteResultsCallback).toHaveBeenCalledWith({ expect(suiteResultsCallback).toHaveBeenCalledWith({
id: suite.id, id: suite.id,
status: '', status: 'finished',
description: "with a child suite", description: "with a child suite",
fullName: "with a child suite" fullName: "with a child suite",
failedExpectations: []
}); });
}); });
@@ -210,7 +297,8 @@ describe("Suite", function() {
id: suite.id, id: suite.id,
status: 'disabled', status: 'disabled',
description: "with a child suite", description: "with a child suite",
fullName: "with a child suite" fullName: "with a child suite",
failedExpectations: []
}); });
}); });
}); });

View File

@@ -38,13 +38,13 @@ describe("Custom Matchers (Integration)", function() {
}); });
it("passes the spec if the custom matcher passes", function(done) { it("passes the spec if the custom matcher passes", function(done) {
env.addMatchers({
toBeReal: function() {
return { compare: function() { return { pass: true }; } };
}
});
env.it("spec using custom matcher", function() { env.it("spec using custom matcher", function() {
env.addMatchers({
toBeReal: function() {
return { compare: function() { return { pass: true }; } };
}
});
env.expect(true).toBeReal(); env.expect(true).toBeReal();
}); });
@@ -57,16 +57,16 @@ describe("Custom Matchers (Integration)", function() {
}); });
it("uses the negative compare function for a negative comparison, if provided", function(done) { it("uses the negative compare function for a negative comparison, if provided", function(done) {
env.addMatchers({
toBeReal: function() {
return {
compare: function() { return { pass: true }; },
negativeCompare: function() { return { pass: true }; }
};
}
});
env.it("spec with custom negative comparison matcher", function() { env.it("spec with custom negative comparison matcher", function() {
env.addMatchers({
toBeReal: function() {
return {
compare: function() { return { pass: true }; },
negativeCompare: function() { return { pass: true }; }
};
}
});
env.expect(true).not.toBeReal(); env.expect(true).not.toBeReal();
}); });
@@ -79,17 +79,17 @@ describe("Custom Matchers (Integration)", function() {
}); });
it("generates messages with the same rules as built in matchers absent a custom message", function(done) { it("generates messages with the same rules as built in matchers absent a custom message", function(done) {
env.addMatchers({ env.it('spec with an expectation', function() {
toBeReal: function() { env.addMatchers({
return { toBeReal: function() {
compare: function() { return {
return { pass: false }; compare: function() {
return { pass: false };
}
} }
} }
} });
});
env.it('spec with an expectation', function() {
env.expect("a").toBeReal(); env.expect("a").toBeReal();
}); });
@@ -103,13 +103,14 @@ describe("Custom Matchers (Integration)", function() {
it("passes the expected and actual arguments to the comparison function", function(done) { it("passes the expected and actual arguments to the comparison function", function(done) {
var argumentSpy = jasmine.createSpy("argument spy").and.returnValue({ pass: true }); var argumentSpy = jasmine.createSpy("argument spy").and.returnValue({ pass: true });
env.addMatchers({
toBeReal: function() {
return { compare: argumentSpy };
}
});
env.it('spec with an expectation', function () { env.it('spec with an expectation', function () {
env.addMatchers({
toBeReal: function() {
return { compare: argumentSpy };
}
});
env.expect(true).toBeReal(); env.expect(true).toBeReal();
env.expect(true).toBeReal("arg"); env.expect(true).toBeReal("arg");
env.expect(true).toBeReal("arg1", "arg2"); env.expect(true).toBeReal("arg1", "arg2");
@@ -130,12 +131,13 @@ describe("Custom Matchers (Integration)", function() {
argumentSpy = jasmine.createSpy("argument spy").and.returnValue(matcherFactory), argumentSpy = jasmine.createSpy("argument spy").and.returnValue(matcherFactory),
customEqualityFn = function() { return true; }; customEqualityFn = function() { return true; };
env.addCustomEqualityTester(customEqualityFn);
env.addMatchers({
toBeReal: argumentSpy
});
env.it("spec with expectation", function() { env.it("spec with expectation", function() {
env.addCustomEqualityTester(customEqualityFn);
env.addMatchers({
toBeReal: argumentSpy
});
env.expect(true).toBeReal(); env.expect(true).toBeReal();
}); });

View File

@@ -1,4 +1,44 @@
describe("Env integration", function() { describe("Env integration", function() {
beforeEach(function() {
jasmine.addMatchers({
toHaveFailedExpecationsForSuite: function(util, customeEqualityTesters) {
return {
compare: function(actual, suiteName, expectedFailures) {
var foundSuite = false, expectations = true, foundFailures = [];
for (var i = 0; i < actual.calls.count(); i++) {
var args = actual.calls.argsFor(i)[0];
if (args.description === suiteName) {
foundSuite = true;
for (var j = 0; j < args.failedExpectations.length; j++) {
foundFailures.push(args.failedExpectations[j].message);
}
for (var j = 0; j < expectedFailures.length; j++) {
var failure = foundFailures[j];
var expectedFailure = expectedFailures[j];
if (Object.prototype.toString.call(expectedFailure) === '[object RegExp]') {
expectations = expectations && expectedFailure.test(failure);
} else {
expectations = expectations && failure === expectedFailure;
}
}
break;
}
}
return {
pass: foundSuite && expectations,
message: !foundSuite ? 'The suite "' + suiteName + '" never finished' :
'Expected suite "' + suiteName + '" to have failures ' + jasmine.pp(expectedFailures) + ' but it had ' + jasmine.pp(foundFailures)
};
}
};
}
});
});
it("Suites execute as expected (no nesting)", function(done) { it("Suites execute as expected (no nesting)", function(done) {
var env = new j$.Env(), var env = new j$.Env(),
@@ -80,7 +120,7 @@ describe("Env integration", function() {
env.describe("Outer suite", function() { env.describe("Outer suite", function() {
env.it("an outer spec", function() { env.it("an outer spec", function() {
calls.push('an outer spec') calls.push('an outer spec');
}); });
env.describe("Inner suite", function() { env.describe("Inner suite", function() {
env.it("an inner spec", function() { env.it("an inner spec", function() {
@@ -212,6 +252,305 @@ describe("Env integration", function() {
env.execute(); env.execute();
}); });
it("calls associated beforeAlls/afterAlls only once per suite", function(done) {
var env = new j$.Env(),
before = jasmine.createSpy('beforeAll'),
after = jasmine.createSpy('afterAll');
env.addReporter({
jasmineDone: function() {
expect(after).toHaveBeenCalled();
expect(after.calls.count()).toBe(1);
expect(before.calls.count()).toBe(1);
done();
}
});
env.describe("with beforeAll and afterAll", function() {
env.it("spec", function() {
expect(before).toHaveBeenCalled();
expect(after).not.toHaveBeenCalled();
});
env.it("another spec", function() {
expect(before).toHaveBeenCalled();
expect(after).not.toHaveBeenCalled();
});
env.beforeAll(before);
env.afterAll(after);
});
env.execute();
});
it("calls associated beforeAlls/afterAlls only once per suite for async", function(done) {
var env = new j$.Env(),
before = jasmine.createSpy('beforeAll'),
after = jasmine.createSpy('afterAll');
env.addReporter({
jasmineDone: function() {
expect(after).toHaveBeenCalled();
expect(after.calls.count()).toBe(1);
expect(before.calls.count()).toBe(1);
done();
}
});
env.describe("with beforeAll and afterAll", function() {
env.it("spec", function() {
expect(before).toHaveBeenCalled();
expect(after).not.toHaveBeenCalled();
});
env.it("another spec", function() {
expect(before).toHaveBeenCalled();
expect(after).not.toHaveBeenCalled();
});
env.beforeAll(function(beforeCallbackUnderTest) {
before();
beforeCallbackUnderTest();
});
env.afterAll(function(afterCallbackUnderTest) {
after();
afterCallbackUnderTest();
});
});
env.execute();
});
it("calls associated beforeAlls/afterAlls with the cascaded 'this'", function(done) {
var env = new j$.Env();
env.addReporter({jasmineDone: done});
env.describe("with beforeAll and afterAll", function() {
env.beforeAll(function() {
this.x = 1;
});
env.it("has an x at the root", function() {
expect(this.x).toBe(1);
});
env.describe("child that deletes", function() {
env.beforeAll(function() {
expect(this.x).toBe(1);
delete this.x;
});
env.it("has no x", function() {
expect(this.x).not.toBeDefined();
});
});
env.describe("child should still have x", function() {
env.beforeAll(function(innerDone) {
expect(this.x).toBe(1);
innerDone();
});
env.it("has an x", function() {
expect(this.x).toBe(1);
delete this.x;
});
env.it("still has an x", function() {
expect(this.x).toBe(1);
});
env.it("adds a y", function() {
this.y = 2;
expect(this.y).toBe(2);
});
env.it("doesn't have y that was added in sibling", function() {
expect(this.y).not.toBeDefined();
});
});
});
env.execute();
});
it("fails all underlying specs when the beforeAll fails", function (done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone" ]);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.specDone.calls.count()).toEqual(2);
expect(reporter.specDone.calls.argsFor(0)[0])
.toEqual(jasmine.objectContaining({status: 'failed'}));
expect(reporter.specDone.calls.argsFor(0)[0].failedExpectations[0].message)
.toEqual("Expected 1 to be 2.");
expect(reporter.specDone.calls.argsFor(1)[0])
.toEqual(jasmine.objectContaining({status: 'failed'}));
expect(reporter.specDone.calls.argsFor(1)[0].failedExpectations[0].message)
.toEqual("Expected 1 to be 2.");
done();
});
env.addReporter(reporter);
env.describe('A suite', function(){
env.beforeAll(function() {
env.expect(1).toBe(2);
});
env.it("spec that will be failed", function() {
});
env.describe("nesting", function() {
env.it("another spec to fail", function() {
});
});
});
env.execute();
});
describe('suiteDone reporting', function(){
it("reports when an afterAll fails an expectation", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone','suiteDone']);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.suiteDone).toHaveFailedExpecationsForSuite('my suite', [
'Expected 1 to equal 2.',
'Expected 2 to equal 3.'
]);
done();
});
env.addReporter(reporter);
env.describe('my suite', function() {
env.it('my spec', function() {
});
env.afterAll(function() {
env.expect(1).toEqual(2);
env.expect(2).toEqual(3);
});
});
env.execute();
});
it("if there are no specs, it still reports correctly", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone','suiteDone']);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.suiteDone).toHaveFailedExpecationsForSuite('outer suite', [
'Expected 1 to equal 2.',
'Expected 2 to equal 3.'
]);
done();
});
env.addReporter(reporter);
env.describe('outer suite', function() {
env.describe('inner suite', function() {
env.it('spec', function(){ });
});
env.afterAll(function() {
env.expect(1).toEqual(2);
env.expect(2).toEqual(3);
});
});
env.execute();
});
it("reports when afterAll throws an exception", function(done) {
var env = new j$.Env(),
error = new Error('After All Exception'),
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone','suiteDone']);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.suiteDone).toHaveFailedExpecationsForSuite('my suite', [
(/^Error: After All Exception/)
]);
done();
});
env.addReporter(reporter);
env.describe('my suite', function() {
env.it('my spec', function() {
});
env.afterAll(function() {
throw error;
});
});
env.execute();
});
it("reports when an async afterAll fails an expectation", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone','suiteDone']);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.suiteDone).toHaveFailedExpecationsForSuite('my suite', [
'Expected 1 to equal 2.'
]);
done();
});
env.addReporter(reporter);
env.describe('my suite', function() {
env.it('my spec', function() {
});
env.afterAll(function(afterAllDone) {
env.expect(1).toEqual(2);
afterAllDone();
});
});
env.execute();
});
it("reports when an async afterAll throws an exception", function(done) {
var env = new j$.Env(),
error = new Error('After All Exception'),
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone','suiteDone']);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.suiteDone).toHaveFailedExpecationsForSuite('my suite', [
(/^Error: After All Exception/)
]);
done();
});
env.addReporter(reporter);
env.describe('my suite', function() {
env.it('my spec', function() {
});
env.afterAll(function(afterAllDone) {
throw error;
});
});
env.execute();
});
});
it("Allows specifying which specs and suites to run", function(done) { it("Allows specifying which specs and suites to run", function(done) {
var env = new j$.Env(), var env = new j$.Env(),
calls = [], calls = [],
@@ -248,21 +587,61 @@ describe("Env integration", function() {
env.execute([secondSuite.id, firstSpec.id]); env.execute([secondSuite.id, firstSpec.id]);
}); });
it("Functions can be spied on and have their calls tracked", function () { it('runs before and after all functions for runnables provided to .execute()', function(done) {
var env = new j$.Env(); var env = new j$.Env(),
calls = [],
first_spec,
second_spec;
var originalFunctionWasCalled = false; var assertions = function() {
var subject = { expect(calls).toEqual([
spiedFunc: function() { "before",
originalFunctionWasCalled = true; "first spec",
return "original result"; "after",
} "before",
}; "second spec",
"after"
]);
done();
};
env.addReporter({jasmineDone: assertions});
env.describe("first suite", function() {
env.beforeAll(function() {
calls.push("before");
});
env.afterAll(function() {
calls.push("after")
});
first_spec = env.it("spec", function() {
calls.push('first spec');
});
second_spec = env.it("spec 2", function() {
calls.push("second spec");
});
});
env.execute([first_spec.id, second_spec.id]);
});
it("Functions can be spied on and have their calls tracked", function (done) {
var env = new j$.Env();
var originalFunctionWasCalled = false;
var subject = {
spiedFunc: function() {
originalFunctionWasCalled = true;
return "original result";
}
};
env.addReporter({jasmineDone: done});
env.it("works with spies", function() {
var spy = env.spyOn(subject, 'spiedFunc').and.returnValue("stubbed result"); var spy = env.spyOn(subject, 'spiedFunc').and.returnValue("stubbed result");
expect(subject.spiedFunc).toEqual(spy); expect(subject.spiedFunc).toEqual(spy);
expect(subject.spiedFunc.calls.any()).toEqual(false); expect(subject.spiedFunc.calls.any()).toEqual(false);
expect(subject.spiedFunc.calls.count()).toEqual(0); expect(subject.spiedFunc.calls.count()).toEqual(0);
@@ -281,6 +660,67 @@ describe("Env integration", function() {
expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['bar']); expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['bar']);
expect(subject.spiedFunc.calls.mostRecent().returnValue).toEqual("original result"); expect(subject.spiedFunc.calls.mostRecent().returnValue).toEqual("original result");
expect(originalFunctionWasCalled).toEqual(true); expect(originalFunctionWasCalled).toEqual(true);
});
env.execute();
});
it('removes all spies added in a spec after the spec is complete', function(done) {
var env = new j$.Env(),
originalFoo = function() {},
testObj = {
foo: originalFoo
},
firstSpec = jasmine.createSpy('firstSpec').and.callFake(function() {
env.spyOn(testObj, 'foo');
}),
secondSpec = jasmine.createSpy('secondSpec').and.callFake(function() {
expect(testObj.foo).toBe(originalFoo);
});
env.describe('test suite', function() {
env.it('spec 0', firstSpec);
env.it('spec 1', secondSpec);
});
var assertions = function() {
expect(firstSpec).toHaveBeenCalled();
expect(secondSpec).toHaveBeenCalled();
done();
};
env.addReporter({ jasmineDone: assertions });
env.execute();
});
it('removes all spies added in a suite after the suite is complete', function(done) {
var env = new j$.Env(),
originalFoo = function() {},
testObj = {
foo: originalFoo
};
env.describe('test suite', function() {
env.beforeAll(function() { env.spyOn(testObj, 'foo');})
env.it('spec 0', function() {
expect(j$.isSpy(testObj.foo)).toBe(true);
});
env.it('spec 1', function() {
expect(j$.isSpy(testObj.foo)).toBe(true);
});
});
env.describe('another suite', function() {
env.it('spec 2', function() {
expect(j$.isSpy(testObj.foo)).toBe(false);
});
});
env.addReporter({ jasmineDone: done });
env.execute();
}); });
it("Mock clock can be installed and used in tests", function(done) { it("Mock clock can be installed and used in tests", function(done) {
@@ -345,11 +785,11 @@ describe("Env integration", function() {
beforeEach(function() { beforeEach(function() {
originalTimeout = j$.DEFAULT_TIMEOUT_INTERVAL; originalTimeout = j$.DEFAULT_TIMEOUT_INTERVAL;
jasmine.getEnv().clock.install(); jasmine.clock().install();
}); });
afterEach(function() { afterEach(function() {
jasmine.getEnv().clock.uninstall(); jasmine.clock().uninstall();
j$.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; j$.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
}); });
@@ -371,7 +811,63 @@ describe("Env integration", function() {
env.it("async spec that doesn't call done", function(underTestCallback) { env.it("async spec that doesn't call done", function(underTestCallback) {
env.expect(true).toBeTruthy(); env.expect(true).toBeTruthy();
jasmine.getEnv().clock.tick(8416); jasmine.clock().tick(8416);
});
env.execute();
});
it("should wait a specified interval before failing beforeAll's and their associated specs that haven't called done", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone" ]);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.specDone.calls.count()).toEqual(2);
expect(reporter.specDone.calls.argsFor(0)[0]).toEqual(jasmine.objectContaining({status: 'failed'}));
expect(reporter.specDone.calls.argsFor(1)[0]).toEqual(jasmine.objectContaining({status: 'failed'}));
done();
});
env.addReporter(reporter);
j$.DEFAULT_TIMEOUT_INTERVAL = 1290;
env.beforeAll(function(done) {
jasmine.clock().tick(1290);
});
env.it("spec that will be failed", function() {
});
env.describe("nesting", function() {
env.it("another spec to fail", function() {
});
});
env.execute();
});
it("should wait the specified interval before reporting an afterAll that fails to call done", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone','suiteDone']);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.suiteDone).toHaveFailedExpecationsForSuite('my suite', [
(/^Error: Timeout - Async callback was not invoked within timeout specified by jasmine\.DEFAULT_TIMEOUT_INTERVAL\./)
]);
done();
});
env.addReporter(reporter);
j$.DEFAULT_TIMEOUT_INTERVAL = 3000;
env.describe('my suite', function() {
env.it('my spec', function() {
});
env.afterAll(function(innerDone) {
jasmine.clock().tick(3001);
innerDone();
});
}); });
env.execute(); env.execute();
@@ -436,7 +932,58 @@ describe("Env integration", function() {
}); });
}); });
// TODO: something is wrong with this spec describe('focused tests', function() {
it('should only run the focused tests', function(done) {
var env = new j$.Env(),
calls = [];
var assertions = function() {
expect(calls).toEqual(['focused']);
done();
};
env.addReporter({jasmineDone: assertions});
env.describe('a suite', function() {
env.fit('is focused', function() {
calls.push('focused');
});
env.it('is not focused', function() {
calls.push('freakout');
})
});
env.execute();
});
it('should only run focused suites', function(){
var env = new j$.Env(),
calls = [];
var assertions = function() {
expect(calls).toEqual(['focused']);
done();
};
env.addReporter({jasmineDone: assertions});
env.fdescribe('a focused suite', function() {
env.it('is focused', function() {
calls.push('focused');
});
});
env.describe('a regular suite', function() {
env.it('is not focused', function() {
calls.push('freakout');
})
});
env.execute();
});
});
it("should report as expected", function(done) { it("should report as expected", function(done) {
var env = new j$.Env(), var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ reporter = jasmine.createSpyObj('fakeReporter', [
@@ -502,11 +1049,7 @@ describe("Env integration", function() {
it("Custom equality testers should be per spec", function(done) { it("Custom equality testers should be per spec", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}), var env = new j$.Env({global: { setTimeout: setTimeout }}),
reporter = jasmine.createSpyObj('fakeReporter', [ reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone", "jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone" "specDone"
]); ]);
@@ -536,30 +1079,42 @@ describe("Env integration", function() {
env.execute(); env.execute();
}); });
it("Custom matchers should be per spec", function() { it("Custom equality testers should be per suite", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}), var env = new j$.Env({global: { setTimeout: setTimeout }}),
matchers = {
toFoo: function() {}
},
reporter = jasmine.createSpyObj('fakeReporter', [ reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone", "jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone" "specDone"
]); ]);
reporter.jasmineDone.and.callFake(function() {
var firstSpecResult = reporter.specDone.calls.first().args[0],
secondSpecResult = reporter.specDone.calls.argsFor(0)[0],
thirdSpecResult = reporter.specDone.calls.mostRecent().args[0];
expect(firstSpecResult.status).toEqual("passed");
expect(secondSpecResult.status).toEqual("passed");
expect(thirdSpecResult.status).toEqual("failed");
done();
});
env.addReporter(reporter); env.addReporter(reporter);
env.describe("testing custom matchers", function() { env.describe("testing custom equality testers", function() {
env.it("with a custom matcher", function() { env.beforeAll(function() { env.addCustomEqualityTester(function(a, b) { return true; }); });
env.addMatchers(matchers);
expect(env.expect().toFoo).toBeDefined(); env.it("with a custom tester", function() {
env.expect("a").toEqual("b");
}); });
env.it("without a custom matcher", function() { env.it("with the same custom tester", function() {
expect(env.expect().toFoo).toBeUndefined(); env.expect("a").toEqual("b");
});
});
env.describe("another suite", function() {
env.it("without the custom tester", function(){
env.expect("a").toEqual("b");
}); });
}); });
@@ -569,11 +1124,7 @@ describe("Env integration", function() {
it("Custom equality testers for toContain should be per spec", function(done) { it("Custom equality testers for toContain should be per spec", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}), var env = new j$.Env({global: { setTimeout: setTimeout }}),
reporter = jasmine.createSpyObj('fakeReporter', [ reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone", "jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone" "specDone"
]); ]);
@@ -596,7 +1147,7 @@ describe("Env integration", function() {
}); });
env.it("without a custom tester", function() { env.it("without a custom tester", function() {
env.expect("a").toContain("b"); env.expect(["a"]).toContain("b");
}); });
}); });
@@ -616,5 +1167,166 @@ describe("Env integration", function() {
env.execute(); env.execute();
}); });
});
it("Custom equality testers for toContain should be per suite", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineDone",
"specDone"
]);
reporter.jasmineDone.and.callFake(function() {
var firstSpecResult = reporter.specDone.calls.first().args[0],
secondSpecResult = reporter.specDone.calls.argsFor(1)[0],
thirdSpecResult = reporter.specDone.calls.mostRecent().args[0];
expect(firstSpecResult.status).toEqual("passed");
expect(secondSpecResult.status).toEqual("passed");
expect(thirdSpecResult.status).toEqual("failed");
done();
});
env.addReporter(reporter);
env.describe("testing custom equality testers", function() {
env.beforeAll(function() { env.addCustomEqualityTester(function(a, b) { return true; })});
env.it("with a custom tester", function() {
env.expect(["a"]).toContain("b");
});
env.it("also with the custom tester", function() {
env.expect(["a"]).toContain("b");
});
});
env.describe("another suite", function() {
env.it("without the custom tester", function() {
env.expect(["a"]).toContain("b");
});
});
env.execute();
});
it("Custom matchers should be per spec", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
matchers = {
toFoo: function() {}
};
env.describe("testing custom matchers", function() {
env.it("with a custom matcher", function() {
env.addMatchers(matchers);
expect(env.expect().toFoo).toBeDefined();
});
env.it("without a custom matcher", function() {
expect(env.expect().toFoo).toBeUndefined();
});
});
env.addReporter({jasmineDone: done});
env.execute();
});
it("Custom matchers should be per suite", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
matchers = {
toFoo: function() {}
};
env.describe("testing custom matchers", function() {
env.beforeAll(function() { env.addMatchers(matchers); });
env.it("with a custom matcher", function() {
expect(env.expect().toFoo).toBeDefined();
});
env.it("with the same custom matcher", function() {
expect(env.expect().toFoo).toBeDefined();
});
});
env.describe("another suite", function() {
env.it("no longer has the custom matcher", function() {
expect(env.expect().toFoo).not.toBeDefined();
});
});
env.addReporter({jasmineDone: done});
env.execute();
});
it('throws an exception if you try to create a spy outside of a runnable', function (done) {
var env = new j$.Env(),
obj = {fn: function () {}},
exception;
env.describe("a suite", function () {
try {
env.spyOn(obj, 'fn');
} catch(e) {
exception = e;
}
});
var assertions = function() {
expect(exception.message).toBe('Spies must be created in a before function or a spec');
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('throws an exception if you try to add a matcher outside of a runnable', function (done) {
var env = new j$.Env(),
obj = {fn: function () {}},
exception;
env.describe("a suite", function () {
try {
env.addMatchers({myMatcher: function(actual,expected){return false;}});
} catch(e) {
exception = e;
}
});
var assertions = function() {
expect(exception.message).toBe('Matchers must be added in a before function or a spec');
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('throws an exception if you try to add a custom equality outside of a runnable', function (done) {
var env = new j$.Env(),
obj = {fn: function () {}},
exception;
env.describe("a suite", function () {
try {
env.addCustomEqualityTester(function(first, second) {return true;});
} catch(e) {
exception = e;
}
});
var assertions = function() {
expect(exception.message).toBe('Custom Equalities must be added in a before function or a spec');
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
});

View File

@@ -159,7 +159,7 @@ describe("jasmine spec running", function () {
]; ];
expect(actions).toEqual(expected); expect(actions).toEqual(expected);
done(); done();
} };
env.addReporter({jasmineDone: assertions}); env.addReporter({jasmineDone: assertions});
@@ -228,6 +228,257 @@ describe("jasmine spec running", function () {
env.execute(); env.execute();
}); });
it('should run beforeAlls before beforeEachs and afterAlls after afterEachs', function() {
var actions = [];
env.beforeAll(function() {
actions.push('runner beforeAll');
});
env.afterAll(function() {
actions.push('runner afterAll');
});
env.beforeEach(function () {
actions.push('runner beforeEach');
});
env.afterEach(function () {
actions.push('runner afterEach');
});
env.describe('Something', function() {
env.beforeEach(function() {
actions.push('inner beforeEach');
});
env.afterEach(function() {
actions.push('inner afterEach');
});
env.beforeAll(function() {
actions.push('inner beforeAll');
});
env.afterAll(function() {
actions.push('inner afterAll');
});
env.it('does something or other', function() {
actions.push('it');
});
});
var assertions = function() {
var expected = [
"runner beforeAll",
"inner beforeAll",
"runner beforeEach",
"inner beforeEach",
"it",
"inner afterEach",
"runner afterEach",
"inner afterAll",
"runner afterAll"
];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('should run beforeAlls and afterAlls as beforeEachs and afterEachs in the order declared when runnablesToRun is provided', function() {
var actions = [],
spec,
spec2;
env.beforeAll(function() {
actions.push('runner beforeAll');
});
env.afterAll(function() {
actions.push('runner afterAll');
});
env.beforeEach(function () {
actions.push('runner beforeEach');
});
env.afterEach(function () {
actions.push('runner afterEach');
});
env.describe('Something', function() {
env.beforeEach(function() {
actions.push('inner beforeEach');
});
env.afterEach(function() {
actions.push('inner afterEach');
});
env.beforeAll(function() {
actions.push('inner beforeAll');
});
env.afterAll(function() {
actions.push('inner afterAll');
});
spec = env.it('does something', function() {
actions.push('it');
});
spec2 = env.it('does something or other', function() {
actions.push('it2');
});
});
var assertions = function() {
var expected = [
"runner beforeAll",
"inner beforeAll",
"runner beforeEach",
"inner beforeEach",
"it",
"inner afterEach",
"runner afterEach",
"inner afterAll",
"runner afterAll",
"runner beforeAll",
"inner beforeAll",
"runner beforeEach",
"inner beforeEach",
"it2",
"inner afterEach",
"runner afterEach",
"inner afterAll",
"runner afterAll"
];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute([spec.id, spec2.id]);
});
describe('focused runnables', function() {
it('runs the relevant alls and eachs for each runnable', function(done) {
var actions = [];
env.beforeAll(function() {actions.push('beforeAll')});
env.afterAll(function() {actions.push('afterAll')});
env.beforeEach(function() {actions.push('beforeEach')});
env.afterEach(function() {actions.push('afterEach')});
env.fdescribe('a focused suite', function() {
env.it('is run', function() {
actions.push('spec in fdescribe')
});
});
env.describe('an unfocused suite', function() {
env.fit('has a focused spec', function() {
actions.push('focused spec')
});
});
var assertions = function() {
var expected = [
'beforeAll',
'beforeEach',
'spec in fdescribe',
'afterEach',
'afterAll',
'beforeAll',
'beforeEach',
'focused spec',
'afterEach',
'afterAll'
];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('focused specs in focused suites cause non-focused siblings to not run', function(done){
var actions = [];
env.fdescribe('focused suite', function() {
env.it('unfocused spec', function() {
actions.push('unfocused spec')
});
env.fit('focused spec', function() {
actions.push('focused spec')
});
});
var assertions = function() {
var expected = ['focused spec'];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('focused suites in focused suites cause non-focused siblings to not run', function(done){
var actions = [];
env.fdescribe('focused suite', function() {
env.it('unfocused spec', function() {
actions.push('unfocused spec')
});
env.fdescribe('inner focused suite', function() {
env.it('inner spec', function() {
actions.push('inner spec');
});
});
});
var assertions = function() {
var expected = ['inner spec'];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('focused runnables unfocus ancestor focused suites', function() {
var actions = [];
env.fdescribe('focused suite', function() {
env.it('unfocused spec', function() {
actions.push('unfocused spec')
});
env.describe('inner focused suite', function() {
env.fit('focused spec', function() {
actions.push('focused spec');
});
});
});
var assertions = function() {
var expected = ['focused spec'];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
});
it("shouldn't run disabled suites", function(done) { it("shouldn't run disabled suites", function(done) {
var specInADisabledSuite = jasmine.createSpy("specInADisabledSuite"), var specInADisabledSuite = jasmine.createSpy("specInADisabledSuite"),
suite = env.describe('A Suite', function() { suite = env.describe('A Suite', function() {
@@ -236,10 +487,36 @@ describe("jasmine spec running", function () {
}); });
}); });
suite.execute(function() { var assertions = function() {
expect(specInADisabledSuite).not.toHaveBeenCalled(); expect(specInADisabledSuite).not.toHaveBeenCalled();
done(); done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it("should allow top level suites to be disabled", function() {
var specInADisabledSuite = jasmine.createSpy("specInADisabledSuite"),
otherSpec = jasmine.createSpy("otherSpec");
env.xdescribe('A disabled suite', function() {
env.it('spec inside a disabled suite', specInADisabledSuite);
}); });
env.describe('Another suite', function() {
env.it('another spec', otherSpec);
});
var assertions = function() {
expect(specInADisabledSuite).not.toHaveBeenCalled();
expect(otherSpec).toHaveBeenCalled();
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
}); });
it("should set all pending specs to pending when a suite is run", function(done) { it("should set all pending specs to pending when a suite is run", function(done) {
@@ -254,7 +531,6 @@ describe("jasmine spec running", function () {
}); });
}); });
// TODO: is this useful? It doesn't catch syntax errors // TODO: is this useful? It doesn't catch syntax errors
xit("should recover gracefully when there are errors in describe functions", function() { xit("should recover gracefully when there are errors in describe functions", function() {
var specs = []; var specs = [];

View File

@@ -179,6 +179,34 @@ describe("New HtmlReporter", function() {
}); });
}); });
describe("when there are suite failures", function () {
it("displays the exceptions in their own alert bars", function(){
var env = new j$.Env(),
container = document.createElement("div"),
getContainer = function() { return container; },
reporter = new j$.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.jasmineStarted({});
reporter.suiteDone({ failedExpectations: [{ message: 'My After All Exception' }] });
reporter.suiteDone({ failedExpectations: [{ message: 'My Other Exception' }] });
reporter.jasmineDone({});
var alertBars = container.querySelectorAll(".alert .bar");
expect(alertBars.length).toEqual(3);
expect(alertBars[1].innerHTML).toMatch(/My After All Exception/);
expect(alertBars[1].getAttribute("class")).toEqual('bar errored');
expect(alertBars[2].innerHTML).toMatch(/My Other Exception/);
});
});
describe("when Jasmine is done", function() { describe("when Jasmine is done", function() {
it("adds EMPTY to the link title of specs that have no expectations", function() { it("adds EMPTY to the link title of specs that have no expectations", function() {
if (!window.console) { if (!window.console) {

195
spec/node_suite.js Normal file
View File

@@ -0,0 +1,195 @@
var fs = require('fs');
var util = require('util');
var path = require('path');
// boot code for jasmine
var jasmineRequire = require('../lib/jasmine-core/jasmine.js');
var jasmine = jasmineRequire.core(jasmineRequire);
var consoleFns = require('../lib/console/console.js');
extend(jasmineRequire, consoleFns);
jasmineRequire.console(jasmineRequire, jasmine);
var env = jasmine.getEnv();
var jasmineInterface = {
describe: function(description, specDefinitions) {
return env.describe(description, specDefinitions);
},
xdescribe: function(description, specDefinitions) {
return env.xdescribe(description, specDefinitions);
},
it: function(desc, func) {
return env.it(desc, func);
},
xit: function(desc, func) {
return env.xit(desc, func);
},
beforeEach: function(beforeEachFunction) {
return env.beforeEach(beforeEachFunction);
},
afterEach: function(afterEachFunction) {
return env.afterEach(afterEachFunction);
},
expect: function(actual) {
return env.expect(actual);
},
spyOn: function(obj, methodName) {
return env.spyOn(obj, methodName);
},
jsApiReporter: new jasmine.JsApiReporter({
timer: new jasmine.Timer()
}),
beforeAll: function(beforeAllFunction) {
return env.beforeAll(beforeAllFunction);
},
afterAll: function(afterAllFunction) {
return env.afterAll(afterAllFunction);
}
};
extend(global, jasmineInterface);
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
}
jasmine.addCustomEqualityTester = function(tester) {
env.addCustomEqualityTester(tester);
};
jasmine.addMatchers = function(matchers) {
return env.addMatchers(matchers);
};
jasmine.clock = function() {
return env.clock;
};
// Jasmine "runner"
function executeSpecs(specs, done, isVerbose, showColors) {
global.jasmine = jasmine;
for (var i = 0; i < specs.length; i++) {
var filename = specs[i];
require(filename.replace(/\.\w+$/, ""));
}
var env = jasmine.getEnv();
var consoleReporter = new jasmine.ConsoleReporter({
print: util.print,
onComplete: done,
showColors: showColors,
timer: new jasmine.Timer()
});
env.addReporter(consoleReporter);
env.execute();
}
function getFiles(dir, matcher) {
var allFiles = [];
if (fs.statSync(dir).isFile() && dir.match(matcher)) {
allFiles.push(dir);
} else {
var files = fs.readdirSync(dir);
for (var i = 0, len = files.length; i < len; ++i) {
var filename = dir + '/' + files[i];
if (fs.statSync(filename).isFile() && filename.match(matcher)) {
allFiles.push(filename);
} else if (fs.statSync(filename).isDirectory()) {
var subfiles = getFiles(filename);
subfiles.forEach(function(result) {
allFiles.push(result);
});
}
}
}
return allFiles;
}
function getSpecFiles(dir) {
return getFiles(dir, new RegExp("Spec.js$"));
}
var j$require = (function() {
var exported = {},
j$req;
global.getJasmineRequireObj = getJasmineRequireObj;
j$req = require(__dirname + "/../src/core/requireCore.js");
extend(j$req, require(__dirname + "/../src/console/requireConsole.js"));
var srcFiles = getFiles(__dirname + "/../src/core");
srcFiles.push(__dirname + "/../src/version.js");
srcFiles.push(__dirname + "/../src/console/ConsoleReporter.js");
for (var i = 0; i < srcFiles.length; i++) {
require(srcFiles[i]);
}
extend(j$req, exported);
delete global.getJasmineRequireObj;
return j$req;
function getJasmineRequireObj() {
return exported;
}
}());
j$ = j$require.core(j$require);
j$require.console(j$require, j$);
// options from command line
var isVerbose = false;
var showColors = true;
var perfSuite = false;
process.argv.forEach(function(arg) {
switch (arg) {
case '--color':
showColors = true;
break;
case '--noColor':
showColors = false;
break;
case '--verbose':
isVerbose = true;
break;
case '--perf':
perfSuite = true;
break;
}
});
specs = [];
if (perfSuite) {
specs = getFiles(__dirname + '/performance', new RegExp("test.js$"));
} else {
var consoleSpecs = getSpecFiles(__dirname + "/console"),
coreSpecs = getSpecFiles(__dirname + "/core"),
specs = consoleSpecs.concat(coreSpecs);
}
executeSpecs(specs, function(passed) {
if (passed) {
process.exit(0);
} else {
process.exit(1);
}
}, isVerbose, showColors);

View File

@@ -19,7 +19,8 @@ getJasmineRequireObj().ConsoleReporter = function() {
red: '\x1B[31m', red: '\x1B[31m',
yellow: '\x1B[33m', yellow: '\x1B[33m',
none: '\x1B[0m' none: '\x1B[0m'
}; },
failedSuites = [];
this.jasmineStarted = function() { this.jasmineStarted = function() {
specCount = 0; specCount = 0;
@@ -54,9 +55,12 @@ getJasmineRequireObj().ConsoleReporter = function() {
printNewline(); printNewline();
var seconds = timer.elapsed() / 1000; var seconds = timer.elapsed() / 1000;
print('Finished in ' + seconds + ' ' + plural('second', seconds)); print('Finished in ' + seconds + ' ' + plural('second', seconds));
printNewline(); printNewline();
for(i = 0; i < failedSuites.length; i++) {
suiteFailureDetails(failedSuites[i]);
}
onComplete(failureCount === 0); onComplete(failureCount === 0);
}; };
@@ -81,6 +85,13 @@ getJasmineRequireObj().ConsoleReporter = function() {
} }
}; };
this.suiteDone = function(result) {
if (result.failedExpectations && result.failedExpectations.length > 0) {
failureCount++;
failedSuites.push(result);
}
};
return this; return this;
function printNewline() { function printNewline() {
@@ -125,6 +136,17 @@ getJasmineRequireObj().ConsoleReporter = function() {
printNewline(); printNewline();
} }
function suiteFailureDetails(result) {
for (var i = 0; i < result.failedExpectations.length; i++) {
printNewline();
print(colored('red', 'An error was thrown in an afterAll'));
printNewline();
print(colored('red', 'AfterAll ' + result.failedExpectations[i].message));
}
printNewline();
}
} }
return ConsoleReporter; return ConsoleReporter;

View File

@@ -14,11 +14,19 @@ getJasmineRequireObj().Env = function(j$) {
this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler(), new j$.MockDate(global)); this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler(), new j$.MockDate(global));
var runnableLookupTable = {}; var runnableLookupTable = {};
var runnableResources = {};
var spies = [];
var currentSpec = null; var currentSpec = null;
var currentSuite = null; var currentlyExecutingSuites = [];
var currentDeclarationSuite = null;
var currentSuite = function() {
return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
};
var currentRunnable = function() {
return currentSpec || currentSuite();
};
var reporter = new j$.ReportDispatcher([ var reporter = new j$.ReportDispatcher([
'jasmineStarted', 'jasmineStarted',
@@ -33,11 +41,21 @@ getJasmineRequireObj().Env = function(j$) {
return true; return true;
}; };
var equalityTesters = [];
var customEqualityTesters = [];
this.addCustomEqualityTester = function(tester) { this.addCustomEqualityTester = function(tester) {
customEqualityTesters.push(tester); if(!currentRunnable()) {
throw new Error('Custom Equalities must be added in a before function or a spec');
}
runnableResources[currentRunnable().id].customEqualityTesters.push(tester);
};
this.addMatchers = function(matchersToAdd) {
if(!currentRunnable()) {
throw new Error('Matchers must be added in a before function or a spec');
}
var customMatchers = runnableResources[currentRunnable().id].customMatchers;
for (var matcherName in matchersToAdd) {
customMatchers[matcherName] = matchersToAdd[matcherName];
}
}; };
j$.Expectation.addCoreMatchers(j$.matchers); j$.Expectation.addCoreMatchers(j$.matchers);
@@ -55,7 +73,8 @@ getJasmineRequireObj().Env = function(j$) {
var expectationFactory = function(actual, spec) { var expectationFactory = function(actual, spec) {
return j$.Expectation.Factory({ return j$.Expectation.Factory({
util: j$.matchersUtil, util: j$.matchersUtil,
customEqualityTesters: customEqualityTesters, customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
customMatchers: runnableResources[spec.id].customMatchers,
actual: actual, actual: actual,
addExpectationResult: addExpectationResult addExpectationResult: addExpectationResult
}); });
@@ -65,30 +84,44 @@ getJasmineRequireObj().Env = function(j$) {
} }
}; };
var specStarted = function(spec) { var defaultResourcesForRunnable = function(id, parentRunnableId) {
currentSpec = spec; var resources = {spies: [], customEqualityTesters: [], customMatchers: {}};
reporter.specStarted(spec.result);
if(runnableResources[parentRunnableId]){
resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters);
resources.customMatchers = j$.util.clone(runnableResources[parentRunnableId].customMatchers);
}
runnableResources[id] = resources;
}; };
var beforeFns = function(suite) { var clearResourcesForRunnable = function(id) {
spyRegistry.clearSpies();
delete runnableResources[id];
};
var beforeAndAfterFns = function(suite, runnablesExplictlySet) {
return function() { return function() {
var befores = []; var befores = [],
afters = [],
beforeAlls = [],
afterAlls = [];
while(suite) { while(suite) {
befores = befores.concat(suite.beforeFns); befores = befores.concat(suite.beforeFns);
suite = suite.parentSuite;
}
return befores.reverse();
};
};
var afterFns = function(suite) {
return function() {
var afters = [];
while(suite) {
afters = afters.concat(suite.afterFns); afters = afters.concat(suite.afterFns);
if (runnablesExplictlySet()) {
beforeAlls = beforeAlls.concat(suite.beforeAllFns);
afterAlls = afterAlls.concat(suite.afterAllFns);
}
suite = suite.parentSuite; suite = suite.parentSuite;
} }
return afters; return {
befores: beforeAlls.reverse().concat(befores.reverse()),
afters: afters.concat(afterAlls)
};
}; };
}; };
@@ -146,65 +179,54 @@ getJasmineRequireObj().Env = function(j$) {
id: getNextSuiteId(), id: getNextSuiteId(),
description: 'Jasmine__TopLevel__Suite', description: 'Jasmine__TopLevel__Suite',
queueRunner: queueRunnerFactory, queueRunner: queueRunnerFactory,
resultCallback: function() {} // TODO - hook this up resultCallback: function(attrs) {
reporter.suiteDone(attrs);
}
}); });
runnableLookupTable[topSuite.id] = topSuite; runnableLookupTable[topSuite.id] = topSuite;
currentSuite = topSuite; defaultResourcesForRunnable(topSuite.id);
currentDeclarationSuite = topSuite;
this.topSuite = function() { this.topSuite = function() {
return topSuite; return topSuite;
}; };
this.execute = function(runnablesToRun) { this.execute = function(runnablesToRun) {
runnablesToRun = runnablesToRun || [topSuite.id]; if(runnablesToRun) {
runnablesExplictlySet = true;
} else if (focusedRunnables.length) {
runnablesExplictlySet = true;
runnablesToRun = focusedRunnables;
} else {
runnablesToRun = [topSuite.id];
}
var allFns = []; var allFns = [];
for(var i = 0; i < runnablesToRun.length; i++) { for(var i = 0; i < runnablesToRun.length; i++) {
var runnable = runnableLookupTable[runnablesToRun[i]]; var runnable = runnableLookupTable[runnablesToRun[i]];
allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable)); allFns.push((function(runnable) { return { fn: function(done) { runnable.execute(done); } }; })(runnable));
} }
reporter.jasmineStarted({ reporter.jasmineStarted({
totalSpecsDefined: totalSpecsDefined totalSpecsDefined: totalSpecsDefined
}); });
queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone}); queueRunnerFactory({queueableFns: allFns, onComplete: reporter.jasmineDone});
}; };
this.addReporter = function(reporterToAdd) { this.addReporter = function(reporterToAdd) {
reporter.addReporter(reporterToAdd); reporter.addReporter(reporterToAdd);
}; };
this.addMatchers = function(matchersToAdd) { var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
j$.Expectation.addMatchers(matchersToAdd); if(!currentRunnable()) {
}; throw new Error('Spies must be created in a before function or a spec');
this.spyOn = function(obj, methodName) {
if (j$.util.isUndefined(obj)) {
throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
} }
return runnableResources[currentRunnable().id].spies;
}});
if (j$.util.isUndefined(obj[methodName])) { this.spyOn = function() {
throw new Error(methodName + '() method does not exist'); return spyRegistry.spyOn.apply(spyRegistry, arguments);
}
if (obj[methodName] && j$.isSpy(obj[methodName])) {
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
throw new Error(methodName + ' has already been spied upon');
}
var spy = j$.createSpy(methodName, obj[methodName]);
spies.push({
spy: spy,
baseObj: obj,
methodName: methodName,
originalValue: obj[methodName]
});
obj[methodName] = spy;
return spy;
}; };
var suiteFactory = function(description) { var suiteFactory = function(description) {
@@ -212,40 +234,33 @@ getJasmineRequireObj().Env = function(j$) {
env: self, env: self,
id: getNextSuiteId(), id: getNextSuiteId(),
description: description, description: description,
parentSuite: currentSuite, parentSuite: currentDeclarationSuite,
queueRunner: queueRunnerFactory, queueRunner: queueRunnerFactory,
onStart: suiteStarted, onStart: suiteStarted,
expectationFactory: expectationFactory,
expectationResultFactory: expectationResultFactory,
resultCallback: function(attrs) { resultCallback: function(attrs) {
if (!suite.disabled) {
clearResourcesForRunnable(suite.id);
currentlyExecutingSuites.pop();
}
reporter.suiteDone(attrs); reporter.suiteDone(attrs);
} }
}); });
runnableLookupTable[suite.id] = suite; runnableLookupTable[suite.id] = suite;
return suite; return suite;
function suiteStarted(suite) {
currentlyExecutingSuites.push(suite);
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
reporter.suiteStarted(suite.result);
}
}; };
this.describe = function(description, specDefinitions) { this.describe = function(description, specDefinitions) {
var suite = suiteFactory(description); var suite = suiteFactory(description);
addSpecsToSuite(suite, specDefinitions);
var parentSuite = currentSuite;
parentSuite.addChild(suite);
currentSuite = suite;
var declarationError = null;
try {
specDefinitions.call(suite);
} catch (e) {
declarationError = e;
}
if (declarationError) {
this.it('encountered a declaration exception', function() {
throw declarationError;
});
}
currentSuite = parentSuite;
return suite; return suite;
}; };
@@ -255,15 +270,75 @@ getJasmineRequireObj().Env = function(j$) {
return suite; return suite;
}; };
var focusedRunnables = [];
this.fdescribe = function(description, specDefinitions) {
var suite = suiteFactory(description);
suite.isFocused = true;
focusedRunnables.push(suite.id);
unfocusAncestor();
addSpecsToSuite(suite, specDefinitions);
return suite;
};
function addSpecsToSuite(suite, specDefinitions) {
var parentSuite = currentDeclarationSuite;
parentSuite.addChild(suite);
currentDeclarationSuite = suite;
var declarationError = null;
try {
specDefinitions.call(suite);
} catch (e) {
declarationError = e;
}
if (declarationError) {
self.it('encountered a declaration exception', function() {
throw declarationError;
});
}
currentDeclarationSuite = parentSuite;
}
function findFocusedAncestor(suite) {
while (suite) {
if (suite.isFocused) {
return suite.id;
}
suite = suite.parentSuite;
}
return null;
}
function unfocusAncestor() {
var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
if (focusedAncestor) {
for (var i = 0; i < focusedRunnables.length; i++) {
if (focusedRunnables[i] === focusedAncestor) {
focusedRunnables.splice(i, 1);
break;
}
}
}
}
var runnablesExplictlySet = false;
var runnablesExplictlySetGetter = function(){
return runnablesExplictlySet;
};
var specFactory = function(description, fn, suite) { var specFactory = function(description, fn, suite) {
totalSpecsDefined++; totalSpecsDefined++;
var spec = new j$.Spec({ var spec = new j$.Spec({
id: getNextSpecId(), id: getNextSpecId(),
beforeFns: beforeFns(suite), beforeAndAfterFns: beforeAndAfterFns(suite, runnablesExplictlySetGetter),
afterFns: afterFns(suite),
expectationFactory: expectationFactory, expectationFactory: expectationFactory,
exceptionFormatter: exceptionFormatter,
resultCallback: specResultCallback, resultCallback: specResultCallback,
getSpecName: function(spec) { getSpecName: function(spec) {
return getSpecName(spec, suite); return getSpecName(spec, suite);
@@ -272,7 +347,8 @@ getJasmineRequireObj().Env = function(j$) {
description: description, description: description,
expectationResultFactory: expectationResultFactory, expectationResultFactory: expectationResultFactory,
queueRunnerFactory: queueRunnerFactory, queueRunnerFactory: queueRunnerFactory,
fn: fn userContext: function() { return suite.clonedSharedUserContext(); },
queueableFn: { fn: fn, type: 'it', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } }
}); });
runnableLookupTable[spec.id] = spec; runnableLookupTable[spec.id] = spec;
@@ -283,30 +359,22 @@ getJasmineRequireObj().Env = function(j$) {
return spec; return spec;
function removeAllSpies() {
for (var i = 0; i < spies.length; i++) {
var spyEntry = spies[i];
spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
}
spies = [];
}
function specResultCallback(result) { function specResultCallback(result) {
removeAllSpies(); clearResourcesForRunnable(spec.id);
j$.Expectation.resetMatchers();
customEqualityTesters = [];
currentSpec = null; currentSpec = null;
reporter.specDone(result); reporter.specDone(result);
} }
};
var suiteStarted = function(suite) { function specStarted(spec) {
reporter.suiteStarted(suite.result); currentSpec = spec;
defaultResourcesForRunnable(spec.id, suite.id);
reporter.specStarted(spec.result);
}
}; };
this.it = function(description, fn) { this.it = function(description, fn) {
var spec = specFactory(description, fn, currentSuite); var spec = specFactory(description, fn, currentDeclarationSuite);
currentSuite.addChild(spec); currentDeclarationSuite.addChild(spec);
return spec; return spec;
}; };
@@ -316,20 +384,36 @@ getJasmineRequireObj().Env = function(j$) {
return spec; return spec;
}; };
this.fit = function(description, fn ){
var spec = this.it(description, fn);
focusedRunnables.push(spec.id);
unfocusAncestor();
return spec;
};
this.expect = function(actual) { this.expect = function(actual) {
if (!currentSpec) { if (!currentRunnable()) {
throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out'); throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out');
} }
return currentSpec.expect(actual); return currentRunnable().expect(actual);
}; };
this.beforeEach = function(beforeEachFunction) { this.beforeEach = function(beforeEachFunction) {
currentSuite.beforeEach(beforeEachFunction); currentDeclarationSuite.beforeEach({ fn: beforeEachFunction, type: 'beforeEach', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } });
};
this.beforeAll = function(beforeAllFunction) {
currentDeclarationSuite.beforeAll({ fn: beforeAllFunction, type: 'beforeAll', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } });
}; };
this.afterEach = function(afterEachFunction) { this.afterEach = function(afterEachFunction) {
currentSuite.afterEach(afterEachFunction); currentDeclarationSuite.afterEach({ fn: afterEachFunction, type: 'afterEach', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } });
};
this.afterAll = function(afterAllFunction) {
currentDeclarationSuite.afterAll({ fn: afterAllFunction, type: 'afterAll', timeout: function() { return j$.DEFAULT_TIMEOUT_INTERVAL; } });
}; };
this.pending = function() { this.pending = function() {
@@ -343,7 +427,7 @@ getJasmineRequireObj().Env = function(j$) {
message += error.message || error; message += error.message || error;
} }
currentSpec.addExpectationResult(false, { currentRunnable().addExpectationResult(false, {
matcherName: '', matcherName: '',
passed: false, passed: false,
expected: '', expected: '',

View File

@@ -1,7 +1,5 @@
getJasmineRequireObj().Expectation = function() { getJasmineRequireObj().Expectation = function() {
var matchers = {};
function Expectation(options) { function Expectation(options) {
this.util = options.util || { buildFailureMessage: function() {} }; this.util = options.util || { buildFailureMessage: function() {} };
this.customEqualityTesters = options.customEqualityTesters || []; this.customEqualityTesters = options.customEqualityTesters || [];
@@ -9,8 +7,9 @@ getJasmineRequireObj().Expectation = function() {
this.addExpectationResult = options.addExpectationResult || function(){}; this.addExpectationResult = options.addExpectationResult || function(){};
this.isNot = options.isNot; this.isNot = options.isNot;
for (var matcherName in matchers) { var customMatchers = options.customMatchers || {};
this[matcherName] = matchers[matcherName]; for (var matcherName in customMatchers) {
this[matcherName] = Expectation.prototype.wrapCompare(matcherName, customMatchers[matcherName]);
} }
} }
@@ -77,19 +76,6 @@ getJasmineRequireObj().Expectation = function() {
} }
}; };
Expectation.addMatchers = function(matchersToAdd) {
for (var name in matchersToAdd) {
var matcher = matchersToAdd[name];
matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
}
};
Expectation.resetMatchers = function() {
for (var name in matchers) {
delete matchers[name];
}
};
Expectation.Factory = function(options) { Expectation.Factory = function(options) {
options = options || {}; options = options || {};

View File

@@ -11,31 +11,31 @@ getJasmineRequireObj().QueueRunner = function(j$) {
} }
function QueueRunner(attrs) { function QueueRunner(attrs) {
this.fns = attrs.fns || []; this.queueableFns = attrs.queueableFns || [];
this.onComplete = attrs.onComplete || function() {}; this.onComplete = attrs.onComplete || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();}; this.clearStack = attrs.clearStack || function(fn) {fn();};
this.onException = attrs.onException || function() {}; this.onException = attrs.onException || function() {};
this.catchException = attrs.catchException || function() { return true; }; this.catchException = attrs.catchException || function() { return true; };
this.enforceTimeout = attrs.enforceTimeout || function() { return false; }; this.userContext = attrs.userContext || {};
this.userContext = {};
this.timer = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout}; this.timer = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
} }
QueueRunner.prototype.execute = function() { QueueRunner.prototype.execute = function() {
this.run(this.fns, 0); this.run(this.queueableFns, 0);
}; };
QueueRunner.prototype.run = function(fns, recursiveIndex) { QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
var length = fns.length, var length = queueableFns.length,
self = this, self = this,
iterativeIndex; iterativeIndex;
for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) { for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
var fn = fns[iterativeIndex]; var queueableFn = queueableFns[iterativeIndex];
if (fn.length > 0) { if (queueableFn.fn.length > 0) {
return attemptAsync(fn); return attemptAsync(queueableFn);
} else { } else {
attemptSync(fn); attemptSync(queueableFn);
} }
} }
@@ -45,41 +45,46 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.clearStack(this.onComplete); this.clearStack(this.onComplete);
} }
function attemptSync(fn) { function attemptSync(queueableFn) {
try { try {
fn.call(self.userContext); queueableFn.fn.call(self.userContext);
} catch (e) { } catch (e) {
handleException(e); handleException(e, queueableFn);
} }
} }
function attemptAsync(fn) { function attemptAsync(queueableFn) {
var clearTimeout = function () { var clearTimeout = function () {
Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeoutId]]); Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeoutId]]);
}, },
next = once(function () { next = once(function () {
clearTimeout(timeoutId); clearTimeout(timeoutId);
self.run(fns, iterativeIndex + 1); self.run(queueableFns, iterativeIndex + 1);
}), }),
timeoutId; timeoutId;
if (self.enforceTimeout()) { if (queueableFn.timeout) {
timeoutId = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() { timeoutId = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
self.onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.')); var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
onException(error, queueableFn);
next(); next();
}, j$.DEFAULT_TIMEOUT_INTERVAL]]); }, queueableFn.timeout()]]);
} }
try { try {
fn.call(self.userContext, next); queueableFn.fn.call(self.userContext, next);
} catch (e) { } catch (e) {
handleException(e); handleException(e, queueableFn);
next(); next();
} }
} }
function handleException(e) { function onException(e, queueableFn) {
self.onException(e); self.onException(e);
}
function handleException(e, queueableFn) {
onException(e, queueableFn);
if (!self.catchException(e)) { if (!self.catchException(e)) {
//TODO: set a var when we catch an exception and //TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way.. //use a finally block to close the loop in a nice way..

View File

@@ -4,17 +4,16 @@ getJasmineRequireObj().Spec = function(j$) {
this.resultCallback = attrs.resultCallback || function() {}; this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id; this.id = attrs.id;
this.description = attrs.description || ''; this.description = attrs.description || '';
this.fn = attrs.fn; this.queueableFn = attrs.queueableFn;
this.beforeFns = attrs.beforeFns || function() { return []; }; this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return {befores: [], afters: []}; };
this.afterFns = attrs.afterFns || function() { return []; }; this.userContext = attrs.userContext || function() { return {}; };
this.onStart = attrs.onStart || function() {}; this.onStart = attrs.onStart || function() {};
this.exceptionFormatter = attrs.exceptionFormatter || function() {};
this.getSpecName = attrs.getSpecName || function() { return ''; }; this.getSpecName = attrs.getSpecName || function() { return ''; };
this.expectationResultFactory = attrs.expectationResultFactory || function() { }; this.expectationResultFactory = attrs.expectationResultFactory || function() { };
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
if (!this.fn) { if (!this.queueableFn.fn) {
this.pend(); this.pend();
} }
@@ -50,30 +49,16 @@ getJasmineRequireObj().Spec = function(j$) {
return; return;
} }
var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()); var fns = this.beforeAndAfterFns();
var allFns = fns.befores.concat(this.queueableFn).concat(fns.afters);
this.queueRunnerFactory({ this.queueRunnerFactory({
fns: allFns, queueableFns: allFns,
onException: onException, onException: function() { self.onException.apply(self, arguments); },
onComplete: complete, onComplete: complete,
enforceTimeout: function() { return true; } userContext: this.userContext()
}); });
function onException(e) {
if (Spec.isPendingSpecException(e)) {
self.pend();
return;
}
self.addExpectationResult(false, {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: e
});
}
function complete() { function complete() {
self.result.status = self.status(); self.result.status = self.status();
self.resultCallback(self.result); self.resultCallback(self.result);
@@ -84,6 +69,21 @@ getJasmineRequireObj().Spec = function(j$) {
} }
}; };
Spec.prototype.onException = function onException(e) {
if (Spec.isPendingSpecException(e)) {
this.pend();
return;
}
this.addExpectationResult(false, {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: e
});
};
Spec.prototype.disable = function() { Spec.prototype.disable = function() {
this.disabled = true; this.disabled = true;
}; };
@@ -108,6 +108,10 @@ getJasmineRequireObj().Spec = function(j$) {
} }
}; };
Spec.prototype.isExecutable = function() {
return !this.disabled && !this.markedPending;
};
Spec.prototype.getFullName = function() { Spec.prototype.getFullName = function() {
return this.getSpecName(this); return this.getSpecName(this);
}; };

45
src/core/SpyRegistry.js Normal file
View File

@@ -0,0 +1,45 @@
getJasmineRequireObj().SpyRegistry = function(j$) {
function SpyRegistry(options) {
options = options || {};
var currentSpies = options.currentSpies || function() { return []; };
this.spyOn = function(obj, methodName) {
if (j$.util.isUndefined(obj)) {
throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
}
if (j$.util.isUndefined(obj[methodName])) {
throw new Error(methodName + '() method does not exist');
}
if (obj[methodName] && j$.isSpy(obj[methodName])) {
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
throw new Error(methodName + ' has already been spied upon');
}
var spy = j$.createSpy(methodName, obj[methodName]);
currentSpies().push({
spy: spy,
baseObj: obj,
methodName: methodName,
originalValue: obj[methodName]
});
obj[methodName] = spy;
return spy;
};
this.clearSpies = function() {
var spies = currentSpies();
for (var i = 0; i < spies.length; i++) {
var spyEntry = spies[i];
spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
}
};
}
return SpyRegistry;
};

View File

@@ -7,9 +7,13 @@ getJasmineRequireObj().Suite = function() {
this.onStart = attrs.onStart || function() {}; this.onStart = attrs.onStart || function() {};
this.resultCallback = attrs.resultCallback || function() {}; this.resultCallback = attrs.resultCallback || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();}; this.clearStack = attrs.clearStack || function(fn) {fn();};
this.expectationFactory = attrs.expectationFactory;
this.expectationResultFactory = attrs.expectationResultFactory;
this.beforeFns = []; this.beforeFns = [];
this.afterFns = []; this.afterFns = [];
this.beforeAllFns = [];
this.afterAllFns = [];
this.queueRunner = attrs.queueRunner || function() {}; this.queueRunner = attrs.queueRunner || function() {};
this.disabled = false; this.disabled = false;
@@ -17,12 +21,16 @@ getJasmineRequireObj().Suite = function() {
this.result = { this.result = {
id: this.id, id: this.id,
status: this.disabled ? 'disabled' : '',
description: this.description, description: this.description,
fullName: this.getFullName() fullName: this.getFullName(),
failedExpectations: []
}; };
} }
Suite.prototype.expect = function(actual) {
return this.expectationFactory(actual, this);
};
Suite.prototype.getFullName = function() { Suite.prototype.getFullName = function() {
var fullName = this.description; var fullName = this.description;
for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
@@ -42,10 +50,18 @@ getJasmineRequireObj().Suite = function() {
this.beforeFns.unshift(fn); this.beforeFns.unshift(fn);
}; };
Suite.prototype.beforeAll = function(fn) {
this.beforeAllFns.push(fn);
};
Suite.prototype.afterEach = function(fn) { Suite.prototype.afterEach = function(fn) {
this.afterFns.unshift(fn); this.afterFns.unshift(fn);
}; };
Suite.prototype.afterAll = function(fn) {
this.afterAllFns.push(fn);
};
Suite.prototype.addChild = function(child) { Suite.prototype.addChild = function(child) {
this.children.push(child); this.children.push(child);
}; };
@@ -62,16 +78,25 @@ getJasmineRequireObj().Suite = function() {
var allFns = []; var allFns = [];
for (var i = 0; i < this.children.length; i++) { if (this.isExecutable()) {
allFns.push(wrapChildAsAsync(this.children[i])); allFns = allFns.concat(this.beforeAllFns);
for (var i = 0; i < this.children.length; i++) {
allFns.push(wrapChildAsAsync(this.children[i]));
}
allFns = allFns.concat(this.afterAllFns);
} }
this.queueRunner({ this.queueRunner({
fns: allFns, queueableFns: allFns,
onComplete: complete onComplete: complete,
userContext: this.sharedUserContext(),
onException: function() { self.onException.apply(self, arguments); }
}); });
function complete() { function complete() {
self.result.status = self.disabled ? 'disabled' : 'finished';
self.resultCallback(self.result); self.resultCallback(self.result);
if (onComplete) { if (onComplete) {
@@ -80,10 +105,82 @@ getJasmineRequireObj().Suite = function() {
} }
function wrapChildAsAsync(child) { function wrapChildAsAsync(child) {
return function(done) { child.execute(done); }; return { fn: function(done) { child.execute(done); } };
} }
}; };
Suite.prototype.isExecutable = function() {
var foundActive = false;
for(var i = 0; i < this.children.length; i++) {
if(this.children[i].isExecutable()) {
foundActive = true;
break;
}
}
return foundActive;
};
Suite.prototype.sharedUserContext = function() {
if (!this.sharedContext) {
this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {};
}
return this.sharedContext;
};
Suite.prototype.clonedSharedUserContext = function() {
return clone(this.sharedUserContext());
};
Suite.prototype.onException = function() {
if(isAfterAll(this.children)) {
var data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: arguments[0]
};
this.result.failedExpectations.push(this.expectationResultFactory(data));
} else {
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
child.onException.apply(child, arguments);
}
}
};
Suite.prototype.addExpectationResult = function () {
if(isAfterAll(this.children) && isFailure(arguments)){
var data = arguments[1];
this.result.failedExpectations.push(this.expectationResultFactory(data));
} else {
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
child.addExpectationResult.apply(child, arguments);
}
}
};
function isAfterAll(children) {
return children && children[0].result.status;
}
function isFailure(args) {
return !args[0];
}
function clone(obj) {
var clonedObj = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
clonedObj[prop] = obj[prop];
}
}
return clonedObj;
}
return Suite; return Suite;
}; };

View File

@@ -33,6 +33,7 @@ getJasmineRequireObj = (function (jasmineGlobal) {
j$.QueueRunner = jRequire.QueueRunner(j$); j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher(); j$.ReportDispatcher = jRequire.ReportDispatcher();
j$.Spec = jRequire.Spec(j$); j$.Spec = jRequire.Spec(j$);
j$.SpyRegistry = jRequire.SpyRegistry(j$);
j$.SpyStrategy = jRequire.SpyStrategy(); j$.SpyStrategy = jRequire.SpyStrategy();
j$.Suite = jRequire.Suite(); j$.Suite = jRequire.Suite();
j$.Timer = jRequire.Timer(); j$.Timer = jRequire.Timer();

View File

@@ -24,6 +24,14 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.afterEach(afterEachFunction); return env.afterEach(afterEachFunction);
}, },
beforeAll: function(beforeAllFunction) {
return env.beforeAll(beforeAllFunction);
},
afterAll: function(afterAllFunction) {
return env.afterAll(afterAllFunction);
},
expect: function(actual) { expect: function(actual) {
return env.expect(actual); return env.expect(actual);
}, },

View File

@@ -40,5 +40,20 @@ getJasmineRequireObj().util = function() {
return false; return false;
}; };
util.clone = function(obj) {
if (Object.prototype.toString.apply(obj) === '[object Array]') {
return obj.slice();
}
var cloned = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
cloned[prop] = obj[prop];
}
}
return cloned;
};
return util; return util;
}; };

View File

@@ -17,7 +17,8 @@ jasmineRequire.HtmlReporter = function(j$) {
failureCount = 0, failureCount = 0,
pendingSpecCount = 0, pendingSpecCount = 0,
htmlReporterMain, htmlReporterMain,
symbols; symbols,
failedSuites = [];
this.initialize = function() { this.initialize = function() {
clearPrior(); clearPrior();
@@ -54,6 +55,10 @@ jasmineRequire.HtmlReporter = function(j$) {
}; };
this.suiteDone = function(result) { this.suiteDone = function(result) {
if (result.failedExpectations && result.failedExpectations.length > 0) {
failedSuites.push(result);
}
if (currentParent == topResults) { if (currentParent == topResults) {
return; return;
} }
@@ -149,6 +154,15 @@ jasmineRequire.HtmlReporter = function(j$) {
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage)); alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage));
for(i = 0; i < failedSuites.length; i++) {
var failedSuite = failedSuites[i];
for(var j = 0; j < failedSuite.failedExpectations.length; j++) {
var errorBarMessage = 'AfterAll ' + failedSuite.failedExpectations[j].message;
var errorBarClassName = 'bar errored';
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessage));
}
}
var results = find('.results'); var results = find('.results');
results.appendChild(summary); results.appendChild(summary);

View File

@@ -194,6 +194,10 @@ body {
background-color: $neutral-color; background-color: $neutral-color;
} }
&.errored {
background-color: $failing-color;
}
&.menu { &.menu {
background-color: #fff; background-color: #fff;
color: $faint-text-color; color: $faint-text-color;