diff options
| author | Misko Hevery | 2010-10-19 15:34:58 -0700 |
|---|---|---|
| committer | Misko Hevery | 2010-10-19 15:56:53 -0700 |
| commit | 01c7abab35dbdee711c54875424b388f8631a3c0 (patch) | |
| tree | 00a4adee508a9e854881f7ecea5e779fb6d48a80 | |
| parent | e7e894a2e36e042be6d62af56b0f3126f4e4fc77 (diff) | |
| download | angular.js-01c7abab35dbdee711c54875424b388f8631a3c0.tar.bz2 | |
Fix browser triggering in scenario to always do native events.
- Also fixed angular.suffix for scenarios
- refactored click() to browserTrigger()
- Fixed Rakefile with CSS and jQuery
| -rw-r--r-- | Rakefile | 7 | ||||
| -rw-r--r-- | css/angular-scenario.css | 40 | ||||
| -rw-r--r-- | scenario/widgets-scenario.js | 17 | ||||
| -rw-r--r-- | scenario/widgets.html | 2 | ||||
| -rw-r--r-- | src/Angular.js | 4 | ||||
| -rw-r--r-- | src/jqLite.js | 11 | ||||
| -rw-r--r-- | src/scenario/Scenario.js | 49 | ||||
| -rw-r--r-- | src/scenario/SpecRunner.js | 34 | ||||
| -rw-r--r-- | src/scenario/angular.prefix | 1 | ||||
| -rw-r--r-- | src/scenario/angular.suffix | 13 | ||||
| -rw-r--r-- | src/scenario/bootstrap.js | 8 | ||||
| -rwxr-xr-x | test.sh | 4 | ||||
| -rw-r--r-- | test/BinderTest.js | 4 | ||||
| -rw-r--r-- | test/scenario/dslSpec.js | 42 | ||||
| -rw-r--r-- | test/testabilityPatch.js | 19 | ||||
| -rw-r--r-- | test/widgetsSpec.js | 16 |
16 files changed, 119 insertions, 152 deletions
@@ -53,7 +53,7 @@ end desc 'Compile Scenario' task :compile_scenario do - + deps = [ 'lib/jquery/jquery-1.4.2.js', 'src/scenario/angular.prefix', @@ -66,7 +66,7 @@ task :compile_scenario do File.open('angular-scenario.js', 'w') do |f| f.write(%x{#{concat}}) - f.write(gen_css('css/angular.css')) + f.write(gen_css('css/angular.css') + "\n") f.write(gen_css('css/angular-scenario.css')) end end @@ -234,7 +234,8 @@ def gen_css(cssFile, minify = false) end #escape for js - css.gsub! /'/, "\\'" + css.gsub! /\\/, "\\\\\\" + css.gsub! /'/, "\\\\'" css.gsub! /\n/, "\\n" return %Q{document.write('<style type="text/css">#{css}</style>');} diff --git a/css/angular-scenario.css b/css/angular-scenario.css index 2cf24b19..3462ecef 100644 --- a/css/angular-scenario.css +++ b/css/angular-scenario.css @@ -38,15 +38,15 @@ body { padding: 0.5em; font-size: 1.1em; } - + #status-legend { margin-top: 10px; margin-right: 10px; } -#header, +#header, #frame, -.test-info, +.test-info, .test-actions li { overflow: hidden; } @@ -67,10 +67,10 @@ body { #frame iframe { border: none; } - -.tests li, + +.tests li, .test-actions li, -.test-it li, +.test-it li, .test-it ol, .status-display { list-style-type: none; @@ -83,14 +83,14 @@ body { padding: 0; } -.test-info { +.test-info { margin-left: 1em; margin-top: 0.5em; border-radius: 8px 0 0 8px; -webkit-border-radius: 8px 0 0 8px; -moz-border-radius: 8px 0 0 8px; } - + .test-it ol { margin-left: 2.5em; } @@ -104,7 +104,7 @@ body { padding: 5px 10px; } -.timer-result, +.timer-result, .test-title { display: inline-block; margin: 0; @@ -129,7 +129,7 @@ body { } .test-actions .status-pending .test-title:before { - content: 'ยป '; + content: '\00bb\00A0'; } /** Colors */ @@ -150,7 +150,7 @@ body { #frame { border: 1px solid #BABAD1; } - + .test-describe .test-describe { border-left: 1px solid #BABAD1; border-right: 1px solid #BABAD1; @@ -168,29 +168,29 @@ body { .status-display .status-success, .status-success .test-info { - background-color: #B1D7A1; + background-color: #B1D7A1; } - + .status-display .status-failure, -.status-failure .test-info { - background-color: #FF8286; +.status-failure .test-info { + background-color: #FF8286; } .status-display .status-error, -.status-error .test-info { +.status-error .test-info { background-color: black; color: white; } -.test-actions .status-success .test-title { - color: #30B30A; +.test-actions .status-success .test-title { + color: #30B30A; } -.test-actions .status-failure .test-title { +.test-actions .status-failure .test-title { color: #DF0000; } -.test-actions .status-error .test-title { +.test-actions .status-error .test-title { color: black; } diff --git a/scenario/widgets-scenario.js b/scenario/widgets-scenario.js index befc481c..0cb189f7 100644 --- a/scenario/widgets-scenario.js +++ b/scenario/widgets-scenario.js @@ -1,17 +1,17 @@ describe('widgets', function() { it('should verify that basic widgets work', function(){ navigateTo('widgets.html'); - + using('#text-basic-box').input('text.basic').enter('Carlos'); expect(binding('text.basic')).toEqual('Carlos'); input('text.basic').enter('Carlos Santana'); expect(binding('text.basic')).not().toEqual('Carlos Boozer'); - + input('text.password').enter('secret'); expect(binding('text.password')).toEqual('secret'); - + expect(binding('text.hidden')).toEqual('hiddenValue'); - + expect(binding('gender')).toEqual('male'); input('gender').select('female'); expect(using('#gender-box').binding('gender')).toEqual('female'); @@ -19,10 +19,11 @@ describe('widgets', function() { expect(repeater('#repeater-row ul li').count()).toEqual(2); expect(repeater('#repeater-row ul li').row(1)).toEqual(['adam']); expect(repeater('#repeater-row ul li').column('name')).toEqual(['misko', 'adam']); - + select('select').option('B'); expect(binding('select')).toEqual('B'); - + + select('multiselect').options('A', 'C'); expect(binding('multiselect').fromJson()).toEqual(['A', 'C']); @@ -35,14 +36,14 @@ describe('widgets', function() { expect(binding('button').fromJson()).toEqual({'count': 3}); element('input[type="image"]').click(); expect(binding('button').fromJson()).toEqual({'count': 4}); - + /** * Custom value parser for futures. */ function checkboxParser(value) { return angular.fromJson(value.substring(value.indexOf('=')+1)); } - + input('checkbox.tea').check(); expect(binding('checkbox').parsedWith(checkboxParser)).toEqual({coffee: false, tea: false}); input('checkbox.coffee').check(); diff --git a/scenario/widgets.html b/scenario/widgets.html index 80a0a22f..8960f5f4 100644 --- a/scenario/widgets.html +++ b/scenario/widgets.html @@ -2,7 +2,7 @@ <html xmlns:ng="http://angularjs.org"> <head> <link rel="stylesheet" type="text/css" href="style.css"/> - <script type="text/javascript" src="../lib/jquery/jquery-1.4.2.js"></script> + <script type="text/javascript" src="../libs/jquery/jquery-1.4.2.js"></script> <script type="text/javascript" src="../src/angular-bootstrap.js" ng:autobind></script> </head> <body ng:init="$window.$scope = this"> diff --git a/src/Angular.js b/src/Angular.js index 8cacb9e4..b97c4226 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -146,12 +146,12 @@ function HTML(html) { if (msie) { nodeName = function(element) { - element = element[0] || element; + element = element.nodeName ? element : element[0]; return (element.scopeName && element.scopeName != 'HTML' ) ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName; }; } else { nodeName = function(element) { - return (element[0] || element).nodeName; + return element.nodeName ? element.nodeName : element[0].nodeName; }; } diff --git a/src/jqLite.js b/src/jqLite.js index a2ea286b..6c70f2a8 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -118,17 +118,6 @@ JQLite.prototype = { }); }, - trigger: function(type) { - if (msie) { - this[0].fireEvent('on' + type); - } else { - var evnt = document.createEvent('MouseEvents'), - element = this[0]; - evnt.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element); - element.dispatchEvent(evnt); - } - }, - replaceWith: function(replaceNode) { this[0].parentNode.replaceChild(jqLite(replaceNode)[0], this[0]); }, diff --git a/src/scenario/Scenario.js b/src/scenario/Scenario.js index e93f6b2e..ba206632 100644 --- a/src/scenario/Scenario.js +++ b/src/scenario/Scenario.js @@ -1,5 +1,5 @@ /** - * Setup file for the Scenario. + * Setup file for the Scenario. * Must be first in the compilation/bootstrap list. */ @@ -19,7 +19,7 @@ angular.scenario.ui = {}; * functions. * * @param {String} The name of the statement - * @param {Function} Factory function(application), return a function for + * @param {Function} Factory function(application), return a function for * the statement. */ angular.scenario.dsl = function(name, fn) { @@ -50,7 +50,7 @@ angular.scenario.dsl = function(name, fn) { /** * Defines a new matcher for use with the expects() statement. The value - * this.actual (like in Jasmine) is available in your matcher to compare + * 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. * @@ -83,7 +83,7 @@ angular.scenario.matcher = function(name, fn) { * * @param {Array} list to iterate over * @param {Function} Callback function(value, continueFunction) - * @param {Function} Callback function(error, result) called when iteration + * @param {Function} Callback function(error, result) called when iteration * finishes or an error occurs. */ function asyncForEach(list, iterator, done) { @@ -101,3 +101,44 @@ function asyncForEach(list, iterator, done) { } loop(); } + + +function browserTrigger(element, type) { + if (!element.nodeName) element = element[0]; + 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' + }[element.type] || 'click'; + } + if (lowercase(nodeName(element)) == 'option') { + element.parentNode.value = element.value; + element = element.parentNode; + type = 'change'; + } + if (msie) { + element.fireEvent('on' + type); + } else { + var evnt = document.createEvent('MouseEvents'); + evnt.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element); + element.dispatchEvent(evnt); + } +} + +_jQuery.fn.trigger = function(type) { + return this.each(function(index, node) { + browserTrigger(node, type); + }); +}; + + diff --git a/src/scenario/SpecRunner.js b/src/scenario/SpecRunner.js index d6cbdcdc..26fa9b91 100644 --- a/src/scenario/SpecRunner.js +++ b/src/scenario/SpecRunner.js @@ -21,7 +21,7 @@ angular.scenario.SpecRunner = function() { */ angular.scenario.SpecRunner.prototype.run = function(ui, spec, specDone) { var specUI = ui.addSpec(spec); - + try { spec.fn.call(this); } catch (e) { @@ -29,9 +29,9 @@ angular.scenario.SpecRunner.prototype.run = function(ui, spec, specDone) { specDone(); return; } - + asyncForEach( - this.futures, + this.futures, function(future, futureDone) { var stepUI = specUI.addStep(future.name); try { @@ -43,10 +43,10 @@ angular.scenario.SpecRunner.prototype.run = function(ui, spec, specDone) { stepUI.error(e); throw e; } - }, + }, function(e) { - specUI.finish(e); - specDone(); + specUI.finish(e); + specDone(); } ); }; @@ -89,29 +89,9 @@ angular.scenario.SpecRunner.prototype.addFutureAction = function(name, behavior) }; } - result.trigger = function(type) { - result.each(function(index, node) { - var element = $window.angular.element(node); - //TODO(esprehn): HACK!!! Something is broken in angular event dispatching - // and if the real jQuery is used we need to set the attribtue after too - if (angular.isDefined(element.selector)) { - if (type === 'click' && node.nodeName.toLowerCase() === 'input') { - element.attr('checked', !element.attr('checked')); - } - } - //TODO(esprehn): HACK!! See above comment. - element.trigger(type); - if (angular.isDefined(element.selector)) { - if (type === 'click' && node.nodeName.toLowerCase() === 'input') { - element.attr('checked', !element.attr('checked')); - } - } - }); - }; - return result; }); - + try { behavior.call(this, $window, $document, done); } catch(e) { diff --git a/src/scenario/angular.prefix b/src/scenario/angular.prefix index a1b4e151..d6660d61 100644 --- a/src/scenario/angular.prefix +++ b/src/scenario/angular.prefix @@ -22,3 +22,4 @@ * THE SOFTWARE. */ (function(window, document, previousOnLoad){ + var _jQuery = window.jQuery.noConflict(true);
\ No newline at end of file diff --git a/src/scenario/angular.suffix b/src/scenario/angular.suffix index 53d99dd2..c38f0ab5 100644 --- a/src/scenario/angular.suffix +++ b/src/scenario/angular.suffix @@ -4,22 +4,19 @@ try { if (previousOnLoad) previousOnLoad(); } catch(e) {} - jQuery(document.body).append( + _jQuery(document.body).append( '<div id="runner"></div>' + '<div id="frame"></div>' ); - var frame = jQuery('#frame'); - var runner = jQuery('#runner'); + var frame = _jQuery('#frame'); + var runner = _jQuery('#runner'); var application = new angular.scenario.Application(frame); var ui = new angular.scenario.ui.Html(runner); - $scenario.run(ui, application, function(error) { + $scenario.run(ui, application, angular.scenario.SpecRunner, function(error) { frame.remove(); if (error) { if (window.console) { - console.log(error); - if (error.stack) { - console.log(error.stack); - } + console.log(error.stack || error); } else { // Do something for IE alert(error); diff --git a/src/scenario/bootstrap.js b/src/scenario/bootstrap.js index 014c636d..4661bfb2 100644 --- a/src/scenario/bootstrap.js +++ b/src/scenario/bootstrap.js @@ -10,7 +10,7 @@ } } })(); - + function addScript(path) { document.write('<script type="text/javascript" src="' + prefix + path + '"></script>'); } @@ -46,6 +46,11 @@ addCSS("../../css/angular-scenario.css"); addScript("../../lib/jquery/jquery-1.4.2.js"); + document.write( + '<script type="text/javascript">' + + 'var _jQuery = jQuery.noConflict(true);' + + '</script>' + ); addScript("../angular-bootstrap.js"); addScript("Scenario.js"); @@ -61,7 +66,6 @@ // Create the runner (which also sets up the global API) document.write( '<script type="text/javascript">' + - 'var _jQuery = jQuery.noConflict(true);' + 'var $scenario = new angular.scenario.Runner(window);' + '</script>' ); @@ -3,5 +3,5 @@ if [[ $tests = "" ]]; then tests="all" fi -java -jar lib/jstestdriver/JsTestDriver.jar --tests "$tests" -#java -jar lib/jstestdriver/JsTestDriver.jar --tests "$tests" --config jsTestDriver-jquery.conf +#java -jar lib/jstestdriver/JsTestDriver.jar --tests "$tests" +java -jar lib/jstestdriver/JsTestDriver.jar --tests "$tests" --config jsTestDriver-jquery.conf diff --git a/test/BinderTest.js b/test/BinderTest.js index 5d72206d..daaaeffe 100644 --- a/test/BinderTest.js +++ b/test/BinderTest.js @@ -589,13 +589,13 @@ BinderTest.prototype.testItShouldSelectTheCorrectRadioBox = function() { var female = jqLite(c.node[0].childNodes[0]); var male = jqLite(c.node[0].childNodes[1]); - click(female); + browserTrigger(female); assertEquals("female", c.scope.sex); assertEquals(true, female[0].checked); assertEquals(false, male[0].checked); assertEquals("female", female.val()); - click(male); + browserTrigger(male); assertEquals("male", c.scope.sex); assertEquals(false, female[0].checked); assertEquals(true, male[0].checked); diff --git a/test/scenario/dslSpec.js b/test/scenario/dslSpec.js index a30fe165..dd489d86 100644 --- a/test/scenario/dslSpec.js +++ b/test/scenario/dslSpec.js @@ -10,24 +10,6 @@ AngularMock.prototype.reset = function() { this.log = []; }; -AngularMock.prototype.element = function(node) { - this.log.push('element(' + node.nodeName.toLowerCase() + ')'); - var mock = this; - return { - selector: '', - attr: function(name, value) { - mock.log.push('attr(' + name + (angular.isDefined(value) ? ',' + value : '') + ')'); - return _jQuery.fn.attr.apply(_jQuery(node), arguments); - }, - trigger: function(type) { - mock.log.push('element().trigger(' + type + ')'); - //TODO(esprehn): See the HACK!! in the SpecRunner. This avoids - // triggering the second part of the hack in tests - delete this.selector; - } - }; -}; - AngularMock.prototype.$browser = function() { this.log.push('$brower()'); return this; @@ -181,7 +163,7 @@ describe("angular.scenario.dsl", function() { $root.dsl.select('test').options('A', 'B'); expect(_jQuery('[name="test"]').val()).toEqual(['A','B']); }); - + it('should fail to select multiple options on non-multiple select', function() { doc.append('<select name="test"></select>'); $root.dsl.select('test').options('A', 'B'); @@ -198,7 +180,7 @@ describe("angular.scenario.dsl", function() { }); $root.dsl.element('a').click(); }); - + it('should get attribute', function() { doc.append('<div id="test" class="foo"></div>'); $root.dsl.element('#test').attr('class'); @@ -210,13 +192,13 @@ describe("angular.scenario.dsl", function() { $root.dsl.element('#test').attr('class', 'bam'); expect(doc.find('div').attr('class')).toEqual('bam'); }); - + it('should get val', function() { doc.append('<input value="bar">'); $root.dsl.element('input').val(); expect($root.futureResult).toEqual('bar'); }); - + it('should set val', function() { doc.append('<input value="bar">'); $root.dsl.element('input').val('baz'); @@ -259,7 +241,7 @@ describe("angular.scenario.dsl", function() { $root.dsl.binding('foo.bar'); expect($root.futureResult).toEqual('some value'); }); - + it('should select binding in template by name', function() { doc.append('<pre ng:bind-template="foo {{bar}} baz">foo some baz</pre>'); $root.dsl.binding('bar'); @@ -271,7 +253,7 @@ describe("angular.scenario.dsl", function() { expect($root.futureError).toMatch(/did not match/); }); }); - + describe('Using', function() { it('should prefix selector in $document.elements()', function() { var chain; @@ -281,8 +263,6 @@ describe("angular.scenario.dsl", function() { ); chain = $root.dsl.using('div#test2'); chain.input('test.input').enter('foo'); - expect($window.angular.log).toContain('element(input)'); - expect($window.angular.log).toContain('element().trigger(change)'); var inputs = _jQuery('input[name="test.input"]'); expect(inputs.first().val()).toEqual('something'); expect(inputs.last().val()).toEqual('foo'); @@ -294,8 +274,6 @@ describe("angular.scenario.dsl", function() { doc.append('<input name="test.input" value="something">'); var chain = $root.dsl.input('test.input'); chain.enter('foo'); - expect($window.angular.log).toContain('element(input)'); - expect($window.angular.log).toContain('element().trigger(change)'); expect(_jQuery('input[name="test.input"]').val()).toEqual('foo'); }); @@ -311,14 +289,10 @@ describe("angular.scenario.dsl", function() { attr('checked')).toBeTruthy(); var chain = $root.dsl.input('test.input'); chain.check(); - expect($window.angular.log).toContain('element(input)'); - expect($window.angular.log).toContain('element().trigger(click)'); expect(_jQuery('input[name="test.input"]'). attr('checked')).toBeFalsy(); $window.angular.reset(); chain.check(); - expect($window.angular.log).toContain('element(input)'); - expect($window.angular.log).toContain('element().trigger(click)'); expect(_jQuery('input[name="test.input"]'). attr('checked')).toBeTruthy(); }); @@ -342,8 +316,6 @@ describe("angular.scenario.dsl", function() { attr('checked')).toBeFalsy(); var chain = $root.dsl.input('test.input'); chain.select('foo'); - expect($window.angular.log).toContain('element(input)'); - expect($window.angular.log).toContain('element().trigger(click)'); expect(_jQuery('input[name="0@test.input"][value="bar"]'). attr('checked')).toBeFalsy(); expect(_jQuery('input[name="0@test.input"][value="foo"]'). @@ -356,6 +328,6 @@ describe("angular.scenario.dsl", function() { expect($root.futureError).toMatch(/did not match/); }); }); - + }); }); diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js index 59d8f4ac..247faa19 100644 --- a/test/testabilityPatch.js +++ b/test/testabilityPatch.js @@ -189,25 +189,6 @@ function assertThrows(error, fn){ log = noop; error = noop; -function click(element) { - element = jqLite(element); - var type = lowercase(element.attr('type')); - var name = lowercase(nodeName(element)); - if (msie) { - if (name == 'input') { - if (type == 'radio' || type == 'checkbox') { - element[0].checked = ! element[0].checked; - } - } - } - if (name == 'option') { - element.parent().val(element.val()); - JQLite.prototype.trigger.call(element.parent(), 'change'); - } else { - JQLite.prototype.trigger.call(element, 'click'); - } -} - function rethrow(e) { if(e) { throw e; diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index 31596a48..cc254eff 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -128,10 +128,10 @@ describe("widget", function(){ it('should support type="checkbox"', function(){ compile('<input type="checkBox" name="checkbox" checked ng:change="action = true"/>'); expect(scope.checkbox).toEqual(true); - click(element); + browserTrigger(element); expect(scope.checkbox).toEqual(false); expect(scope.action).toEqual(true); - click(element); + browserTrigger(element); expect(scope.checkbox).toEqual(true); }); @@ -151,7 +151,7 @@ describe("widget", function(){ expect(scope.state).toEqual("Worked"); expect(scope.$element[0].checked).toEqual(true); - click(scope.$element); + browserTrigger(scope.$element); expect(scope.state).toEqual("Failed"); expect(scope.$element[0].checked).toEqual(false); @@ -278,13 +278,13 @@ describe("widget", function(){ it('should call ng:change on button click', function(){ compile('<input type="button" value="Click Me" ng:change="clicked = true"/>'); - click(element); + browserTrigger(element); expect(scope.$get('clicked')).toEqual(true); }); it('should support button alias', function(){ compile('<button ng:change="clicked = true">Click Me</button>'); - click(element); + browserTrigger(element); expect(scope.$get('clicked')).toEqual(true); }); @@ -310,7 +310,7 @@ describe("widget", function(){ expect(b.checked).toEqual(true); expect(scope.clicked).not.toBeDefined(); - click(a); + browserTrigger(a); expect(scope.chose).toEqual('A'); expect(scope.clicked).toEqual(1); }); @@ -363,7 +363,7 @@ describe("widget", function(){ // childNodes[0] is repeater comment expect(scope.selection).toEqual(undefined); - click(element[0].childNodes[2]); + browserTrigger(element[0].childNodes[2], 'change'); expect(scope.selection).toEqual(1); scope.selection = 2; @@ -423,7 +423,7 @@ describe("widget", function(){ it('should report error on ng:change exception', function(){ compile('<button ng:change="a-2=x">click</button>'); - click(element); + browserTrigger(element); expect(element.hasClass('ng-exception')).toBeTruthy(); }); }); |
