diff options
| author | Elliott Sprehn | 2010-10-19 13:17:49 -0700 |
|---|---|---|
| committer | Elliott Sprehn | 2010-10-20 14:38:00 -0700 |
| commit | 2115db69035c5993533fe7a3825e64cf6e9068ad (patch) | |
| tree | 796a502b28cd2bda8108a672eac0bf28c8bc21d4 /src/scenario/Scenario.js | |
| parent | 9c8b1800b90e14b643bab6ada8e96f8f850e84a6 (diff) | |
| download | angular.js-2115db69035c5993533fe7a3825e64cf6e9068ad.tar.bz2 | |
Lots of stability and performance updates and UI polish too.
Polish the Scenario Runner UI to include:
- a scroll pane that steps appear in since the list can be very long
- Collapse successful tests
- Show the line where the DSL statements were when there's an error (Chrome, Firefox)
Also:
- Remove lots angular.bind calls to reduce the amount of stack space used.
- Use setTimeout(...,0) to schedule the next future to let the browser breathe and have it repaint the steps. Also prevents overflowing the stack when an it() creates many futures.
- Run afterEach() handlers even if the it() block fails.
- Make navigateTo() take a function as the second argument so you can compute a URL in the future.
- Add wait() DSL statement to allow interactive debugging of tests.
- Allow custom jQuery selectors with element(...).query(fn) DSL statement.
Known Issues:
- All afterEach() handlers run even if a beforeEach() handler fails. Only after handlers for the same level as the failure and above should run.
Diffstat (limited to 'src/scenario/Scenario.js')
| -rw-r--r-- | src/scenario/Scenario.js | 97 |
1 files changed, 82 insertions, 15 deletions
diff --git a/src/scenario/Scenario.js b/src/scenario/Scenario.js index 979210e5..b1782cf2 100644 --- a/src/scenario/Scenario.js +++ b/src/scenario/Scenario.js @@ -32,9 +32,9 @@ angular.scenario.dsl = angular.scenario.dsl || function(name, fn) { var chain = angular.extend({}, result); angular.foreach(chain, function(value, name) { if (angular.isFunction(value)) { - chain[name] = angular.bind(self, function() { + chain[name] = function() { return executeStatement.call(self, value, arguments); - }); + }; } else { chain[name] = value; } @@ -63,17 +63,18 @@ angular.scenario.matcher = angular.scenario.matcher || function(name, fn) { if (this.inverse) { prefix += 'not '; } - this.addFuture(prefix + name + ' ' + angular.toJson(expected), - angular.bind(this, function(done) { - this.actual = this.future.value; - if ((this.inverse && fn.call(this, expected)) || - (!this.inverse && !fn.call(this, expected))) { - this.error = 'expected ' + angular.toJson(expected) + - ' but was ' + angular.toJson(this.actual); + 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(this.error); - }) - ); + done(error); + }); }; }; @@ -88,7 +89,10 @@ angular.scenario.matcher = angular.scenario.matcher || function(name, fn) { */ function asyncForEach(list, iterator, done) { var i = 0; - function loop(error) { + function loop(error, index) { + if (index && index > i) { + i = index; + } if (error || i >= list.length) { done(error); } else { @@ -102,7 +106,63 @@ function asyncForEach(list, iterator, done) { loop(); } +/** + * Formats an exception into a string with the stack trace, but limits + * to a specific line length. + * + * @param {Object} the exception to format, can be anything throwable + * @param {Number} 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. + */ +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} Either a wrapped jQuery/jqLite node or a DOMElement + * @param {String} Optional event type. + */ function browserTrigger(element, type) { if (element && !element.nodeName) element = element[0]; if (!element) return; @@ -136,10 +196,17 @@ function browserTrigger(element, type) { } } +/** + * 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. + */ _jQuery.fn.trigger = function(type) { return this.each(function(index, node) { browserTrigger(node, type); }); }; - - |
