1 /** 2 * Internal representation of a Jasmine specification, or test. 3 * 4 * @constructor 5 * @param {jasmine.Env} env 6 * @param {jasmine.Suite} suite 7 * @param {String} description 8 */ 9 jasmine.Spec = function(env, suite, description) { 10 if (!env) { 11 throw new Error('jasmine.Env() required'); 12 } 13 if (!suite) { 14 throw new Error('jasmine.Suite() required'); 15 } 16 var spec = this; 17 spec.id = env.nextSpecId ? env.nextSpecId() : null; 18 spec.env = env; 19 spec.suite = suite; 20 spec.description = description; 21 spec.queue = new jasmine.Queue(env); 22 23 spec.afterCallbacks = []; 24 spec.spies_ = []; 25 26 spec.results_ = new jasmine.NestedResults(); 27 spec.results_.description = description; 28 spec.matchersClass = null; 29 }; 30 31 jasmine.Spec.prototype.getFullName = function() { 32 return this.suite.getFullName() + ' ' + this.description + '.'; 33 }; 34 35 36 jasmine.Spec.prototype.results = function() { 37 return this.results_; 38 }; 39 40 jasmine.Spec.prototype.log = function() { 41 return this.results_.log(arguments); 42 }; 43 44 jasmine.Spec.prototype.runs = function (func) { 45 var block = new jasmine.Block(this.env, func, this); 46 this.addToQueue(block); 47 return this; 48 }; 49 50 jasmine.Spec.prototype.addToQueue = function (block) { 51 if (this.queue.isRunning()) { 52 this.queue.insertNext(block); 53 } else { 54 this.queue.add(block); 55 } 56 }; 57 58 /** 59 * @param {jasmine.ExpectationResult} result 60 */ 61 jasmine.Spec.prototype.addMatcherResult = function(result) { 62 this.results_.addResult(result); 63 }; 64 65 jasmine.Spec.prototype.expect = function(actual) { 66 var positive = new (this.getMatchersClass_())(this.env, actual, this); 67 positive.not = new (this.getMatchersClass_())(this.env, actual, this, true); 68 return positive; 69 }; 70 71 jasmine.Spec.prototype.waits = function(timeout) { 72 var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); 73 this.addToQueue(waitsFunc); 74 return this; 75 }; 76 77 jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, timeoutMessage) { 78 var waitsForFunc = new jasmine.WaitsForBlock(this.env, timeout, latchFunction, timeoutMessage, this); 79 this.addToQueue(waitsForFunc); 80 return this; 81 }; 82 83 jasmine.Spec.prototype.fail = function (e) { 84 var expectationResult = new jasmine.ExpectationResult({ 85 passed: false, 86 message: e ? jasmine.util.formatException(e) : 'Exception' 87 }); 88 this.results_.addResult(expectationResult); 89 }; 90 91 jasmine.Spec.prototype.getMatchersClass_ = function() { 92 return this.matchersClass || this.env.matchersClass; 93 }; 94 95 jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { 96 var parent = this.getMatchersClass_(); 97 var newMatchersClass = function() { 98 parent.apply(this, arguments); 99 }; 100 jasmine.util.inherit(newMatchersClass, parent); 101 jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); 102 this.matchersClass = newMatchersClass; 103 }; 104 105 jasmine.Spec.prototype.finishCallback = function() { 106 this.env.reporter.reportSpecResults(this); 107 }; 108 109 jasmine.Spec.prototype.finish = function(onComplete) { 110 this.removeAllSpies(); 111 this.finishCallback(); 112 if (onComplete) { 113 onComplete(); 114 } 115 }; 116 117 jasmine.Spec.prototype.after = function(doAfter) { 118 if (this.queue.isRunning()) { 119 this.queue.add(new jasmine.Block(this.env, doAfter, this)); 120 } else { 121 this.afterCallbacks.unshift(doAfter); 122 } 123 }; 124 125 jasmine.Spec.prototype.execute = function(onComplete) { 126 var spec = this; 127 if (!spec.env.specFilter(spec)) { 128 spec.results_.skipped = true; 129 spec.finish(onComplete); 130 return; 131 } 132 this.env.reporter.log('>> Jasmine Running ' + this.suite.description + ' ' + this.description + '...'); 133 134 spec.env.currentSpec = spec; 135 136 spec.addBeforesAndAftersToQueue(); 137 138 spec.queue.start(function () { 139 spec.finish(onComplete); 140 }); 141 }; 142 143 jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { 144 var runner = this.env.currentRunner(); 145 var i; 146 147 for (var suite = this.suite; suite; suite = suite.parentSuite) { 148 for (i = 0; i < suite.before_.length; i++) { 149 this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this)); 150 } 151 } 152 for (i = 0; i < runner.before_.length; i++) { 153 this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); 154 } 155 for (i = 0; i < this.afterCallbacks.length; i++) { 156 this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); 157 } 158 for (suite = this.suite; suite; suite = suite.parentSuite) { 159 for (i = 0; i < suite.after_.length; i++) { 160 this.queue.add(new jasmine.Block(this.env, suite.after_[i], this)); 161 } 162 } 163 for (i = 0; i < runner.after_.length; i++) { 164 this.queue.add(new jasmine.Block(this.env, runner.after_[i], this)); 165 } 166 }; 167 168 jasmine.Spec.prototype.explodes = function() { 169 throw 'explodes function should not have been called'; 170 }; 171 172 jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { 173 if (obj == jasmine.undefined) { 174 throw "spyOn could not find an object to spy upon for " + methodName + "()"; 175 } 176 177 if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) { 178 throw methodName + '() method does not exist'; 179 } 180 181 if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { 182 throw new Error(methodName + ' has already been spied upon'); 183 } 184 185 var spyObj = jasmine.createSpy(methodName); 186 187 this.spies_.push(spyObj); 188 spyObj.baseObj = obj; 189 spyObj.methodName = methodName; 190 spyObj.originalValue = obj[methodName]; 191 192 obj[methodName] = spyObj; 193 194 return spyObj; 195 }; 196 197 jasmine.Spec.prototype.removeAllSpies = function() { 198 for (var i = 0; i < this.spies_.length; i++) { 199 var spy = this.spies_[i]; 200 spy.baseObj[spy.methodName] = spy.originalValue; 201 } 202 this.spies_ = []; 203 }; 204 205