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/ObjectModel.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/ObjectModel.js')
| -rw-r--r-- | src/ngScenario/ObjectModel.js | 247 | 
1 files changed, 247 insertions, 0 deletions
| diff --git a/src/ngScenario/ObjectModel.js b/src/ngScenario/ObjectModel.js new file mode 100644 index 00000000..b4dad1a5 --- /dev/null +++ b/src/ngScenario/ObjectModel.js @@ -0,0 +1,247 @@ +'use strict'; + +/** + * Maintains an object tree from the runner events. + * + * @param {Object} runner The scenario Runner instance to connect to. + * + * TODO(esprehn): Every output type creates one of these, but we probably + *  want one global shared instance. Need to handle events better too + *  so the HTML output doesn't need to do spec model.getSpec(spec.id) + *  silliness. + * + * TODO(vojta) refactor on, emit methods (from all objects) - use inheritance + */ +angular.scenario.ObjectModel = function(runner) { +  var self = this; + +  this.specMap = {}; +  this.listeners = []; +  this.value = { +    name: '', +    children: {} +  }; + +  runner.on('SpecBegin', function(spec) { +    var block = self.value, +        definitions = []; + +    angular.forEach(self.getDefinitionPath(spec), function(def) { +      if (!block.children[def.name]) { +        block.children[def.name] = { +          id: def.id, +          name: def.name, +          children: {}, +          specs: {} +        }; +      } +      block = block.children[def.name]; +      definitions.push(def.name); +    }); + +    var it = self.specMap[spec.id] = +             block.specs[spec.name] = +             new angular.scenario.ObjectModel.Spec(spec.id, spec.name, definitions); + +    // forward the event +    self.emit('SpecBegin', it); +  }); + +  runner.on('SpecError', function(spec, error) { +    var it = self.getSpec(spec.id); +    it.status = 'error'; +    it.error = error; + +    // forward the event +    self.emit('SpecError', it, error); +  }); + +  runner.on('SpecEnd', function(spec) { +    var it = self.getSpec(spec.id); +    complete(it); + +    // forward the event +    self.emit('SpecEnd', it); +  }); + +  runner.on('StepBegin', function(spec, step) { +    var it = self.getSpec(spec.id); +    var step = new angular.scenario.ObjectModel.Step(step.name); +    it.steps.push(step); + +    // forward the event +    self.emit('StepBegin', it, step); +  }); + +  runner.on('StepEnd', function(spec, step) { +    var it = self.getSpec(spec.id); +    var step = it.getLastStep(); +    if (step.name !== step.name) +      throw 'Events fired in the wrong order. Step names don\'t match.'; +    complete(step); + +    // forward the event +    self.emit('StepEnd', it, step); +  }); + +  runner.on('StepFailure', function(spec, step, error) { +    var it = self.getSpec(spec.id), +        modelStep = it.getLastStep(); + +    modelStep.setErrorStatus('failure', error, step.line()); +    it.setStatusFromStep(modelStep); + +    // forward the event +    self.emit('StepFailure', it, modelStep, error); +  }); + +  runner.on('StepError', function(spec, step, error) { +    var it = self.getSpec(spec.id), +        modelStep = it.getLastStep(); + +    modelStep.setErrorStatus('error', error, step.line()); +    it.setStatusFromStep(modelStep); + +    // forward the event +    self.emit('StepError', it, modelStep, error); +  }); + +  runner.on('RunnerEnd', function() { +    self.emit('RunnerEnd'); +  }); + +  function complete(item) { +    item.endTime = new Date().getTime(); +    item.duration = item.endTime - item.startTime; +    item.status = item.status || 'success'; +  } +}; + +/** + * Adds a listener for an event. + * + * @param {string} eventName Name of the event to add a handler for + * @param {function()} listener Function that will be called when event is fired + */ +angular.scenario.ObjectModel.prototype.on = function(eventName, listener) { +  eventName = eventName.toLowerCase(); +  this.listeners[eventName] = this.listeners[eventName] || []; +  this.listeners[eventName].push(listener); +}; + +/** + * Emits an event which notifies listeners and passes extra + * arguments. + * + * @param {string} eventName Name of the event to fire. + */ +angular.scenario.ObjectModel.prototype.emit = function(eventName) { +  var self = this, +      args = Array.prototype.slice.call(arguments, 1), +      eventName = eventName.toLowerCase(); + +  if (this.listeners[eventName]) { +    angular.forEach(this.listeners[eventName], function(listener) { +      listener.apply(self, args); +    }); +  } +}; + +/** + * Computes the path of definition describe blocks that wrap around + * this spec. + * + * @param spec Spec to compute the path for. + * @return {Array<Describe>} The describe block path + */ +angular.scenario.ObjectModel.prototype.getDefinitionPath = function(spec) { +  var path = []; +  var currentDefinition = spec.definition; +  while (currentDefinition && currentDefinition.name) { +    path.unshift(currentDefinition); +    currentDefinition = currentDefinition.parent; +  } +  return path; +}; + +/** + * Gets a spec by id. + * + * @param {string} The id of the spec to get the object for. + * @return {Object} the Spec instance + */ +angular.scenario.ObjectModel.prototype.getSpec = function(id) { +  return this.specMap[id]; +}; + +/** + * A single it block. + * + * @param {string} id Id of the spec + * @param {string} name Name of the spec + * @param {Array<string>=} definitionNames List of all describe block names that wrap this spec + */ +angular.scenario.ObjectModel.Spec = function(id, name, definitionNames) { +  this.id = id; +  this.name = name; +  this.startTime = new Date().getTime(); +  this.steps = []; +  this.fullDefinitionName = (definitionNames || []).join(' '); +}; + +/** + * Adds a new step to the Spec. + * + * @param {string} step Name of the step (really name of the future) + * @return {Object} the added step + */ +angular.scenario.ObjectModel.Spec.prototype.addStep = function(name) { +  var step = new angular.scenario.ObjectModel.Step(name); +  this.steps.push(step); +  return step; +}; + +/** + * Gets the most recent step. + * + * @return {Object} the step + */ +angular.scenario.ObjectModel.Spec.prototype.getLastStep = function() { +  return this.steps[this.steps.length-1]; +}; + +/** + * Set status of the Spec from given Step + * + * @param {angular.scenario.ObjectModel.Step} step + */ +angular.scenario.ObjectModel.Spec.prototype.setStatusFromStep = function(step) { +  if (!this.status || step.status == 'error') { +    this.status = step.status; +    this.error = step.error; +    this.line = step.line; +  } +}; + +/** + * A single step inside a Spec. + * + * @param {string} step Name of the step + */ +angular.scenario.ObjectModel.Step = function(name) { +  this.name = name; +  this.startTime = new Date().getTime(); +}; + +/** + * Helper method for setting all error status related properties + * + * @param {string} status + * @param {string} error + * @param {string} line + */ +angular.scenario.ObjectModel.Step.prototype.setErrorStatus = function(status, error, line) { +  this.status = status; +  this.error = error; +  this.line = line; +}; | 
