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
This commit is contained in:
Misko Hevery
2010-10-19 15:34:58 -07:00
parent e7e894a2e3
commit 01c7abab35
16 changed files with 119 additions and 152 deletions

View File

@@ -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>');}

View File

@@ -129,7 +129,7 @@ body {
}
.test-actions .status-pending .test-title:before {
content: '» ';
content: '\00bb\00A0';
}
/** Colors */

View File

@@ -23,6 +23,7 @@ describe('widgets', function() {
select('select').option('B');
expect(binding('select')).toEqual('B');
select('multiselect').options('A', 'C');
expect(binding('multiselect').fromJson()).toEqual(['A', 'C']);

View File

@@ -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">

View File

@@ -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;
};
}

View File

@@ -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]);
},

View File

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

View File

@@ -89,26 +89,6 @@ 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;
});

View File

@@ -22,3 +22,4 @@
* THE SOFTWARE.
*/
(function(window, document, previousOnLoad){
var _jQuery = window.jQuery.noConflict(true);

View File

@@ -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);

View File

@@ -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>'
);

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
@@ -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"]').

View File

@@ -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;

View File

@@ -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();
});
});