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.addMatcherResult = function(result) {
 66   this.results_.addResult(result);
 67 };
 68 
 69 jasmine.Spec.prototype.expect = function(actual) {
 70   return new (this.getMatchersClass_())(this.env, actual, this);
 71 };
 72 
 73 jasmine.Spec.prototype.waits = function(timeout) {
 74   var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
 75   this.addToQueue(waitsFunc);
 76   return this;
 77 };
 78 
 79 jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, timeoutMessage) {
 80   var waitsForFunc = new jasmine.WaitsForBlock(this.env, timeout, latchFunction, timeoutMessage, this);
 81   this.addToQueue(waitsForFunc);
 82   return this;
 83 };
 84 
 85 jasmine.Spec.prototype.fail = function (e) {
 86   var expectationResult = new jasmine.ExpectationResult({
 87     passed: false,
 88     message: e ? jasmine.util.formatException(e) : 'Exception'
 89   });
 90   this.results_.addResult(expectationResult);
 91 };
 92 
 93 jasmine.Spec.prototype.getMatchersClass_ = function() {
 94   return this.matchersClass || jasmine.Matchers;
 95 };
 96 
 97 jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
 98   var parent = this.getMatchersClass_();
 99   var newMatchersClass = function() {
100     parent.apply(this, arguments);
101   };
102   jasmine.util.inherit(newMatchersClass, parent);
103   for (var method in matchersPrototype) {
104     newMatchersClass.prototype[method] = matchersPrototype[method];
105   }
106   this.matchersClass = newMatchersClass;
107 };
108 
109 jasmine.Spec.prototype.finishCallback = function() {
110   this.env.reporter.reportSpecResults(this);
111 };
112 
113 jasmine.Spec.prototype.finish = function(onComplete) {
114   this.removeAllSpies();
115   this.finishCallback();
116   if (onComplete) {
117     onComplete();
118   }
119 };
120 
121 jasmine.Spec.prototype.after = function(doAfter, test) {
122 
123   if (this.queue.isRunning()) {
124     this.queue.add(new jasmine.Block(this.env, doAfter, this));
125   } else {
126     this.afterCallbacks.unshift(doAfter);
127   }
128 };
129 
130 jasmine.Spec.prototype.execute = function(onComplete) {
131   var spec = this;
132   if (!spec.env.specFilter(spec)) {
133     spec.results_.skipped = true;
134     spec.finish(onComplete);
135     return;
136   }
137   this.env.reporter.log('>> Jasmine Running ' + this.suite.description + ' ' + this.description + '...');
138 
139   spec.env.currentSpec = spec;
140 
141   spec.addBeforesAndAftersToQueue();
142 
143   spec.queue.start(function () {
144     spec.finish(onComplete);
145   });
146 };
147 
148 jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
149   var runner = this.env.currentRunner();
150   for (var suite = this.suite; suite; suite = suite.parentSuite) {
151     for (var i = 0; i < suite.before_.length; i++) {
152       this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
153     }
154   }
155   for (var i = 0; i < runner.before_.length; i++) {
156     this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
157   }
158   for (i = 0; i < this.afterCallbacks.length; i++) {
159     this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
160   }
161   for (suite = this.suite; suite; suite = suite.parentSuite) {
162     for (var i = 0; i < suite.after_.length; i++) {
163       this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
164     }
165   }
166   for (var i = 0; i < runner.after_.length; i++) {
167     this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
168   }
169 };
170 
171 jasmine.Spec.prototype.explodes = function() {
172   throw 'explodes function should not have been called';
173 };
174 
175 jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
176   if (obj == undefined) {
177     throw "spyOn could not find an object to spy upon for " + methodName + "()";
178   }
179 
180   if (!ignoreMethodDoesntExist && obj[methodName] === undefined) {
181     throw methodName + '() method does not exist';
182   }
183 
184   if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
185     throw new Error(methodName + ' has already been spied upon');
186   }
187 
188   var spyObj = jasmine.createSpy(methodName);
189 
190   this.spies_.push(spyObj);
191   spyObj.baseObj = obj;
192   spyObj.methodName = methodName;
193   spyObj.originalValue = obj[methodName];
194 
195   obj[methodName] = spyObj;
196 
197   return spyObj;
198 };
199 
200 jasmine.Spec.prototype.removeAllSpies = function() {
201   for (var i = 0; i < this.spies_.length; i++) {
202     var spy = this.spies_[i];
203     spy.baseObj[spy.methodName] = spy.originalValue;
204   }
205   this.spies_ = [];
206 };
207 
208