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:
292
src/core/Env.js
292
src/core/Env.js
@@ -14,11 +14,19 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler(), new j$.MockDate(global));
|
||||
|
||||
var runnableLookupTable = {};
|
||||
|
||||
var spies = [];
|
||||
var runnableResources = {};
|
||||
|
||||
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([
|
||||
'jasmineStarted',
|
||||
@@ -33,11 +41,21 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
return true;
|
||||
};
|
||||
|
||||
var equalityTesters = [];
|
||||
|
||||
var customEqualityTesters = [];
|
||||
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);
|
||||
@@ -55,7 +73,8 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
var expectationFactory = function(actual, spec) {
|
||||
return j$.Expectation.Factory({
|
||||
util: j$.matchersUtil,
|
||||
customEqualityTesters: customEqualityTesters,
|
||||
customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
|
||||
customMatchers: runnableResources[spec.id].customMatchers,
|
||||
actual: actual,
|
||||
addExpectationResult: addExpectationResult
|
||||
});
|
||||
@@ -65,30 +84,44 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
}
|
||||
};
|
||||
|
||||
var specStarted = function(spec) {
|
||||
currentSpec = spec;
|
||||
reporter.specStarted(spec.result);
|
||||
var defaultResourcesForRunnable = function(id, parentRunnableId) {
|
||||
var resources = {spies: [], customEqualityTesters: [], customMatchers: {}};
|
||||
|
||||
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() {
|
||||
var befores = [];
|
||||
var befores = [],
|
||||
afters = [],
|
||||
beforeAlls = [],
|
||||
afterAlls = [];
|
||||
|
||||
while(suite) {
|
||||
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);
|
||||
|
||||
if (runnablesExplictlySet()) {
|
||||
beforeAlls = beforeAlls.concat(suite.beforeAllFns);
|
||||
afterAlls = afterAlls.concat(suite.afterAllFns);
|
||||
}
|
||||
|
||||
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(),
|
||||
description: 'Jasmine__TopLevel__Suite',
|
||||
queueRunner: queueRunnerFactory,
|
||||
resultCallback: function() {} // TODO - hook this up
|
||||
resultCallback: function(attrs) {
|
||||
reporter.suiteDone(attrs);
|
||||
}
|
||||
});
|
||||
runnableLookupTable[topSuite.id] = topSuite;
|
||||
currentSuite = topSuite;
|
||||
defaultResourcesForRunnable(topSuite.id);
|
||||
currentDeclarationSuite = topSuite;
|
||||
|
||||
this.topSuite = function() {
|
||||
return topSuite;
|
||||
};
|
||||
|
||||
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 = [];
|
||||
for(var i = 0; i < runnablesToRun.length; 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({
|
||||
totalSpecsDefined: totalSpecsDefined
|
||||
});
|
||||
|
||||
queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
|
||||
queueRunnerFactory({queueableFns: allFns, onComplete: reporter.jasmineDone});
|
||||
};
|
||||
|
||||
this.addReporter = function(reporterToAdd) {
|
||||
reporter.addReporter(reporterToAdd);
|
||||
};
|
||||
|
||||
this.addMatchers = function(matchersToAdd) {
|
||||
j$.Expectation.addMatchers(matchersToAdd);
|
||||
};
|
||||
|
||||
this.spyOn = function(obj, methodName) {
|
||||
if (j$.util.isUndefined(obj)) {
|
||||
throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
|
||||
var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
|
||||
if(!currentRunnable()) {
|
||||
throw new Error('Spies must be created in a before function or a spec');
|
||||
}
|
||||
return runnableResources[currentRunnable().id].spies;
|
||||
}});
|
||||
|
||||
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]);
|
||||
|
||||
spies.push({
|
||||
spy: spy,
|
||||
baseObj: obj,
|
||||
methodName: methodName,
|
||||
originalValue: obj[methodName]
|
||||
});
|
||||
|
||||
obj[methodName] = spy;
|
||||
|
||||
return spy;
|
||||
this.spyOn = function() {
|
||||
return spyRegistry.spyOn.apply(spyRegistry, arguments);
|
||||
};
|
||||
|
||||
var suiteFactory = function(description) {
|
||||
@@ -212,40 +234,33 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
env: self,
|
||||
id: getNextSuiteId(),
|
||||
description: description,
|
||||
parentSuite: currentSuite,
|
||||
parentSuite: currentDeclarationSuite,
|
||||
queueRunner: queueRunnerFactory,
|
||||
onStart: suiteStarted,
|
||||
expectationFactory: expectationFactory,
|
||||
expectationResultFactory: expectationResultFactory,
|
||||
resultCallback: function(attrs) {
|
||||
if (!suite.disabled) {
|
||||
clearResourcesForRunnable(suite.id);
|
||||
currentlyExecutingSuites.pop();
|
||||
}
|
||||
reporter.suiteDone(attrs);
|
||||
}
|
||||
});
|
||||
|
||||
runnableLookupTable[suite.id] = suite;
|
||||
return suite;
|
||||
|
||||
function suiteStarted(suite) {
|
||||
currentlyExecutingSuites.push(suite);
|
||||
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
|
||||
reporter.suiteStarted(suite.result);
|
||||
}
|
||||
};
|
||||
|
||||
this.describe = function(description, specDefinitions) {
|
||||
var suite = suiteFactory(description);
|
||||
|
||||
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;
|
||||
|
||||
addSpecsToSuite(suite, specDefinitions);
|
||||
return suite;
|
||||
};
|
||||
|
||||
@@ -255,15 +270,75 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
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) {
|
||||
totalSpecsDefined++;
|
||||
|
||||
var spec = new j$.Spec({
|
||||
id: getNextSpecId(),
|
||||
beforeFns: beforeFns(suite),
|
||||
afterFns: afterFns(suite),
|
||||
beforeAndAfterFns: beforeAndAfterFns(suite, runnablesExplictlySetGetter),
|
||||
expectationFactory: expectationFactory,
|
||||
exceptionFormatter: exceptionFormatter,
|
||||
resultCallback: specResultCallback,
|
||||
getSpecName: function(spec) {
|
||||
return getSpecName(spec, suite);
|
||||
@@ -272,7 +347,8 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
description: description,
|
||||
expectationResultFactory: expectationResultFactory,
|
||||
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;
|
||||
@@ -283,30 +359,22 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
|
||||
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) {
|
||||
removeAllSpies();
|
||||
j$.Expectation.resetMatchers();
|
||||
customEqualityTesters = [];
|
||||
clearResourcesForRunnable(spec.id);
|
||||
currentSpec = null;
|
||||
reporter.specDone(result);
|
||||
}
|
||||
};
|
||||
|
||||
var suiteStarted = function(suite) {
|
||||
reporter.suiteStarted(suite.result);
|
||||
function specStarted(spec) {
|
||||
currentSpec = spec;
|
||||
defaultResourcesForRunnable(spec.id, suite.id);
|
||||
reporter.specStarted(spec.result);
|
||||
}
|
||||
};
|
||||
|
||||
this.it = function(description, fn) {
|
||||
var spec = specFactory(description, fn, currentSuite);
|
||||
currentSuite.addChild(spec);
|
||||
var spec = specFactory(description, fn, currentDeclarationSuite);
|
||||
currentDeclarationSuite.addChild(spec);
|
||||
return spec;
|
||||
};
|
||||
|
||||
@@ -316,20 +384,36 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
return spec;
|
||||
};
|
||||
|
||||
this.fit = function(description, fn ){
|
||||
var spec = this.it(description, fn);
|
||||
|
||||
focusedRunnables.push(spec.id);
|
||||
unfocusAncestor();
|
||||
return spec;
|
||||
};
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
return currentSpec.expect(actual);
|
||||
return currentRunnable().expect(actual);
|
||||
};
|
||||
|
||||
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) {
|
||||
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() {
|
||||
@@ -343,7 +427,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
message += error.message || error;
|
||||
}
|
||||
|
||||
currentSpec.addExpectationResult(false, {
|
||||
currentRunnable().addExpectationResult(false, {
|
||||
matcherName: '',
|
||||
passed: false,
|
||||
expected: '',
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
getJasmineRequireObj().Expectation = function() {
|
||||
|
||||
var matchers = {};
|
||||
|
||||
function Expectation(options) {
|
||||
this.util = options.util || { buildFailureMessage: function() {} };
|
||||
this.customEqualityTesters = options.customEqualityTesters || [];
|
||||
@@ -9,8 +7,9 @@ getJasmineRequireObj().Expectation = function() {
|
||||
this.addExpectationResult = options.addExpectationResult || function(){};
|
||||
this.isNot = options.isNot;
|
||||
|
||||
for (var matcherName in matchers) {
|
||||
this[matcherName] = matchers[matcherName];
|
||||
var customMatchers = options.customMatchers || {};
|
||||
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) {
|
||||
options = options || {};
|
||||
|
||||
|
||||
@@ -11,31 +11,31 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
}
|
||||
|
||||
function QueueRunner(attrs) {
|
||||
this.fns = attrs.fns || [];
|
||||
this.queueableFns = attrs.queueableFns || [];
|
||||
this.onComplete = attrs.onComplete || function() {};
|
||||
this.clearStack = attrs.clearStack || function(fn) {fn();};
|
||||
this.onException = attrs.onException || function() {};
|
||||
this.catchException = attrs.catchException || function() { return true; };
|
||||
this.enforceTimeout = attrs.enforceTimeout || function() { return false; };
|
||||
this.userContext = {};
|
||||
this.userContext = attrs.userContext || {};
|
||||
this.timer = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
|
||||
}
|
||||
|
||||
QueueRunner.prototype.execute = function() {
|
||||
this.run(this.fns, 0);
|
||||
this.run(this.queueableFns, 0);
|
||||
};
|
||||
|
||||
QueueRunner.prototype.run = function(fns, recursiveIndex) {
|
||||
var length = fns.length,
|
||||
self = this,
|
||||
iterativeIndex;
|
||||
QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
|
||||
var length = queueableFns.length,
|
||||
self = this,
|
||||
iterativeIndex;
|
||||
|
||||
|
||||
for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
|
||||
var fn = fns[iterativeIndex];
|
||||
if (fn.length > 0) {
|
||||
return attemptAsync(fn);
|
||||
var queueableFn = queueableFns[iterativeIndex];
|
||||
if (queueableFn.fn.length > 0) {
|
||||
return attemptAsync(queueableFn);
|
||||
} else {
|
||||
attemptSync(fn);
|
||||
attemptSync(queueableFn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,41 +45,46 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
this.clearStack(this.onComplete);
|
||||
}
|
||||
|
||||
function attemptSync(fn) {
|
||||
function attemptSync(queueableFn) {
|
||||
try {
|
||||
fn.call(self.userContext);
|
||||
queueableFn.fn.call(self.userContext);
|
||||
} catch (e) {
|
||||
handleException(e);
|
||||
handleException(e, queueableFn);
|
||||
}
|
||||
}
|
||||
|
||||
function attemptAsync(fn) {
|
||||
function attemptAsync(queueableFn) {
|
||||
var clearTimeout = function () {
|
||||
Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeoutId]]);
|
||||
},
|
||||
next = once(function () {
|
||||
clearTimeout(timeoutId);
|
||||
self.run(fns, iterativeIndex + 1);
|
||||
self.run(queueableFns, iterativeIndex + 1);
|
||||
}),
|
||||
timeoutId;
|
||||
|
||||
if (self.enforceTimeout()) {
|
||||
if (queueableFn.timeout) {
|
||||
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();
|
||||
}, j$.DEFAULT_TIMEOUT_INTERVAL]]);
|
||||
}, queueableFn.timeout()]]);
|
||||
}
|
||||
|
||||
try {
|
||||
fn.call(self.userContext, next);
|
||||
queueableFn.fn.call(self.userContext, next);
|
||||
} catch (e) {
|
||||
handleException(e);
|
||||
handleException(e, queueableFn);
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
function handleException(e) {
|
||||
function onException(e, queueableFn) {
|
||||
self.onException(e);
|
||||
}
|
||||
|
||||
function handleException(e, queueableFn) {
|
||||
onException(e, queueableFn);
|
||||
if (!self.catchException(e)) {
|
||||
//TODO: set a var when we catch an exception and
|
||||
//use a finally block to close the loop in a nice way..
|
||||
|
||||
@@ -4,17 +4,16 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
this.resultCallback = attrs.resultCallback || function() {};
|
||||
this.id = attrs.id;
|
||||
this.description = attrs.description || '';
|
||||
this.fn = attrs.fn;
|
||||
this.beforeFns = attrs.beforeFns || function() { return []; };
|
||||
this.afterFns = attrs.afterFns || function() { return []; };
|
||||
this.queueableFn = attrs.queueableFn;
|
||||
this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return {befores: [], afters: []}; };
|
||||
this.userContext = attrs.userContext || function() { return {}; };
|
||||
this.onStart = attrs.onStart || function() {};
|
||||
this.exceptionFormatter = attrs.exceptionFormatter || function() {};
|
||||
this.getSpecName = attrs.getSpecName || function() { return ''; };
|
||||
this.expectationResultFactory = attrs.expectationResultFactory || function() { };
|
||||
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
|
||||
this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
|
||||
|
||||
if (!this.fn) {
|
||||
if (!this.queueableFn.fn) {
|
||||
this.pend();
|
||||
}
|
||||
|
||||
@@ -50,30 +49,16 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
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({
|
||||
fns: allFns,
|
||||
onException: onException,
|
||||
queueableFns: allFns,
|
||||
onException: function() { self.onException.apply(self, arguments); },
|
||||
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() {
|
||||
self.result.status = self.status();
|
||||
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() {
|
||||
this.disabled = true;
|
||||
};
|
||||
@@ -108,6 +108,10 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
}
|
||||
};
|
||||
|
||||
Spec.prototype.isExecutable = function() {
|
||||
return !this.disabled && !this.markedPending;
|
||||
};
|
||||
|
||||
Spec.prototype.getFullName = function() {
|
||||
return this.getSpecName(this);
|
||||
};
|
||||
|
||||
45
src/core/SpyRegistry.js
Normal file
45
src/core/SpyRegistry.js
Normal 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;
|
||||
};
|
||||
@@ -7,9 +7,13 @@ getJasmineRequireObj().Suite = function() {
|
||||
this.onStart = attrs.onStart || function() {};
|
||||
this.resultCallback = attrs.resultCallback || function() {};
|
||||
this.clearStack = attrs.clearStack || function(fn) {fn();};
|
||||
this.expectationFactory = attrs.expectationFactory;
|
||||
this.expectationResultFactory = attrs.expectationResultFactory;
|
||||
|
||||
this.beforeFns = [];
|
||||
this.afterFns = [];
|
||||
this.beforeAllFns = [];
|
||||
this.afterAllFns = [];
|
||||
this.queueRunner = attrs.queueRunner || function() {};
|
||||
this.disabled = false;
|
||||
|
||||
@@ -17,12 +21,16 @@ getJasmineRequireObj().Suite = function() {
|
||||
|
||||
this.result = {
|
||||
id: this.id,
|
||||
status: this.disabled ? 'disabled' : '',
|
||||
description: this.description,
|
||||
fullName: this.getFullName()
|
||||
fullName: this.getFullName(),
|
||||
failedExpectations: []
|
||||
};
|
||||
}
|
||||
|
||||
Suite.prototype.expect = function(actual) {
|
||||
return this.expectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Suite.prototype.getFullName = function() {
|
||||
var fullName = this.description;
|
||||
for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
|
||||
@@ -42,10 +50,18 @@ getJasmineRequireObj().Suite = function() {
|
||||
this.beforeFns.unshift(fn);
|
||||
};
|
||||
|
||||
Suite.prototype.beforeAll = function(fn) {
|
||||
this.beforeAllFns.push(fn);
|
||||
};
|
||||
|
||||
Suite.prototype.afterEach = function(fn) {
|
||||
this.afterFns.unshift(fn);
|
||||
};
|
||||
|
||||
Suite.prototype.afterAll = function(fn) {
|
||||
this.afterAllFns.push(fn);
|
||||
};
|
||||
|
||||
Suite.prototype.addChild = function(child) {
|
||||
this.children.push(child);
|
||||
};
|
||||
@@ -62,16 +78,25 @@ getJasmineRequireObj().Suite = function() {
|
||||
|
||||
var allFns = [];
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
allFns.push(wrapChildAsAsync(this.children[i]));
|
||||
if (this.isExecutable()) {
|
||||
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({
|
||||
fns: allFns,
|
||||
onComplete: complete
|
||||
queueableFns: allFns,
|
||||
onComplete: complete,
|
||||
userContext: this.sharedUserContext(),
|
||||
onException: function() { self.onException.apply(self, arguments); }
|
||||
});
|
||||
|
||||
function complete() {
|
||||
self.result.status = self.disabled ? 'disabled' : 'finished';
|
||||
self.resultCallback(self.result);
|
||||
|
||||
if (onComplete) {
|
||||
@@ -80,10 +105,82 @@ getJasmineRequireObj().Suite = function() {
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ getJasmineRequireObj = (function (jasmineGlobal) {
|
||||
j$.QueueRunner = jRequire.QueueRunner(j$);
|
||||
j$.ReportDispatcher = jRequire.ReportDispatcher();
|
||||
j$.Spec = jRequire.Spec(j$);
|
||||
j$.SpyRegistry = jRequire.SpyRegistry(j$);
|
||||
j$.SpyStrategy = jRequire.SpyStrategy();
|
||||
j$.Suite = jRequire.Suite();
|
||||
j$.Timer = jRequire.Timer();
|
||||
|
||||
@@ -24,6 +24,14 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
return env.afterEach(afterEachFunction);
|
||||
},
|
||||
|
||||
beforeAll: function(beforeAllFunction) {
|
||||
return env.beforeAll(beforeAllFunction);
|
||||
},
|
||||
|
||||
afterAll: function(afterAllFunction) {
|
||||
return env.afterAll(afterAllFunction);
|
||||
},
|
||||
|
||||
expect: function(actual) {
|
||||
return env.expect(actual);
|
||||
},
|
||||
|
||||
@@ -40,5 +40,20 @@ getJasmineRequireObj().util = function() {
|
||||
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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user