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); +};  | 
