diff options
| author | Misko Hevery | 2012-03-23 14:03:24 -0700 |
|---|---|---|
| committer | Misko Hevery | 2012-03-28 11:16:35 -0700 |
| commit | 2430f52bb97fa9d682e5f028c977c5bf94c5ec38 (patch) | |
| tree | e7529b741d70199f36d52090b430510bad07f233 /src/ngScenario/SpecRunner.js | |
| parent | 944098a4e0f753f06b40c73ca3e79991cec6c2e2 (diff) | |
| download | angular.js-2430f52bb97fa9d682e5f028c977c5bf94c5ec38.tar.bz2 | |
chore(module): move files around in preparation for more modules
Diffstat (limited to 'src/ngScenario/SpecRunner.js')
| -rw-r--r-- | src/ngScenario/SpecRunner.js | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/ngScenario/SpecRunner.js b/src/ngScenario/SpecRunner.js new file mode 100644 index 00000000..f4b9b0a7 --- /dev/null +++ b/src/ngScenario/SpecRunner.js @@ -0,0 +1,145 @@ +'use strict'; + +/** + * This class is the "this" of the it/beforeEach/afterEach method. + * Responsibilities: + * - "this" for it/beforeEach/afterEach + * - keep state for single it/beforeEach/afterEach execution + * - keep track of all of the futures to execute + * - run single spec (execute each future) + */ +angular.scenario.SpecRunner = function() { + this.futures = []; + this.afterIndex = 0; +}; + +/** + * Executes a spec which is an it block with associated before/after functions + * based on the describe nesting. + * + * @param {Object} spec A spec object + * @param {function()} specDone function that is called when the spec finshes. Function(error, index) + */ +angular.scenario.SpecRunner.prototype.run = function(spec, specDone) { + var self = this; + this.spec = spec; + + this.emit('SpecBegin', spec); + + try { + spec.before.call(this); + spec.body.call(this); + this.afterIndex = this.futures.length; + spec.after.call(this); + } catch (e) { + this.emit('SpecError', spec, e); + this.emit('SpecEnd', spec); + specDone(); + return; + } + + var handleError = function(error, done) { + if (self.error) { + return done(); + } + self.error = true; + done(null, self.afterIndex); + }; + + asyncForEach( + this.futures, + function(future, futureDone) { + self.step = future; + self.emit('StepBegin', spec, future); + try { + future.execute(function(error) { + if (error) { + self.emit('StepFailure', spec, future, error); + self.emit('StepEnd', spec, future); + return handleError(error, futureDone); + } + self.emit('StepEnd', spec, future); + self.$window.setTimeout(function() { futureDone(); }, 0); + }); + } catch (e) { + self.emit('StepError', spec, future, e); + self.emit('StepEnd', spec, future); + handleError(e, futureDone); + } + }, + function(e) { + if (e) { + self.emit('SpecError', spec, e); + } + self.emit('SpecEnd', spec); + // Call done in a timeout so exceptions don't recursively + // call this function + self.$window.setTimeout(function() { specDone(); }, 0); + } + ); +}; + +/** + * Adds a new future action. + * + * Note: Do not pass line manually. It happens automatically. + * + * @param {string} name Name of the future + * @param {function()} behavior Behavior of the future + * @param {function()} line fn() that returns file/line number + */ +angular.scenario.SpecRunner.prototype.addFuture = function(name, behavior, line) { + var future = new angular.scenario.Future(name, angular.bind(this, behavior), line); + this.futures.push(future); + return future; +}; + +/** + * Adds a new future action to be executed on the application window. + * + * Note: Do not pass line manually. It happens automatically. + * + * @param {string} name Name of the future + * @param {function()} behavior Behavior of the future + * @param {function()} line fn() that returns file/line number + */ +angular.scenario.SpecRunner.prototype.addFutureAction = function(name, behavior, line) { + var self = this; + var NG = /\[ng\\\:/; + return this.addFuture(name, function(done) { + this.application.executeAction(function($window, $document) { + + //TODO(esprehn): Refactor this so it doesn't need to be in here. + $document.elements = function(selector) { + var args = Array.prototype.slice.call(arguments, 1); + selector = (self.selector || '') + ' ' + (selector || ''); + selector = _jQuery.trim(selector) || '*'; + angular.forEach(args, function(value, index) { + selector = selector.replace('$' + (index + 1), value); + }); + var result = $document.find(selector); + if (selector.match(NG)) { + result = result.add(selector.replace(NG, '[ng-'), $document); + } + if (!result.length) { + throw { + type: 'selector', + message: 'Selector ' + selector + ' did not match any elements.' + }; + } + + return result; + }; + + try { + behavior.call(self, $window, $document, done); + } catch(e) { + if (e.type && e.type === 'selector') { + done(e.message); + } else { + throw e; + } + } + }); + }, line); +}; |
