aboutsummaryrefslogtreecommitdiffstats
path: root/src/scenario
diff options
context:
space:
mode:
authorMisko Hevery2012-03-23 14:03:24 -0700
committerMisko Hevery2012-03-28 11:16:35 -0700
commit2430f52bb97fa9d682e5f028c977c5bf94c5ec38 (patch)
treee7529b741d70199f36d52090b430510bad07f233 /src/scenario
parent944098a4e0f753f06b40c73ca3e79991cec6c2e2 (diff)
downloadangular.js-2430f52bb97fa9d682e5f028c977c5bf94c5ec38.tar.bz2
chore(module): move files around in preparation for more modules
Diffstat (limited to 'src/scenario')
-rw-r--r--src/scenario/Application.js102
-rw-r--r--src/scenario/Describe.js155
-rw-r--r--src/scenario/Future.js64
-rw-r--r--src/scenario/ObjectModel.js247
-rw-r--r--src/scenario/Runner.js227
-rw-r--r--src/scenario/Scenario.js417
-rw-r--r--src/scenario/SpecRunner.js145
-rw-r--r--src/scenario/angular-bootstrap.js60
-rw-r--r--src/scenario/angular.prefix7
-rw-r--r--src/scenario/angular.suffix22
-rw-r--r--src/scenario/dsl.js405
-rw-r--r--src/scenario/matchers.js45
-rw-r--r--src/scenario/output/Html.js171
-rw-r--r--src/scenario/output/Json.js10
-rw-r--r--src/scenario/output/Object.js8
-rw-r--r--src/scenario/output/Xml.js51
16 files changed, 0 insertions, 2136 deletions
diff --git a/src/scenario/Application.js b/src/scenario/Application.js
deleted file mode 100644
index d3a70569..00000000
--- a/src/scenario/Application.js
+++ /dev/null
@@ -1,102 +0,0 @@
-'use strict';
-
-/**
- * Represents the application currently being tested and abstracts usage
- * of iframes or separate windows.
- *
- * @param {Object} context jQuery wrapper around HTML context.
- */
-angular.scenario.Application = function(context) {
- this.context = context;
- context.append(
- '<h2>Current URL: <a href="about:blank">None</a></h2>' +
- '<div id="test-frames"></div>'
- );
-};
-
-/**
- * Gets the jQuery collection of frames. Don't use this directly because
- * frames may go stale.
- *
- * @private
- * @return {Object} jQuery collection
- */
-angular.scenario.Application.prototype.getFrame_ = function() {
- return this.context.find('#test-frames iframe:last');
-};
-
-/**
- * Gets the window of the test runner frame. Always favor executeAction()
- * instead of this method since it prevents you from getting a stale window.
- *
- * @private
- * @return {Object} the window of the frame
- */
-angular.scenario.Application.prototype.getWindow_ = function() {
- var contentWindow = this.getFrame_().prop('contentWindow');
- if (!contentWindow)
- throw 'Frame window is not accessible.';
- return contentWindow;
-};
-
-/**
- * Changes the location of the frame.
- *
- * @param {string} url The URL. If it begins with a # then only the
- * hash of the page is changed.
- * @param {function()} loadFn function($window, $document) Called when frame loads.
- * @param {function()} errorFn function(error) Called if any error when loading.
- */
-angular.scenario.Application.prototype.navigateTo = function(url, loadFn, errorFn) {
- var self = this;
- var frame = this.getFrame_();
- //TODO(esprehn): Refactor to use rethrow()
- errorFn = errorFn || function(e) { throw e; };
- if (url === 'about:blank') {
- errorFn('Sandbox Error: Navigating to about:blank is not allowed.');
- } else if (url.charAt(0) === '#') {
- url = frame.attr('src').split('#')[0] + url;
- frame.attr('src', url);
- this.executeAction(loadFn);
- } else {
- frame.remove();
- this.context.find('#test-frames').append('<iframe>');
- frame = this.getFrame_();
- frame.load(function() {
- frame.unbind();
- try {
- self.executeAction(loadFn);
- } catch (e) {
- errorFn(e);
- }
- }).attr('src', url);
- }
- this.context.find('> h2 a').attr('href', url).text(url);
-};
-
-/**
- * Executes a function in the context of the tested application. Will wait
- * for all pending angular xhr requests before executing.
- *
- * @param {function()} action The callback to execute. function($window, $document)
- * $document is a jQuery wrapped document.
- */
-angular.scenario.Application.prototype.executeAction = function(action) {
- var self = this;
- var $window = this.getWindow_();
- if (!$window.document) {
- throw 'Sandbox Error: Application document not accessible.';
- }
- if (!$window.angular) {
- return action.call(this, $window, _jQuery($window.document));
- }
- angularInit($window.document, function(element) {
- element = $window.angular.element(element);
- var $injector = element.inheritedData('$injector');
- $injector.invoke(function($browser){
- $browser.notifyWhenNoOutstandingRequests(function() {
- action.call(self, $window, _jQuery($window.document));
- });
- });
- });
-};
diff --git a/src/scenario/Describe.js b/src/scenario/Describe.js
deleted file mode 100644
index 4d52e9d5..00000000
--- a/src/scenario/Describe.js
+++ /dev/null
@@ -1,155 +0,0 @@
-'use strict';
-
-/**
- * The representation of define blocks. Don't used directly, instead use
- * define() in your tests.
- *
- * @param {string} descName Name of the block
- * @param {Object} parent describe or undefined if the root.
- */
-angular.scenario.Describe = function(descName, parent) {
- this.only = parent && parent.only;
- this.beforeEachFns = [];
- this.afterEachFns = [];
- this.its = [];
- this.children = [];
- this.name = descName;
- this.parent = parent;
- this.id = angular.scenario.Describe.id++;
-
- /**
- * Calls all before functions.
- */
- var beforeEachFns = this.beforeEachFns;
- this.setupBefore = function() {
- if (parent) parent.setupBefore.call(this);
- angular.forEach(beforeEachFns, function(fn) { fn.call(this); }, this);
- };
-
- /**
- * Calls all after functions.
- */
- var afterEachFns = this.afterEachFns;
- this.setupAfter = function() {
- angular.forEach(afterEachFns, function(fn) { fn.call(this); }, this);
- if (parent) parent.setupAfter.call(this);
- };
-};
-
-// Shared Unique ID generator for every describe block
-angular.scenario.Describe.id = 0;
-
-// Shared Unique ID generator for every it (spec)
-angular.scenario.Describe.specId = 0;
-
-/**
- * Defines a block to execute before each it or nested describe.
- *
- * @param {function()} body Body of the block.
- */
-angular.scenario.Describe.prototype.beforeEach = function(body) {
- this.beforeEachFns.push(body);
-};
-
-/**
- * Defines a block to execute after each it or nested describe.
- *
- * @param {function()} body Body of the block.
- */
-angular.scenario.Describe.prototype.afterEach = function(body) {
- this.afterEachFns.push(body);
-};
-
-/**
- * Creates a new describe block that's a child of this one.
- *
- * @param {string} name Name of the block. Appended to the parent block's name.
- * @param {function()} body Body of the block.
- */
-angular.scenario.Describe.prototype.describe = function(name, body) {
- var child = new angular.scenario.Describe(name, this);
- this.children.push(child);
- body.call(child);
-};
-
-/**
- * Same as describe() but makes ddescribe blocks the only to run.
- *
- * @param {string} name Name of the test.
- * @param {function()} body Body of the block.
- */
-angular.scenario.Describe.prototype.ddescribe = function(name, body) {
- var child = new angular.scenario.Describe(name, this);
- child.only = true;
- this.children.push(child);
- body.call(child);
-};
-
-/**
- * Use to disable a describe block.
- */
-angular.scenario.Describe.prototype.xdescribe = angular.noop;
-
-/**
- * Defines a test.
- *
- * @param {string} name Name of the test.
- * @param {function()} vody Body of the block.
- */
-angular.scenario.Describe.prototype.it = function(name, body) {
- this.its.push({
- id: angular.scenario.Describe.specId++,
- definition: this,
- only: this.only,
- name: name,
- before: this.setupBefore,
- body: body,
- after: this.setupAfter
- });
-};
-
-/**
- * Same as it() but makes iit tests the only test to run.
- *
- * @param {string} name Name of the test.
- * @param {function()} body Body of the block.
- */
-angular.scenario.Describe.prototype.iit = function(name, body) {
- this.it.apply(this, arguments);
- this.its[this.its.length-1].only = true;
-};
-
-/**
- * Use to disable a test block.
- */
-angular.scenario.Describe.prototype.xit = angular.noop;
-
-/**
- * Gets an array of functions representing all the tests (recursively).
- * that can be executed with SpecRunner's.
- *
- * @return {Array<Object>} Array of it blocks {
- * definition : Object // parent Describe
- * only: boolean
- * name: string
- * before: Function
- * body: Function
- * after: Function
- * }
- */
-angular.scenario.Describe.prototype.getSpecs = function() {
- var specs = arguments[0] || [];
- angular.forEach(this.children, function(child) {
- child.getSpecs(specs);
- });
- angular.forEach(this.its, function(it) {
- specs.push(it);
- });
- var only = [];
- angular.forEach(specs, function(it) {
- if (it.only) {
- only.push(it);
- }
- });
- return (only.length && only) || specs;
-};
diff --git a/src/scenario/Future.js b/src/scenario/Future.js
deleted file mode 100644
index 335dd2bb..00000000
--- a/src/scenario/Future.js
+++ /dev/null
@@ -1,64 +0,0 @@
-'use strict';
-
-/**
- * A future action in a spec.
- *
- * @param {string} name of the future action
- * @param {function()} future callback(error, result)
- * @param {function()} Optional. function that returns the file/line number.
- */
-angular.scenario.Future = function(name, behavior, line) {
- this.name = name;
- this.behavior = behavior;
- this.fulfilled = false;
- this.value = undefined;
- this.parser = angular.identity;
- this.line = line || function() { return ''; };
-};
-
-/**
- * Executes the behavior of the closure.
- *
- * @param {function()} doneFn Callback function(error, result)
- */
-angular.scenario.Future.prototype.execute = function(doneFn) {
- var self = this;
- this.behavior(function(error, result) {
- self.fulfilled = true;
- if (result) {
- try {
- result = self.parser(result);
- } catch(e) {
- error = e;
- }
- }
- self.value = error || result;
- doneFn(error, result);
- });
-};
-
-/**
- * Configures the future to convert it's final with a function fn(value)
- *
- * @param {function()} fn function(value) that returns the parsed value
- */
-angular.scenario.Future.prototype.parsedWith = function(fn) {
- this.parser = fn;
- return this;
-};
-
-/**
- * Configures the future to parse it's final value from JSON
- * into objects.
- */
-angular.scenario.Future.prototype.fromJson = function() {
- return this.parsedWith(angular.fromJson);
-};
-
-/**
- * Configures the future to convert it's final value from objects
- * into JSON.
- */
-angular.scenario.Future.prototype.toJson = function() {
- return this.parsedWith(angular.toJson);
-};
diff --git a/src/scenario/ObjectModel.js b/src/scenario/ObjectModel.js
deleted file mode 100644
index b4dad1a5..00000000
--- a/src/scenario/ObjectModel.js
+++ /dev/null
@@ -1,247 +0,0 @@
-'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;
-};
diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js
deleted file mode 100644
index 06ad3aa1..00000000
--- a/src/scenario/Runner.js
+++ /dev/null
@@ -1,227 +0,0 @@
-'use strict';
-
-/**
- * Runner for scenarios
- *
- * Has to be initialized before any test is loaded,
- * because it publishes the API into window (global space).
- */
-angular.scenario.Runner = function($window) {
- this.listeners = [];
- this.$window = $window;
- this.rootDescribe = new angular.scenario.Describe();
- this.currentDescribe = this.rootDescribe;
- this.api = {
- it: this.it,
- iit: this.iit,
- xit: angular.noop,
- describe: this.describe,
- ddescribe: this.ddescribe,
- xdescribe: angular.noop,
- beforeEach: this.beforeEach,
- afterEach: this.afterEach
- };
- angular.forEach(this.api, angular.bind(this, function(fn, key) {
- this.$window[key] = angular.bind(this, fn);
- }));
-};
-
-/**
- * Emits an event which notifies listeners and passes extra
- * arguments.
- *
- * @param {string} eventName Name of the event to fire.
- */
-angular.scenario.Runner.prototype.emit = function(eventName) {
- var self = this;
- var args = Array.prototype.slice.call(arguments, 1);
- eventName = eventName.toLowerCase();
- if (!this.listeners[eventName])
- return;
- angular.forEach(this.listeners[eventName], function(listener) {
- listener.apply(self, args);
- });
-};
-
-/**
- * Adds a listener for an event.
- *
- * @param {string} eventName The name of the event to add a handler for
- * @param {string} listener The fn(...) that takes the extra arguments from emit()
- */
-angular.scenario.Runner.prototype.on = function(eventName, listener) {
- eventName = eventName.toLowerCase();
- this.listeners[eventName] = this.listeners[eventName] || [];
- this.listeners[eventName].push(listener);
-};
-
-/**
- * Defines a describe block of a spec.
- *
- * @see Describe.js
- *
- * @param {string} name Name of the block
- * @param {function()} body Body of the block
- */
-angular.scenario.Runner.prototype.describe = function(name, body) {
- var self = this;
- this.currentDescribe.describe(name, function() {
- var parentDescribe = self.currentDescribe;
- self.currentDescribe = this;
- try {
- body.call(this);
- } finally {
- self.currentDescribe = parentDescribe;
- }
- });
-};
-
-/**
- * Same as describe, but makes ddescribe the only blocks to run.
- *
- * @see Describe.js
- *
- * @param {string} name Name of the block
- * @param {function()} body Body of the block
- */
-angular.scenario.Runner.prototype.ddescribe = function(name, body) {
- var self = this;
- this.currentDescribe.ddescribe(name, function() {
- var parentDescribe = self.currentDescribe;
- self.currentDescribe = this;
- try {
- body.call(this);
- } finally {
- self.currentDescribe = parentDescribe;
- }
- });
-};
-
-/**
- * Defines a test in a describe block of a spec.
- *
- * @see Describe.js
- *
- * @param {string} name Name of the block
- * @param {function()} body Body of the block
- */
-angular.scenario.Runner.prototype.it = function(name, body) {
- this.currentDescribe.it(name, body);
-};
-
-/**
- * Same as it, but makes iit tests the only tests to run.
- *
- * @see Describe.js
- *
- * @param {string} name Name of the block
- * @param {function()} body Body of the block
- */
-angular.scenario.Runner.prototype.iit = function(name, body) {
- this.currentDescribe.iit(name, body);
-};
-
-/**
- * Defines a function to be called before each it block in the describe
- * (and before all nested describes).
- *
- * @see Describe.js
- *
- * @param {function()} Callback to execute
- */
-angular.scenario.Runner.prototype.beforeEach = function(body) {
- this.currentDescribe.beforeEach(body);
-};
-
-/**
- * Defines a function to be called after each it block in the describe
- * (and before all nested describes).
- *
- * @see Describe.js
- *
- * @param {function()} Callback to execute
- */
-angular.scenario.Runner.prototype.afterEach = function(body) {
- this.currentDescribe.afterEach(body);
-};
-
-/**
- * Creates a new spec runner.
- *
- * @private
- * @param {Object} scope parent scope
- */
-angular.scenario.Runner.prototype.createSpecRunner_ = function(scope) {
- var child = scope.$new();
- var Cls = angular.scenario.SpecRunner;
-
- // Export all the methods to child scope manually as now we don't mess controllers with scopes
- // TODO(vojta): refactor scenario runner so that these objects are not tightly coupled as current
- for (var name in Cls.prototype)
- child[name] = angular.bind(child, Cls.prototype[name]);
-
- Cls.call(child);
- return child;
-};
-
-/**
- * Runs all the loaded tests with the specified runner class on the
- * provided application.
- *
- * @param {angular.scenario.Application} application App to remote control.
- */
-angular.scenario.Runner.prototype.run = function(application) {
- var self = this;
- var $root = angular.injector(['ng']).get('$rootScope');
- angular.extend($root, this);
- angular.forEach(angular.scenario.Runner.prototype, function(fn, name) {
- $root[name] = angular.bind(self, fn);
- });
- $root.application = application;
- $root.emit('RunnerBegin');
- asyncForEach(this.rootDescribe.getSpecs(), function(spec, specDone) {
- var dslCache = {};
- var runner = self.createSpecRunner_($root);
- angular.forEach(angular.scenario.dsl, function(fn, key) {
- dslCache[key] = fn.call($root);
- });
- angular.forEach(angular.scenario.dsl, function(fn, key) {
- self.$window[key] = function() {
- var line = callerFile(3);
- var scope = runner.$new();
-
- // Make the dsl accessible on the current chain
- scope.dsl = {};
- angular.forEach(dslCache, function(fn, key) {
- scope.dsl[key] = function() {
- return dslCache[key].apply(scope, arguments);
- };
- });
-
- // Make these methods work on the current chain
- scope.addFuture = function() {
- Array.prototype.push.call(arguments, line);
- return angular.scenario.SpecRunner.
- prototype.addFuture.apply(scope, arguments);
- };
- scope.addFutureAction = function() {
- Array.prototype.push.call(arguments, line);
- return angular.scenario.SpecRunner.
- prototype.addFutureAction.apply(scope, arguments);
- };
-
- return scope.dsl[key].apply(scope, arguments);
- };
- });
- runner.run(spec, function() {
- runner.$destroy();
- specDone.apply(this, arguments);
- });
- },
- function(error) {
- if (error) {
- self.emit('RunnerError', error);
- }
- self.emit('RunnerEnd');
- });
-};
diff --git a/src/scenario/Scenario.js b/src/scenario/Scenario.js
deleted file mode 100644
index cd3c335f..00000000
--- a/src/scenario/Scenario.js
+++ /dev/null
@@ -1,417 +0,0 @@
-'use strict';
-
-
-/**
- * Setup file for the Scenario.
- * Must be first in the compilation/bootstrap list.
- */
-
-// Public namespace
-angular.scenario = angular.scenario || {};
-
-/**
- * Defines a new output format.
- *
- * @param {string} name the name of the new output format
- * @param {function()} fn function(context, runner) that generates the output
- */
-angular.scenario.output = angular.scenario.output || function(name, fn) {
- angular.scenario.output[name] = fn;
-};
-
-/**
- * Defines a new DSL statement. If your factory function returns a Future
- * it's returned, otherwise the result is assumed to be a map of functions
- * for chaining. Chained functions are subject to the same rules.
- *
- * Note: All functions on the chain are bound to the chain scope so values
- * set on "this" in your statement function are available in the chained
- * functions.
- *
- * @param {string} name The name of the statement
- * @param {function()} fn Factory function(), return a function for
- * the statement.
- */
-angular.scenario.dsl = angular.scenario.dsl || function(name, fn) {
- angular.scenario.dsl[name] = function() {
- function executeStatement(statement, args) {
- var result = statement.apply(this, args);
- if (angular.isFunction(result) || result instanceof angular.scenario.Future)
- return result;
- var self = this;
- var chain = angular.extend({}, result);
- angular.forEach(chain, function(value, name) {
- if (angular.isFunction(value)) {
- chain[name] = function() {
- return executeStatement.call(self, value, arguments);
- };
- } else {
- chain[name] = value;
- }
- });
- return chain;
- }
- var statement = fn.apply(this, arguments);
- return function() {
- return executeStatement.call(this, statement, arguments);
- };
- };
-};
-
-/**
- * Defines a new matcher for use with the expects() statement. The value
- * this.actual (like in Jasmine) is available in your matcher to compare
- * against. Your function should return a boolean. The future is automatically
- * created for you.
- *
- * @param {string} name The name of the matcher
- * @param {function()} fn The matching function(expected).
- */
-angular.scenario.matcher = angular.scenario.matcher || function(name, fn) {
- angular.scenario.matcher[name] = function(expected) {
- var prefix = 'expect ' + this.future.name + ' ';
- if (this.inverse) {
- prefix += 'not ';
- }
- var self = this;
- this.addFuture(prefix + name + ' ' + angular.toJson(expected),
- function(done) {
- var error;
- self.actual = self.future.value;
- if ((self.inverse && fn.call(self, expected)) ||
- (!self.inverse && !fn.call(self, expected))) {
- error = 'expected ' + angular.toJson(expected) +
- ' but was ' + angular.toJson(self.actual);
- }
- done(error);
- });
- };
-};
-
-/**
- * Initialize the scenario runner and run !
- *
- * Access global window and document object
- * Access $runner through closure
- *
- * @param {Object=} config Config options
- */
-angular.scenario.setUpAndRun = function(config) {
- var href = window.location.href;
- var body = _jQuery(document.body);
- var output = [];
- var objModel = new angular.scenario.ObjectModel($runner);
-
- if (config && config.scenario_output) {
- output = config.scenario_output.split(',');
- }
-
- angular.forEach(angular.scenario.output, function(fn, name) {
- if (!output.length || indexOf(output,name) != -1) {
- var context = body.append('<div></div>').find('div:last');
- context.attr('id', name);
- fn.call({}, context, $runner, objModel);
- }
- });
-
- if (!/^http/.test(href) && !/^https/.test(href)) {
- body.append('<p id="system-error"></p>');
- body.find('#system-error').text(
- 'Scenario runner must be run using http or https. The protocol ' +
- href.split(':')[0] + ':// is not supported.'
- );
- return;
- }
-
- var appFrame = body.append('<div id="application"></div>').find('#application');
- var application = new angular.scenario.Application(appFrame);
-
- $runner.on('RunnerEnd', function() {
- appFrame.css('display', 'none');
- appFrame.find('iframe').attr('src', 'about:blank');
- });
-
- $runner.on('RunnerError', function(error) {
- if (window.console) {
- console.log(formatException(error));
- } else {
- // Do something for IE
- alert(error);
- }
- });
-
- $runner.run(application);
-};
-
-/**
- * Iterates through list with iterator function that must call the
- * continueFunction to continute iterating.
- *
- * @param {Array} list list to iterate over
- * @param {function()} iterator Callback function(value, continueFunction)
- * @param {function()} done Callback function(error, result) called when
- * iteration finishes or an error occurs.
- */
-function asyncForEach(list, iterator, done) {
- var i = 0;
- function loop(error, index) {
- if (index && index > i) {
- i = index;
- }
- if (error || i >= list.length) {
- done(error);
- } else {
- try {
- iterator(list[i++], loop);
- } catch (e) {
- done(e);
- }
- }
- }
- loop();
-}
-
-/**
- * Formats an exception into a string with the stack trace, but limits
- * to a specific line length.
- *
- * @param {Object} error The exception to format, can be anything throwable
- * @param {Number} maxStackLines Optional. max lines of the stack trace to include
- * default is 5.
- */
-function formatException(error, maxStackLines) {
- maxStackLines = maxStackLines || 5;
- var message = error.toString();
- if (error.stack) {
- var stack = error.stack.split('\n');
- if (stack[0].indexOf(message) === -1) {
- maxStackLines++;
- stack.unshift(error.message);
- }
- message = stack.slice(0, maxStackLines).join('\n');
- }
- return message;
-}
-
-/**
- * Returns a function that gets the file name and line number from a
- * location in the stack if available based on the call site.
- *
- * Note: this returns another function because accessing .stack is very
- * expensive in Chrome.
- *
- * @param {Number} offset Number of stack lines to skip
- */
-function callerFile(offset) {
- var error = new Error();
-
- return function() {
- var line = (error.stack || '').split('\n')[offset];
-
- // Clean up the stack trace line
- if (line) {
- if (line.indexOf('@') !== -1) {
- // Firefox
- line = line.substring(line.indexOf('@')+1);
- } else {
- // Chrome
- line = line.substring(line.indexOf('(')+1).replace(')', '');
- }
- }
-
- return line || '';
- };
-}
-
-/**
- * Triggers a browser event. Attempts to choose the right event if one is
- * not specified.
- *
- * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
- * @param {string} type Optional event type.
- * @param {Array.<string>=} keys Optional list of pressed keys
- * (valid values: 'alt', 'meta', 'shift', 'ctrl')
- */
-function browserTrigger(element, type, keys) {
- if (element && !element.nodeName) element = element[0];
- if (!element) return;
- if (!type) {
- type = {
- 'text': 'change',
- 'textarea': 'change',
- 'hidden': 'change',
- 'password': 'change',
- 'button': 'click',
- 'submit': 'click',
- 'reset': 'click',
- 'image': 'click',
- 'checkbox': 'click',
- 'radio': 'click',
- 'select-one': 'change',
- 'select-multiple': 'change'
- }[lowercase(element.type)] || 'click';
- }
- if (lowercase(nodeName_(element)) == 'option') {
- element.parentNode.value = element.value;
- element = element.parentNode;
- type = 'change';
- }
-
- keys = keys || [];
- function pressed(key) {
- return indexOf(keys, key) !== -1;
- }
-
- if (msie < 9) {
- switch(element.type) {
- case 'radio':
- case 'checkbox':
- element.checked = !element.checked;
- break;
- }
- // WTF!!! Error: Unspecified error.
- // Don't know why, but some elements when detached seem to be in inconsistent state and
- // calling .fireEvent() on them will result in very unhelpful error (Error: Unspecified error)
- // forcing the browser to compute the element position (by reading its CSS)
- // puts the element in consistent state.
- element.style.posLeft;
-
- // TODO(vojta): create event objects with pressed keys to get it working on IE<9
- var ret = element.fireEvent('on' + type);
- if (lowercase(element.type) == 'submit') {
- while(element) {
- if (lowercase(element.nodeName) == 'form') {
- element.fireEvent('onsubmit');
- break;
- }
- element = element.parentNode;
- }
- }
- return ret;
- } else {
- var evnt = document.createEvent('MouseEvents'),
- originalPreventDefault = evnt.preventDefault,
- iframe = _jQuery('#application iframe')[0],
- appWindow = iframe ? iframe.contentWindow : window,
- fakeProcessDefault = true,
- finalProcessDefault;
-
- // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
- appWindow.angular['ff-684208-preventDefault'] = false;
- evnt.preventDefault = function() {
- fakeProcessDefault = false;
- return originalPreventDefault.apply(evnt, arguments);
- };
-
- evnt.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, pressed('ctrl'), pressed('alt'),
- pressed('shift'), pressed('meta'), 0, element);
-
- element.dispatchEvent(evnt);
- finalProcessDefault = !(appWindow.angular['ff-684208-preventDefault'] || !fakeProcessDefault)
-
- delete appWindow.angular['ff-684208-preventDefault'];
-
- return finalProcessDefault;
- }
-}
-
-/**
- * Don't use the jQuery trigger method since it works incorrectly.
- *
- * jQuery notifies listeners and then changes the state of a checkbox and
- * does not create a real browser event. A real click changes the state of
- * the checkbox and then notifies listeners.
- *
- * To work around this we instead use our own handler that fires a real event.
- */
-(function(fn){
- var parentTrigger = fn.trigger;
- fn.trigger = function(type) {
- if (/(click|change|keydown|blur)/.test(type)) {
- var processDefaults = [];
- this.each(function(index, node) {
- processDefaults.push(browserTrigger(node, type));
- });
-
- // this is not compatible with jQuery - we return an array of returned values,
- // so that scenario runner know whether JS code has preventDefault() of the event or not...
- return processDefaults;
- }
- return parentTrigger.apply(this, arguments);
- };
-})(_jQuery.fn);
-
-/**
- * Finds all bindings with the substring match of name and returns an
- * array of their values.
- *
- * @param {string} bindExp The name to match
- * @return {Array.<string>} String of binding values
- */
-_jQuery.fn.bindings = function(windowJquery, bindExp) {
- var result = [], match,
- bindSelector = '.ng-binding:visible';
- if (angular.isString(bindExp)) {
- bindExp = bindExp.replace(/\s/g, '');
- match = function (actualExp) {
- if (actualExp) {
- actualExp = actualExp.replace(/\s/g, '');
- if (actualExp == bindExp) return true;
- if (actualExp.indexOf(bindExp) == 0) {
- return actualExp.charAt(bindExp.length) == '|';
- }
- }
- }
- } else if (bindExp) {
- match = function(actualExp) {
- return actualExp && bindExp.exec(actualExp);
- }
- } else {
- match = function(actualExp) {
- return !!actualExp;
- };
- }
- var selection = this.find(bindSelector);
- if (this.is(bindSelector)) {
- selection = selection.add(this);
- }
-
- function push(value) {
- if (value == undefined) {
- value = '';
- } else if (typeof value != 'string') {
- value = angular.toJson(value);
- }
- result.push('' + value);
- }
-
- selection.each(function() {
- var element = windowJquery(this),
- binding;
- if (binding = element.data('$binding')) {
- if (typeof binding == 'string') {
- if (match(binding)) {
- push(element.scope().$eval(binding));
- }
- } else {
- if (!angular.isArray(binding)) {
- binding = [binding];
- }
- for(var fns, j=0, jj=binding.length; j<jj; j++) {
- fns = binding[j];
- if (fns.parts) {
- fns = fns.parts;
- } else {
- fns = [fns];
- }
- for (var scope, fn, i = 0, ii = fns.length; i < ii; i++) {
- if(match((fn = fns[i]).exp)) {
- push(fn(scope = scope || element.scope()));
- }
- }
- }
- }
- }
- });
- return result;
-};
diff --git a/src/scenario/SpecRunner.js b/src/scenario/SpecRunner.js
deleted file mode 100644
index f4b9b0a7..00000000
--- a/src/scenario/SpecRunner.js
+++ /dev/null
@@ -1,145 +0,0 @@
-'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);
-};
diff --git a/src/scenario/angular-bootstrap.js b/src/scenario/angular-bootstrap.js
deleted file mode 100644
index a0012ff7..00000000
--- a/src/scenario/angular-bootstrap.js
+++ /dev/null
@@ -1,60 +0,0 @@
-'use strict';
-
-(function(previousOnLoad){
- var prefix = (function() {
- var filename = /(.*\/)angular-bootstrap.js(#(.*))?/;
- var scripts = document.getElementsByTagName("script");
- for(var j = 0; j < scripts.length; j++) {
- var src = scripts[j].src;
- if (src && src.match(filename)) {
- var parts = src.match(filename);
- return parts[1];
- }
- }
- })();
-
- function addScript(path) {
- document.write('<script type="text/javascript" src="' + prefix + path + '"></script>');
- }
-
- function addCSS(path) {
- document.write('<link rel="stylesheet" type="text/css" href="' + prefix + path + '"/>');
- }
-
- window.onload = function() {
- try {
- if (previousOnLoad) previousOnLoad();
- } catch(e) {}
- angular.scenario.setUpAndRun({});
- };
-
- addCSS("../../css/angular-scenario.css");
- addScript("../../lib/jquery/jquery.js");
- document.write(
- '<script type="text/javascript">' +
- 'var _jQuery = jQuery.noConflict(true);' +
- '</script>'
- );
- addScript("../angular-bootstrap.js");
-
- addScript("Scenario.js");
- addScript("Application.js");
- addScript("Describe.js");
- addScript("Future.js");
- addScript("Runner.js");
- addScript("SpecRunner.js");
- addScript("dsl.js");
- addScript("matchers.js");
- addScript("ObjectModel.js");
- addScript("output/Html.js");
- addScript("output/Json.js");
- addScript("output/Object.js");
- addScript("output/Xml.js");
-
- // Create the runner (which also sets up the global API)
- document.write(
- '<script type="text/javascript">' +
- ' var $runner = new angular.scenario.Runner(window);' +
- '</script>');
-
-})(window.onload);
diff --git a/src/scenario/angular.prefix b/src/scenario/angular.prefix
deleted file mode 100644
index 439ce371..00000000
--- a/src/scenario/angular.prefix
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * @license AngularJS v"NG_VERSION_FULL"
- * (c) 2010-2011 AngularJS http://angularjs.org
- * License: MIT
- */
-(function(window, document){
- var _jQuery = window.jQuery.noConflict(true);
diff --git a/src/scenario/angular.suffix b/src/scenario/angular.suffix
deleted file mode 100644
index 846dbe17..00000000
--- a/src/scenario/angular.suffix
+++ /dev/null
@@ -1,22 +0,0 @@
-bindJQuery();
-publishExternalAPI(angular);
-
-var $runner = new angular.scenario.Runner(window),
- scripts = document.getElementsByTagName('script'),
- script = scripts[scripts.length - 1],
- config = {};
-
-angular.forEach(script.attributes, function(attr) {
- var match = attr.name.match(/ng[:\-](.*)/);
- if (match) {
- config[match[1]] = attr.value || true;
- }
-});
-
-if (config.autotest) {
- JQLite(document).ready(function() {
- angular.scenario.setUpAndRun(config);
- });
-}
-})(window, document);
-
diff --git a/src/scenario/dsl.js b/src/scenario/dsl.js
deleted file mode 100644
index 8a1bccb1..00000000
--- a/src/scenario/dsl.js
+++ /dev/null
@@ -1,405 +0,0 @@
-'use strict';
-
-/**
- * Shared DSL statements that are useful to all scenarios.
- */
-
- /**
- * Usage:
- * pause() pauses until you call resume() in the console
- */
-angular.scenario.dsl('pause', function() {
- return function() {
- return this.addFuture('pausing for you to resume', function(done) {
- this.emit('InteractivePause', this.spec, this.step);
- this.$window.resume = function() { done(); };
- });
- };
-});
-
-/**
- * Usage:
- * sleep(seconds) pauses the test for specified number of seconds
- */
-angular.scenario.dsl('sleep', function() {
- return function(time) {
- return this.addFuture('sleep for ' + time + ' seconds', function(done) {
- this.$window.setTimeout(function() { done(null, time * 1000); }, time * 1000);
- });
- };
-});
-
-/**
- * Usage:
- * browser().navigateTo(url) Loads the url into the frame
- * browser().navigateTo(url, fn) where fn(url) is called and returns the URL to navigate to
- * browser().reload() refresh the page (reload the same URL)
- * browser().window.href() window.location.href
- * browser().window.path() window.location.pathname
- * browser().window.search() window.location.search
- * browser().window.hash() window.location.hash without # prefix
- * browser().location().url() see angular.module.ng.$location#url
- * browser().location().path() see angular.module.ng.$location#path
- * browser().location().search() see angular.module.ng.$location#search
- * browser().location().hash() see angular.module.ng.$location#hash
- */
-angular.scenario.dsl('browser', function() {
- var chain = {};
-
- chain.navigateTo = function(url, delegate) {
- var application = this.application;
- return this.addFuture("browser navigate to '" + url + "'", function(done) {
- if (delegate) {
- url = delegate.call(this, url);
- }
- application.navigateTo(url, function() {
- done(null, url);
- }, done);
- });
- };
-
- chain.reload = function() {
- var application = this.application;
- return this.addFutureAction('browser reload', function($window, $document, done) {
- var href = $window.location.href;
- application.navigateTo(href, function() {
- done(null, href);
- }, done);
- });
- };
-
- chain.window = function() {
- var api = {};
-
- api.href = function() {
- return this.addFutureAction('window.location.href', function($window, $document, done) {
- done(null, $window.location.href);
- });
- };
-
- api.path = function() {
- return this.addFutureAction('window.location.path', function($window, $document, done) {
- done(null, $window.location.pathname);
- });
- };
-
- api.search = function() {
- return this.addFutureAction('window.location.search', function($window, $document, done) {
- done(null, $window.location.search);
- });
- };
-
- api.hash = function() {
- return this.addFutureAction('window.location.hash', function($window, $document, done) {
- done(null, $window.location.hash.replace('#', ''));
- });
- };
-
- return api;
- };
-
- chain.location = function() {
- var api = {};
-
- api.url = function() {
- return this.addFutureAction('$location.url()', function($window, $document, done) {
- done(null, $window.angular.injector(['ng']).get('$location').url());
- });
- };
-
- api.path = function() {
- return this.addFutureAction('$location.path()', function($window, $document, done) {
- done(null, $window.angular.injector(['ng']).get('$location').path());
- });
- };
-
- api.search = function() {
- return this.addFutureAction('$location.search()', function($window, $document, done) {
- done(null, $window.angular.injector(['ng']).get('$location').search());
- });
- };
-
- api.hash = function() {
- return this.addFutureAction('$location.hash()', function($window, $document, done) {
- done(null, $window.angular.injector(['ng']).get('$location').hash());
- });
- };
-
- return api;
- };
-
- return function(time) {
- return chain;
- };
-});
-
-/**
- * Usage:
- * expect(future).{matcher} where matcher is one of the matchers defined
- * with angular.scenario.matcher
- *
- * ex. expect(binding("name")).toEqual("Elliott")
- */
-angular.scenario.dsl('expect', function() {
- var chain = angular.extend({}, angular.scenario.matcher);
-
- chain.not = function() {
- this.inverse = true;
- return chain;
- };
-
- return function(future) {
- this.future = future;
- return chain;
- };
-});
-
-/**
- * Usage:
- * using(selector, label) scopes the next DSL element selection
- *
- * ex.
- * using('#foo', "'Foo' text field").input('bar')
- */
-angular.scenario.dsl('using', function() {
- return function(selector, label) {
- this.selector = _jQuery.trim((this.selector||'') + ' ' + selector);
- if (angular.isString(label) && label.length) {
- this.label = label + ' ( ' + this.selector + ' )';
- } else {
- this.label = this.selector;
- }
- return this.dsl;
- };
-});
-
-/**
- * Usage:
- * binding(name) returns the value of the first matching binding
- */
-angular.scenario.dsl('binding', function() {
- return function(name) {
- return this.addFutureAction("select binding '" + name + "'", function($window, $document, done) {
- var values = $document.elements().bindings($window.angular.element, name);
- if (!values.length) {
- return done("Binding selector '" + name + "' did not match.");
- }
- done(null, values[0]);
- });
- };
-});
-
-/**
- * Usage:
- * input(name).enter(value) enters value in input with specified name
- * input(name).check() checks checkbox
- * input(name).select(value) selects the radio button with specified name/value
- * input(name).val() returns the value of the input.
- */
-angular.scenario.dsl('input', function() {
- var chain = {};
-
- chain.enter = function(value, event) {
- return this.addFutureAction("input '" + this.name + "' enter '" + value + "'", function($window, $document, done) {
- var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
- input.val(value);
- input.trigger(event || 'blur');
- done();
- });
- };
-
- chain.check = function() {
- return this.addFutureAction("checkbox '" + this.name + "' toggle", function($window, $document, done) {
- var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':checkbox');
- input.trigger('click');
- done();
- });
- };
-
- chain.select = function(value) {
- return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'", function($window, $document, done) {
- var input = $document.
- elements('[ng\\:model="$1"][value="$2"]', this.name, value).filter(':radio');
- input.trigger('click');
- done();
- });
- };
-
- chain.val = function() {
- return this.addFutureAction("return input val", function($window, $document, done) {
- var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
- done(null,input.val());
- });
- };
-
- return function(name) {
- this.name = name;
- return chain;
- };
-});
-
-
-/**
- * Usage:
- * repeater('#products table', 'Product List').count() number of rows
- * repeater('#products table', 'Product List').row(1) all bindings in row as an array
- * repeater('#products table', 'Product List').column('product.name') all values across all rows in an array
- */
-angular.scenario.dsl('repeater', function() {
- var chain = {};
-
- chain.count = function() {
- return this.addFutureAction("repeater '" + this.label + "' count", function($window, $document, done) {
- try {
- done(null, $document.elements().length);
- } catch (e) {
- done(null, 0);
- }
- });
- };
-
- chain.column = function(binding) {
- return this.addFutureAction("repeater '" + this.label + "' column '" + binding + "'", function($window, $document, done) {
- done(null, $document.elements().bindings($window.angular.element, binding));
- });
- };
-
- chain.row = function(index) {
- return this.addFutureAction("repeater '" + this.label + "' row '" + index + "'", function($window, $document, done) {
- var matches = $document.elements().slice(index, index + 1);
- if (!matches.length)
- return done('row ' + index + ' out of bounds');
- done(null, matches.bindings($window.angular.element));
- });
- };
-
- return function(selector, label) {
- this.dsl.using(selector, label);
- return chain;
- };
-});
-
-/**
- * Usage:
- * select(name).option('value') select one option
- * select(name).options('value1', 'value2', ...) select options from a multi select
- */
-angular.scenario.dsl('select', function() {
- var chain = {};
-
- chain.option = function(value) {
- return this.addFutureAction("select '" + this.name + "' option '" + value + "'", function($window, $document, done) {
- var select = $document.elements('select[ng\\:model="$1"]', this.name);
- var option = select.find('option[value="' + value + '"]');
- if (option.length) {
- select.val(value);
- } else {
- option = select.find('option:contains("' + value + '")');
- if (option.length) {
- select.val(option.val());
- }
- }
- select.trigger('change');
- done();
- });
- };
-
- chain.options = function() {
- var values = arguments;
- return this.addFutureAction("select '" + this.name + "' options '" + values + "'", function($window, $document, done) {
- var select = $document.elements('select[multiple][ng\\:model="$1"]', this.name);
- select.val(values);
- select.trigger('change');
- done();
- });
- };
-
- return function(name) {
- this.name = name;
- return chain;
- };
-});
-
-/**
- * Usage:
- * element(selector, label).count() get the number of elements that match selector
- * element(selector, label).click() clicks an element
- * element(selector, label).query(fn) executes fn(selectedElements, done)
- * element(selector, label).{method}() gets the value (as defined by jQuery, ex. val)
- * element(selector, label).{method}(value) sets the value (as defined by jQuery, ex. val)
- * element(selector, label).{method}(key) gets the value (as defined by jQuery, ex. attr)
- * element(selector, label).{method}(key, value) sets the value (as defined by jQuery, ex. attr)
- */
-angular.scenario.dsl('element', function() {
- var KEY_VALUE_METHODS = ['attr', 'css', 'prop'];
- var VALUE_METHODS = [
- 'val', 'text', 'html', 'height', 'innerHeight', 'outerHeight', 'width',
- 'innerWidth', 'outerWidth', 'position', 'scrollLeft', 'scrollTop', 'offset'
- ];
- var chain = {};
-
- chain.count = function() {
- return this.addFutureAction("element '" + this.label + "' count", function($window, $document, done) {
- try {
- done(null, $document.elements().length);
- } catch (e) {
- done(null, 0);
- }
- });
- };
-
- chain.click = function() {
- return this.addFutureAction("element '" + this.label + "' click", function($window, $document, done) {
- var elements = $document.elements();
- var href = elements.attr('href');
- var eventProcessDefault = elements.trigger('click')[0];
-
- if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
- this.application.navigateTo(href, function() {
- done();
- }, done);
- } else {
- done();
- }
- });
- };
-
- chain.query = function(fn) {
- return this.addFutureAction('element ' + this.label + ' custom query', function($window, $document, done) {
- fn.call(this, $document.elements(), done);
- });
- };
-
- angular.forEach(KEY_VALUE_METHODS, function(methodName) {
- chain[methodName] = function(name, value) {
- var args = arguments,
- futureName = (args.length == 1)
- ? "element '" + this.label + "' get " + methodName + " '" + name + "'"
- : "element '" + this.label + "' set " + methodName + " '" + name + "' to " + "'" + value + "'";
-
- return this.addFutureAction(futureName, function($window, $document, done) {
- var element = $document.elements();
- done(null, element[methodName].apply(element, args));
- });
- };
- });
-
- angular.forEach(VALUE_METHODS, function(methodName) {
- chain[methodName] = function(value) {
- var args = arguments,
- futureName = (args.length == 0)
- ? "element '" + this.label + "' " + methodName
- : futureName = "element '" + this.label + "' set " + methodName + " to '" + value + "'";
-
- return this.addFutureAction(futureName, function($window, $document, done) {
- var element = $document.elements();
- done(null, element[methodName].apply(element, args));
- });
- };
- });
-
- return function(selector, label) {
- this.dsl.using(selector, label);
- return chain;
- };
-});
diff --git a/src/scenario/matchers.js b/src/scenario/matchers.js
deleted file mode 100644
index 183dce46..00000000
--- a/src/scenario/matchers.js
+++ /dev/null
@@ -1,45 +0,0 @@
-'use strict';
-
-/**
- * Matchers for implementing specs. Follows the Jasmine spec conventions.
- */
-
-angular.scenario.matcher('toEqual', function(expected) {
- return angular.equals(this.actual, expected);
-});
-
-angular.scenario.matcher('toBe', function(expected) {
- return this.actual === expected;
-});
-
-angular.scenario.matcher('toBeDefined', function() {
- return angular.isDefined(this.actual);
-});
-
-angular.scenario.matcher('toBeTruthy', function() {
- return this.actual;
-});
-
-angular.scenario.matcher('toBeFalsy', function() {
- return !this.actual;
-});
-
-angular.scenario.matcher('toMatch', function(expected) {
- return new RegExp(expected).test(this.actual);
-});
-
-angular.scenario.matcher('toBeNull', function() {
- return this.actual === null;
-});
-
-angular.scenario.matcher('toContain', function(expected) {
- return includes(this.actual, expected);
-});
-
-angular.scenario.matcher('toBeLessThan', function(expected) {
- return this.actual < expected;
-});
-
-angular.scenario.matcher('toBeGreaterThan', function(expected) {
- return this.actual > expected;
-});
diff --git a/src/scenario/output/Html.js b/src/scenario/output/Html.js
deleted file mode 100644
index 326928d8..00000000
--- a/src/scenario/output/Html.js
+++ /dev/null
@@ -1,171 +0,0 @@
-'use strict';
-
-/**
- * User Interface for the Scenario Runner.
- *
- * TODO(esprehn): This should be refactored now that ObjectModel exists
- * to use angular bindings for the UI.
- */
-angular.scenario.output('html', function(context, runner, model) {
- var specUiMap = {},
- lastStepUiMap = {};
-
- context.append(
- '<div id="header">' +
- ' <h1><span class="angular">AngularJS</span>: Scenario Test Runner</h1>' +
- ' <ul id="status-legend" class="status-display">' +
- ' <li class="status-error">0 Errors</li>' +
- ' <li class="status-failure">0 Failures</li>' +
- ' <li class="status-success">0 Passed</li>' +
- ' </ul>' +
- '</div>' +
- '<div id="specs">' +
- ' <div class="test-children"></div>' +
- '</div>'
- );
-
- runner.on('InteractivePause', function(spec, step) {
- var ui = lastStepUiMap[spec.id];
- ui.find('.test-title').
- html('paused... <a href="javascript:resume()">resume</a> when ready.');
- });
-
- runner.on('SpecBegin', function(spec) {
- var ui = findContext(spec);
- ui.find('> .tests').append(
- '<li class="status-pending test-it"></li>'
- );
- ui = ui.find('> .tests li:last');
- ui.append(
- '<div class="test-info">' +
- ' <p class="test-title">' +
- ' <span class="timer-result"></span>' +
- ' <span class="test-name"></span>' +
- ' </p>' +
- '</div>' +
- '<div class="scrollpane">' +
- ' <ol class="test-actions"></ol>' +
- '</div>'
- );
- ui.find('> .test-info .test-name').text(spec.name);
- ui.find('> .test-info').click(function() {
- var scrollpane = ui.find('> .scrollpane');
- var actions = scrollpane.find('> .test-actions');
- var name = context.find('> .test-info .test-name');
- if (actions.find(':visible').length) {
- actions.hide();
- name.removeClass('open').addClass('closed');
- } else {
- actions.show();
- scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
- name.removeClass('closed').addClass('open');
- }
- });
-
- specUiMap[spec.id] = ui;
- });
-
- runner.on('SpecError', function(spec, error) {
- var ui = specUiMap[spec.id];
- ui.append('<pre></pre>');
- ui.find('> pre').text(formatException(error));
- });
-
- runner.on('SpecEnd', function(spec) {
- var ui = specUiMap[spec.id];
- spec = model.getSpec(spec.id);
- ui.removeClass('status-pending');
- ui.addClass('status-' + spec.status);
- ui.find("> .test-info .timer-result").text(spec.duration + "ms");
- if (spec.status === 'success') {
- ui.find('> .test-info .test-name').addClass('closed');
- ui.find('> .scrollpane .test-actions').hide();
- }
- updateTotals(spec.status);
- });
-
- runner.on('StepBegin', function(spec, step) {
- var ui = specUiMap[spec.id];
- spec = model.getSpec(spec.id);
- step = spec.getLastStep();
- ui.find('> .scrollpane .test-actions').append('<li class="status-pending"></li>');
- var stepUi = lastStepUiMap[spec.id] = ui.find('> .scrollpane .test-actions li:last');
- stepUi.append(
- '<div class="timer-result"></div>' +
- '<div class="test-title"></div>'
- );
- stepUi.find('> .test-title').text(step.name);
- var scrollpane = stepUi.parents('.scrollpane');
- scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
- });
-
- runner.on('StepFailure', function(spec, step, error) {
- var ui = lastStepUiMap[spec.id];
- addError(ui, step.line, error);
- });
-
- runner.on('StepError', function(spec, step, error) {
- var ui = lastStepUiMap[spec.id];
- addError(ui, step.line, error);
- });
-
- runner.on('StepEnd', function(spec, step) {
- var stepUi = lastStepUiMap[spec.id];
- spec = model.getSpec(spec.id);
- step = spec.getLastStep();
- stepUi.find('.timer-result').text(step.duration + 'ms');
- stepUi.removeClass('status-pending');
- stepUi.addClass('status-' + step.status);
- var scrollpane = specUiMap[spec.id].find('> .scrollpane');
- scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
- });
-
- /**
- * Finds the context of a spec block defined by the passed definition.
- *
- * @param {Object} The definition created by the Describe object.
- */
- function findContext(spec) {
- var currentContext = context.find('#specs');
- angular.forEach(model.getDefinitionPath(spec), function(defn) {
- var id = 'describe-' + defn.id;
- if (!context.find('#' + id).length) {
- currentContext.find('> .test-children').append(
- '<div class="test-describe" id="' + id + '">' +
- ' <h2></h2>' +
- ' <div class="test-children"></div>' +
- ' <ul class="tests"></ul>' +
- '</div>'
- );
- context.find('#' + id).find('> h2').text('describe: ' + defn.name);
- }
- currentContext = context.find('#' + id);
- });
- return context.find('#describe-' + spec.definition.id);
- }
-
- /**
- * Updates the test counter for the status.
- *
- * @param {string} the status.
- */
- function updateTotals(status) {
- var legend = context.find('#status-legend .status-' + status);
- var parts = legend.text().split(' ');
- var value = (parts[0] * 1) + 1;
- legend.text(value + ' ' + parts[1]);
- }
-
- /**
- * Add an error to a step.
- *
- * @param {Object} The JQuery wrapped context
- * @param {function()} fn() that should return the file/line number of the error
- * @param {Object} the error.
- */
- function addError(context, line, error) {
- context.find('.test-title').append('<pre></pre>');
- var message = _jQuery.trim(line() + '\n\n' + formatException(error));
- context.find('.test-title pre:last').text(message);
- }
-});
diff --git a/src/scenario/output/Json.js b/src/scenario/output/Json.js
deleted file mode 100644
index c024d923..00000000
--- a/src/scenario/output/Json.js
+++ /dev/null
@@ -1,10 +0,0 @@
-'use strict';
-
-/**
- * Generates JSON output into a context.
- */
-angular.scenario.output('json', function(context, runner, model) {
- model.on('RunnerEnd', function() {
- context.text(angular.toJson(model.value));
- });
-});
diff --git a/src/scenario/output/Object.js b/src/scenario/output/Object.js
deleted file mode 100644
index 621b816f..00000000
--- a/src/scenario/output/Object.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-/**
- * Creates a global value $result with the result of the runner.
- */
-angular.scenario.output('object', function(context, runner, model) {
- runner.$window.$result = model.value;
-});
diff --git a/src/scenario/output/Xml.js b/src/scenario/output/Xml.js
deleted file mode 100644
index 6cd27fe7..00000000
--- a/src/scenario/output/Xml.js
+++ /dev/null
@@ -1,51 +0,0 @@
-'use strict';
-
-/**
- * Generates XML output into a context.
- */
-angular.scenario.output('xml', function(context, runner, model) {
- var $ = function(args) {return new context.init(args);};
- model.on('RunnerEnd', function() {
- var scenario = $('<scenario></scenario>');
- context.append(scenario);
- serializeXml(scenario, model.value);
- });
-
- /**
- * Convert the tree into XML.
- *
- * @param {Object} context jQuery context to add the XML to.
- * @param {Object} tree node to serialize
- */
- function serializeXml(context, tree) {
- angular.forEach(tree.children, function(child) {
- var describeContext = $('<describe></describe>');
- describeContext.attr('id', child.id);
- describeContext.attr('name', child.name);
- context.append(describeContext);
- serializeXml(describeContext, child);
- });
- var its = $('<its></its>');
- context.append(its);
- angular.forEach(tree.specs, function(spec) {
- var it = $('<it></it>');
- it.attr('id', spec.id);
- it.attr('name', spec.name);
- it.attr('duration', spec.duration);
- it.attr('status', spec.status);
- its.append(it);
- angular.forEach(spec.steps, function(step) {
- var stepContext = $('<step></step>');
- stepContext.attr('name', step.name);
- stepContext.attr('duration', step.duration);
- stepContext.attr('status', step.status);
- it.append(stepContext);
- if (step.error) {
- var error = $('<error></error>');
- stepContext.append(error);
- error.text(formatException(stepContext.error));
- }
- });
- });
- }
-});