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