1 /**
  2  * Internal representation of a Jasmine specification, or test.
  3  * @private
  4  * @constructs
  5  * @param {jasmine.Env} env
  6  * @param {jasmine.Suite} suite
  7  * @param {String} description
  8  */
  9 jasmine.Spec = function(env, suite, description) {
 10   this.id = env.nextSpecId_++;
 11   this.env = env;
 12   this.suite = suite;
 13   this.description = description;
 14   this.queue = [];
 15   this.currentTimeout = 0;
 16   this.currentLatchFunction = undefined;
 17   this.finished = false;
 18   this.afterCallbacks = [];
 19   this.spies_ = [];
 20 
 21   this.results = new jasmine.NestedResults();
 22   this.results.description = description;
 23   this.runs = this.addToQueue;
 24 };
 25 
 26 jasmine.Spec.prototype.getFullName = function() {
 27   return this.suite.getFullName() + ' ' + this.description + '.';
 28 };
 29 
 30 jasmine.Spec.prototype.getResults = function() {
 31   return this.results;
 32 };
 33 
 34 jasmine.Spec.prototype.addToQueue = function(func) {
 35   var queuedFunction = new jasmine.QueuedFunction(this.env, func, this.currentTimeout, this.currentLatchFunction, this);
 36   this.queue.push(queuedFunction);
 37 
 38   if (this.queue.length > 1) {
 39     var previousQueuedFunction = this.queue[this.queue.length - 2];
 40     previousQueuedFunction.next = function() {
 41       queuedFunction.execute();
 42     };
 43   }
 44 
 45   this.resetTimeout();
 46   return this;
 47 };
 48 
 49 /**
 50  * @private
 51  * @deprecated
 52  */
 53 jasmine.Spec.prototype.expects_that = function(actual) {
 54   return this.expect(actual);
 55 };
 56 
 57 /**
 58  * @private
 59  * @deprecated
 60  */
 61 jasmine.Spec.prototype.expect = function(actual) {
 62   return new jasmine.Matchers(this.env, actual, this.results);
 63 };
 64 
 65 /**
 66  * @private
 67  * @deprecated
 68  */
 69 jasmine.Spec.prototype.waits = function(timeout) {
 70   this.currentTimeout = timeout;
 71   this.currentLatchFunction = undefined;
 72   return this;
 73 };
 74 
 75 /**
 76  * @private
 77  * @deprecated
 78  */
 79 jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, message) {
 80   this.currentTimeout = timeout;
 81   this.currentLatchFunction = latchFunction;
 82   this.currentLatchFunction.description = message;
 83   return this;
 84 };
 85 
 86 jasmine.Spec.prototype.resetTimeout = function() {
 87   this.currentTimeout = 0;
 88   this.currentLatchFunction = undefined;
 89 };
 90 
 91 jasmine.Spec.prototype.finishCallback = function() {
 92   if (this.env.reporter) {
 93     this.env.reporter.reportSpecResults(this);
 94   }
 95 };
 96 
 97 jasmine.Spec.prototype.finish = function() {
 98   this.safeExecuteAfters();
 99 
100   this.removeAllSpies();
101   this.finishCallback();
102   this.finished = true;
103 };
104 
105 jasmine.Spec.prototype.after = function(doAfter) {
106   this.afterCallbacks.unshift(doAfter);
107 };
108 
109 jasmine.Spec.prototype.execute = function() {
110   if (!this.env.specFilter(this)) {
111     this.results.skipped = true;
112     this.finishCallback();
113     this.finished = true;
114     return;
115   }
116 
117   this.env.currentSpec = this;
118   this.env.currentlyRunningTests = true;
119 
120   this.safeExecuteBefores();
121 
122   if (this.queue[0]) {
123     this.queue[0].execute();
124   } else {
125     this.finish();
126   }
127   this.env.currentlyRunningTests = false;
128 };
129 
130 jasmine.Spec.prototype.safeExecuteBefores = function() {
131   var befores = [];
132   for (var suite = this.suite; suite; suite = suite.parentSuite) {
133     if (suite.beforeEachFunction) befores.push(suite.beforeEachFunction);
134   }
135 
136   while (befores.length) {
137     this.safeExecuteBeforeOrAfter(befores.pop());
138   }
139 };
140 
141 jasmine.Spec.prototype.safeExecuteAfters = function() {
142   for (var suite = this.suite; suite; suite = suite.parentSuite) {
143     if (suite.afterEachFunction) this.safeExecuteBeforeOrAfter(suite.afterEachFunction);
144   }
145 };
146 
147 jasmine.Spec.prototype.safeExecuteBeforeOrAfter = function(func) {
148   try {
149     func.apply(this);
150   } catch (e) {
151     this.results.addResult(new jasmine.ExpectationResult(false, func.typeName + '() fail: ' + jasmine.util.formatException(e), null));
152   }
153 };
154 
155 jasmine.Spec.prototype.explodes = function() {
156   throw 'explodes function should not have been called';
157 };
158 
159 jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
160   if (obj == undefined) {
161     throw "spyOn could not find an object to spy upon for " + methodName + "()";
162   }
163 
164   if (!ignoreMethodDoesntExist && obj[methodName] === undefined) {
165     throw methodName + '() method does not exist';
166   }
167 
168   if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
169     throw new Error(methodName + ' has already been spied upon');
170   }
171 
172   var spyObj = jasmine.createSpy(methodName);
173 
174   this.spies_.push(spyObj);
175   spyObj.baseObj = obj;
176   spyObj.methodName = methodName;
177   spyObj.originalValue = obj[methodName];
178 
179   obj[methodName] = spyObj;
180 
181   return spyObj;
182 };
183 
184 jasmine.Spec.prototype.removeAllSpies = function() {
185   for (var i = 0; i < this.spies_.length; i++) {
186     var spy = this.spies_[i];
187     spy.baseObj[spy.methodName] = spy.originalValue;
188   }
189   this.spies_ = [];
190 };
191 
192