DIR : /home/kozerus/public_html/pn/uize/site-source/js/Uize/Test/Uize/Class/mChildObjectEventBindings.js

/home/kozerus/public_html/pn/uize/site-source/js/Uize/Test/Uize/Class

/*______________
|       ______  |   U I Z E    J A V A S C R I P T    F R A M E W O R K
|     /      /  |   ---------------------------------------------------
|    /    O /   |    MODULE : Uize.Test.Uize.Class.mChildObjectEventBindings Class
|   /    / /    |
|  /    / /  /| |    ONLINE : http://www.uize.com
| /____/ /__/_| | COPYRIGHT : (c)2014-2016 UIZE
|          /___ |   LICENSE : Available under MIT License or GNU General Public License
|_______________|             http://www.uize.com/license.html
*/

/* Module Meta Data
	type: Test
	importance: 3
	codeCompleteness: 100
	docCompleteness: 100
*/

/*?
	Introduction
		The =Uize.Test.Uize.Class.mChildObjectEventBindings= module defines a suite of unit tests for the =Uize.Class.mChildObjectEventBindings= mixin module.

		*DEVELOPERS:* `Ben Ilegbodu`, original code contributed by `Zazzle Inc.`
*/

Uize.module ({
	name:'Uize.Test.Uize.Class.mChildObjectEventBindings',
	superclass:'Uize.Test.Class',
	required:[
		'Uize.Comm',
		'Uize.Test.Widget',
		'Uize.Widget'
	],
	builder:function (_superclass) {
		'use strict';

		var
			_Uize = Uize,

			_eventBindingsFunctionName = 'eventBindings',

			_global = Uize.global(),
			_processArrayAsync = Uize.Comm.processArrayAsync,
			_defaultHandler = function(_event, _source) { _event.handler.call(this, _event, _source) },
			_defaultChangedHandler = function(_event, _source) { this.get(_event.name.slice(8)).call(this, _event, _source) },
			_originalWindow,

			_class = _superclass.subclass({
				moduleToTest:'Uize.Class.mChildObjectEventBindings'
			})
		;

		function _getMockDomNode(_name) { return Uize.Test.Widget.getMockDomNode(_name) }

		function _getTestWidgetClass(_eventBindings, _children) {
			return Uize.Widget.subclass (
				_Uize.copyInto(
					{
						mixins:Uize.Class.mChildObjectEventBindings,
						childObjectEventBindings:{
							declaration:_eventBindingsFunctionName,
							instanceProperty:'children',
							addedInstanceProperty:'addedChildren',
							additionalTypes:{
								dom:{
									namePrefix:'#',
									wireWhenever:'wired',
									getObjectMethod:'getNode',
									wireObjectMethod:'wireNode',
									defaultFireIf:'enabledInherited,!busyInherited'
								}
							}
						},
						omegastructor:function() {
							this.addChildren(Uize.lookup(_children, {widgetClass:Uize.Widget}));
						}
					},
					_Uize.pairUp(_eventBindingsFunctionName, _eventBindings)
				)
			);
		}

		function _getTestWidgetClassInstance(_eventBindings, _children, _nodes, _instanceProperties) {
			return _getTestWidgetClass(_eventBindings, _children)(
				Uize.copyInto(
					{
						nodeMap:Uize.map(
							Uize.lookup(_nodes),
							function(_value, _node) { return _getMockDomNode(_node) }
						)
					},
					_instanceProperties
				)
			);
		}

		function _generateTest(_title, _eventBindingsShorthand, _eventBindingsVerbose, _wiredEvents, _deferredChildren) {
			function _generateSyntaxTests(_isVerbose) {
				var _eventBindings = _isVerbose ? _eventBindingsVerbose : _eventBindingsShorthand;

				function _getSyntaxTestWidgetClass(_children) {
					return _getTestWidgetClass(_eventBindings, _children);
				}

				function _getSyntaxTestWidgetClassInstance(_children, _nodes, _instanceProperties) {
					return _getTestWidgetClassInstance(_eventBindings, _children, _nodes, _instanceProperties);
				}

				function _generateFireTests(_type) {
					var _fireEventMethodName = _type == 'node' ? 'triggerEvent' : 'fire';

					function _generateFireTest(_expectFunc, _instanceProperties) {
						return function(_continue) {
							if (!_wiredEvents || Uize.isEmpty(_wiredEvents[_type]))
								return true;

							var
								_typeEvents = _wiredEvents[_type],
								_names = _type == 'self' ? ['self'] : Uize.keys(_typeEvents),
								_testWidgetClassInstance = _getSyntaxTestWidgetClassInstance(
									_type == 'child' ? _names : undefined,
									_type == 'node' ? _names : undefined,
									_instanceProperties
								),
								_fail = function() { _continue(true) }
							;
							_processArrayAsync(
								_names,
								function(_objectName, _nextObjectFunc) {
									_processArrayAsync(
										(_type == 'self' ? _wiredEvents : _typeEvents)[_objectName],
										function(_eventName, _nextEventFunc) {
											var
												_objectToFireOn = _type == 'self'
													? _testWidgetClassInstance
													: (_type == 'child'
														? _testWidgetClassInstance.children[_objectName]
														: _testWidgetClassInstance.getNode(_objectName)
													),
												_fireEvent = function(_fireHandler) {
													_type == 'self' && !_eventName.indexOf('Changed.')
														? _objectToFireOn.set(
															_eventName.slice(8),
															_fireHandler
														)
														: _objectToFireOn[_fireEventMethodName]({
															name:_eventName,
															handler:_fireHandler
														})
													;
												},
												_verifyEventFired = function(_nextFunc) {
													var _handlerNotCalledTimeout = setTimeout(function() { _continue(false) }, 0); // timeout for if handler isn't called
													_fireEvent(
														function(_event, _source) {
															clearTimeout(_handlerNotCalledTimeout);
															_expectFunc.call(
																this,
																{
																	_nextFunc:_nextFunc,
																	_testWidgetClassInstance:_testWidgetClassInstance,
																	_eventName:_eventName,
																	_event:_event,
																	_source:_source,
																	_fail:_fail,
																	_firedObject:_objectToFireOn
																}
															);
														}
													);
												},
												_verifyEventNotFired = function(_nextFunc) {
													var
														_handlerNotCalledTimeout = setTimeout(_nextFunc, 0)// timeout for when handler isn't called
													;

													// Verify event is not fired
													_fireEvent(
														function() { // handler shouldn't get called
															clearTimeout(_handlerNotCalledTimeout);
															_continue(false);
														}
													);
												},
												_deferredChildrenForEventObject = !Uize.isEmpty(_deferredChildren)
													&& (_type == 'self'
														? _deferredChildren.self
														: (_deferredChildren[_type] && _deferredChildren[_type][_objectName])
													),
												_deferredChildrenForEvent = _deferredChildrenForEventObject && _deferredChildrenForEventObject[_eventName]
											;

											_type == 'node' && _testWidgetClassInstance.met('wired');

											if (Uize.isEmpty(_deferredChildrenForEvent)) {
												_verifyEventFired(_nextEventFunc);
											}
											else {
												_processArrayAsync(
													_deferredChildrenForEvent,
													function(_deferredChildName, _nextDeferredChildFunc) {
														_verifyEventNotFired(
															function() {
																// Add deferred child
																_testWidgetClassInstance.addChild(_deferredChildName, Uize.Widget);

																_nextDeferredChildFunc();
															}
														);
													},
													function() {
														// Verify event is fired
														_verifyEventFired(
															function() {
																// Remove a random child
																_testWidgetClassInstance.removeChild(
																	_deferredChildrenForEvent[
																		Math.floor(Math.random() * _deferredChildrenForEvent.length)
																	]
																);

																// Verify event is not fired & then move onto next event
																_verifyEventNotFired(_nextEventFunc);
															}
														);
													}
												);
											}
										},
										_nextObjectFunc
									);
								},
								function() { _continue(true) }
							);
						};
					}

					return {
						title:Uize.capFirstChar(_type) + ' events are successfully fired',
						test:[
							{
								title:'Handler is called',
								test:_generateFireTest(
									function(_data) { _data._nextFunc() }
								)
							},
							{
								title:'"this" context is widget',
								test:_generateFireTest(
									function(_data) {
										this == _data._testWidgetClassInstance
											? _data._nextFunc()
											: _data._fail()
										;
									}
								)
							},
							{
								title:'First argument is event object',
								test:_generateFireTest(
									function(_data) {
										_data._event.name == _data._eventName
											? _data._nextFunc()
											: _data._fail()
										;
									}
								)
							},
							{
								title:'Second argument is source object',
								test:_generateFireTest(
									function(_data) {
										_data._source == _data._firedObject
											? _data._nextFunc()
											: _data._fail()
										;
									}
								)
							}
						]
					};
				}

				return {
					title:(_isVerbose ? 'Verbose' : 'Shorthand') + ' Syntax',
					test:[
						{
							title:'Widget class is a function (not null)',
							test:function() { return this.expectFunction(_getSyntaxTestWidgetClass()) }
						},
						{
							title:'Widget instance is an object (not null)',
							test:function() { return this.expectObject(_getSyntaxTestWidgetClassInstance()) }
						},
						_generateFireTests('self'),
						_generateFireTests('child'),
						{
							title:'Node events do not fire before widget is wired',
							test:function(_continue) {
								if (!_wiredEvents || Uize.isEmpty(_wiredEvents.node))
									return true;

								var
									_nodeNames = Uize.keys(_wiredEvents.node),
									_testWidgetClassInstance = _getSyntaxTestWidgetClassInstance(null, _nodeNames)
								;
								_processArrayAsync(
									_nodeNames,
									function(_nodeName, _nextNodeFunc) {
										_processArrayAsync(
											_wiredEvents.node[_nodeName],
											function(_eventName, _nextEventFunc) {
												// The handler shouldn't be called which means we won't continue to the next node,
												// so, set up a timeout to continue on if the handler is not called.
												var _notFiredTimeout = setTimeout(_nextEventFunc, 0);
												_testWidgetClassInstance.getNode(_nodeName).triggerEvent({
													name:_eventName,
													handler:function() {
														clearTimeout(_notFiredTimeout);
														_continue(false); // we should never get here
													}
												});
											},
											_nextNodeFunc
										);
									},
									function() { _continue(true) }
								);
							}
						},
						_generateFireTests('node')
					]
				};
			}

			return {
				title:_title,
				test:[
					_generateSyntaxTests(),
					_generateSyntaxTests(true)
				]
			};
		}

		return _class.declare({
			set:{
				test:[
					{
						title:'Set the global window object',
						test:function() {
							_originalWindow = _global.window;
							_global.window = _global;  // For Uize.Dom.Basics
							return true;
						}
					},
					Uize.Test.requiredModulesTest ([
						'Uize.Widget',
						'Uize.Class.mChildObjectEventBindings'
					]),
					{
						title:'Empty bindings',
						test:[
							_generateTest('When no declarative event bindings are specified, no events are wired'),
							_generateTest('When empty event bindings is specified, no events are wired')
						]
					},
					{
						title:'Child Events',
						test:[
							_generateTest(
								'When a single child with a single event binding is declared, only that child event is bound',
								{
									'foo:Click':_defaultHandler
								},
								{
									foo:{
										Click:_defaultHandler
									}
								},
								{
									child:{
										foo:['Click']
									}
								}
							),
							_generateTest(
								'When a single child with multiple event bindings are declared, only the events for that child are bound',
								Uize.lookup(
									[
										'foo:Click',
										'foo:Changed.value',
										'foo:Changed.bar'
									],
									_defaultHandler
								),
								{
									foo:{
										Click:_defaultHandler,
										'Changed.value':_defaultHandler,
										'Changed.bar':_defaultHandler
									}
								},
								{
									child:{
										foo:['Click', 'Changed.value', 'Changed.bar']
									}
								}
							),
							_generateTest(
								'When a multiple children each with a single event binding are declared, only the one event for each child is bound',
								Uize.lookup(
									[
										'foo:Changed.bar',
										'lorem:Changed.ipsum'
									],
									_defaultHandler
								),
								{
									foo:{
										'Changed.bar':_defaultHandler
									},
									lorem:{
										'Changed.ipsum':_defaultHandler
									}
								},
								{
									child:{
										foo:['Changed.bar'],
										lorem:['Changed.ipsum']
									}
								}
							),
							_generateTest(
								'When a multiple children each with multiple event bindings are declared, only the events for those children are bound',
								Uize.lookup(
									[
										'foo:Click',
										'lorem:Changed.ipsum',
										'foo:Changed.value',
										'lorem:Changed.dolor',
										'foo:Changed.bar',
										'a:Changed.b',
										'a:c',
										'a:d',
										'a:Changed.e'
									],
									_defaultHandler
								),
								{
									foo:{
										Click:_defaultHandler,
										'Changed.value':_defaultHandler,
										'Changed.bar':_defaultHandler
									},
									lorem:{
										'Changed.ipsum':_defaultHandler,
										'Changed.dolor':_defaultHandler
									},
									a:{
										'Changed.b':_defaultHandler,
										'c':_defaultHandler,
										'd':_defaultHandler,
										'Changed.e':_defaultHandler
									}
								},
								{
									child:{
										foo:['Click', 'Changed.value', 'Changed.bar'],
										lorem:['Changed.ipsum', 'Changed.dolor'],
										a:['Changed.b', 'c', 'd', 'Changed.e']
									}
								}
							),
							{
								title:'Required Children',
								test:[
									_generateTest(
										'When required is left unspecified for a child event binding, the event is fired normally (w/ no errors)',
										{
											'foo:Click':{
													handler:_defaultHandler
												}
										},
										{
											foo:{
												Click:{
													handler:_defaultHandler
												}
											}
										},
										{
											child:{
												foo:['Click']
											}
										}
									),
									_generateTest(
										'When a single required child for a child event binding is declared, the event is not fired until the child is added',
										{
											'foo:Click':{
													handler:_defaultHandler,
													required:['baz']
												}
										},
										{
											foo:{
												Click:{
													handler:_defaultHandler,
													required:['baz']
												}
											}
										},
										{
											child:{
												foo:['Click']
											}
										},
										{
											child:{
												foo:{
													Click:['baz']
												}
											}
										}
									),
									_generateTest(
										'When multiple required children for a child event binding are declared, the event is not fired until all the children are added (and order doesn\'t matter)',
										{
											'foo:Click':{
												handler:_defaultHandler,
												required:['baz', 'bat', 'baf']
											}
										},
										{
											foo:{
												Click:{
													handler:_defaultHandler,
													required:['baz', 'bat', 'baf']
												}
											}
										},
										{
											child:{
												foo:['Click']
											}
										},
										{
											child:{
												foo:{
													Click:['bat', 'baf', 'baz']
												}
											}
										}
									)
								]
							},
							{
								title:'Conditional firing (fireIf)',
								test:Uize.push(
									Uize.map(
										[
											{
												title:'When fireIf is undefined and widget is disabled, child event is fired',
												state:{enabled:false}
											},
											{
												title:'When fireIf is undefined and widget is busy, child event is fired',
												state:{busy:true}
											},
											{
												title:'When fireIf evaluates to true, child event is fired',
												fireIf:'foo',
												state:{foo:true}
											}
										],
										function(_testInfo) {
											return {
												title:_testInfo.title,
												test:function(_continue) {
													var
														_testWidgetClassInstance = _getTestWidgetClassInstance(
															{
																'foo:Click':{
																	handler:function() {
																		clearTimeout(_notFiredTimeout);
																		_continue(true);
																	},
																	fireIf:_testInfo.fireIf
																}
															},
															['foo'],
															null,
															_testInfo.state
														),
														_notFiredTimeout
													;

													_notFiredTimeout = setTimeout(
														function() { _continue(false) },
														0
													);

													_testWidgetClassInstance.children.foo.fire('Click');
												}
											};
										}
									),
									[
										{
											title:'When fireIf evaluates to false, child event isn\'t fired',
											test:function(_continue) {
												var
													_testWidgetClassInstance = _getTestWidgetClassInstance(
														{
															'foo:Click':{
																handler:function() {
																	clearTimeout(_notFiredTimeout);
																	_continue(false);
																},
																fireIf:'foo'
															}
														},
														['foo'],
														null
													),
													_notFiredTimeout
												;

												// fire child widget event (shouldn't actually be handled by widget)
												_testWidgetClassInstance.children.foo.fire('Click');

												_notFiredTimeout = setTimeout(
													function() { _continue(true) },
													0
												);
											}
										}
									]
								)
							}
						]
					},
					{
						title:'Self Events',
						test:[
							_generateTest(
								'When a single event binding is declared, only that event is bound',
								Uize.lookup(
									[
										':Click'
									],
									_defaultHandler
								),
								{
									'':{
										Click:_defaultHandler
									}
								},
								{
									self:['Click']
								}
							),
							_generateTest(
								'When multiple events binding are declared, only those events are bound',
								{
									':Click':_defaultHandler,
									':Changed.value':_defaultChangedHandler
								},
								{
									'':{
										Click:_defaultHandler,
										'Changed.value':_defaultChangedHandler
									}
								},
								{
									self:['Click', 'Changed.value']
								}
							),
							_generateTest(
								'When a single required child for a self event binding is declared, the event is not fired until the child is added',
								{
									':Click':{
										handler:_defaultHandler,
										required:['baz']
									}
								},
								{
									'':{
										Click:{
											handler:_defaultHandler,
											required:['baz']
										}
									}
								},
								{
									self:['Click']
								},
								{
									self:{
										Click:['baz']
									}
								}
							),
							_generateTest(
								'When multiple required children for a self event binding are declared, the event is not fired until all the children are added (and order doesn\'t matter)',
								{
									':Click':{
										handler:_defaultHandler,
										required:['baz', 'bat', 'baf']
									}
								},
								{
									'':{
										Click:{
											handler:_defaultHandler,
											required:['baz', 'bat', 'baf']
										}
									}
								},
								{
									self:['Click']
								},
								{
									self:{
										Click:['bat', 'baf', 'baz']
									}
								}
							),
							{
								title:'Conditional firing (fireIf)',
								test:Uize.push(
									Uize.map(
										[
											{
												title:'When fireIf is undefined and widget is disabled, self event is fired',
												state:{enabled:false}
											},
											{
												title:'When fireIf is undefined and widget is busy, self event is fired',
												state:{busy:true}
											},
											{
												title:'When fireIf evaluates to true, self event is fired',
												fireIf:'foo',
												state:{foo:true}
											}
										],
										function(_testInfo) {
											return {
												title:_testInfo.title,
												test:function(_continue) {
													var
														_testWidgetClassInstance = _getTestWidgetClassInstance(
															{
																':Click':{
																	handler:function() {
																		clearTimeout(_notFiredTimeout);
																		_continue(true);
																	},
																	fireIf:_testInfo.fireIf
																}
															},
															null,
															null,
															_testInfo.state
														),
														_notFiredTimeout
													;

													_notFiredTimeout = setTimeout(
														function() { _continue(false) },
														0
													);

													_testWidgetClassInstance.fire('Click');
												}
											};
										}
									),
									[
										{
											title:'When fireIf evaluates to false, self event isn\'t fired',
											test:function(_continue) {
												var
													_testWidgetClassInstance = _getTestWidgetClassInstance(
														{
															':Click':{
																handler:function() {
																	clearTimeout(_notFiredTimeout);
																	_continue(false);
																},
																fireIf:'foo'
															}
														},
														null,
														null
													),
													_notFiredTimeout
												;

												// fire child widget event (shouldn't actually be handled by widget)
												_testWidgetClassInstance.fire('Click');

												_notFiredTimeout = setTimeout(
													function() { _continue(true) },
													0
												);
											}
										}
									]
								)
							}
						]
					},
					{
						title:'Node Events',
						test:[
							_generateTest(
								'When a single node with a single event binding is declared, only that node event is bound',
								Uize.lookup(
									[
										'#foo:click'
									],
									_defaultHandler
								),
								{
									'#foo':{
										click:_defaultHandler
									}
								},
								{
									node:{
										foo:['click']
									}
								}
							),
							_generateTest(
								'When a single node with multiple event bindings are declared, only the events for that node are bound',
								Uize.lookup(
									[
										'#foo:click',
										'#foo:mousemove',
										'#foo:change'
									],
									_defaultHandler
								),
								{
									'#foo':{
										click:_defaultHandler,
										mousemove:_defaultHandler,
										change:_defaultHandler
									}
								},
								{
									node:{
										foo:['click', 'mousemove', 'change']
									}
								}
							),
							_generateTest(
								'When a multiple nodes each with a single event binding are declared, only the one event for each node is bound',
								Uize.lookup(
									[
										'#foo:load',
										'#lorem:unload'
									],
									_defaultHandler
								),
								{
									'#foo':{
										load:_defaultHandler
									},
									'#lorem':{
										unload:_defaultHandler
									}
								},
								{
									node:{
										foo:['load'],
										lorem:['unload']
									}
								}
							),
							_generateTest(
								'When a multiple nodes each with multiple event bindings are declared, only the events for those nodes are bound',
								Uize.lookup(
									[
										'#a:focus',
										'#foo:click',
										'#lorem:keypress',
										'#a:change',
										'#foo:mouseover',
										'#a:blur',
										'#foo:keydown',
										'#lorem:keyup',
										'#a:load'
									],
									_defaultHandler
								),
								{
									'#foo':{
										click:_defaultHandler,
										mouseover:_defaultHandler,
										keydown:_defaultHandler
									},
									'#lorem':{
										keypress:_defaultHandler,
										keyup:_defaultHandler
									},
									'#a':{
										load:_defaultHandler,
										blur:_defaultHandler,
										focus:_defaultHandler,
										change:_defaultHandler
									}
								},
								{
									node:{
										foo:['click', 'mouseover', 'keydown'],
										lorem:['keypress', 'keyup'],
										a:['load', 'blur', 'focus', 'change']
									}
								}
							),
							_generateTest(
								'When root node with a single event binding is declared, only that node event is bound',
								Uize.lookup(
									[
										'#:click'
									],
									_defaultHandler
								),
								{
									'#':{
										click:_defaultHandler
									}
								},
								{
									node:{
										'':['click']
									}
								}
							),
							_generateTest(
								'When root node with multiple event bindings are declared, only the events for the node are bound',
								Uize.lookup(
									[
										'#:click',
										'#:mousemove'
									],
									_defaultHandler
								),
								{
									'#':{
										click:_defaultHandler,
										mousemove:_defaultHandler
									}
								},
								{
									node:{
										'':['click', 'mousemove']
									}
								}
							),
							{
								title:'Required children',
								test:[
									_generateTest(
										'When required is left unspecified for a node event binding, the event is fired normally (w/ no errors)',
										{
											'#foo:click':{
												handler:_defaultHandler
											}
										},
										{
											'#foo':{
												click:{
													handler:_defaultHandler
												}
											}
										},
										{
											node:{
												foo:['click']
											}
										}
									),
									_generateTest(
										'When a single required child for a node event binding is declared, the event is not fired until the child is added',
										{
											'#foo:click':{
												handler:_defaultHandler,
												required:['baz']
											}
										},
										{
											'#foo':{
												click:{
													handler:_defaultHandler,
													required:['baz']
												}
											}
										},
										{
											node:{
												foo:['click']
											}
										},
										{
											node:{
												foo:{
													click:['baz']
												}
											}
										}
									),
									_generateTest(
										'When multiple required children for a node event binding are declared, the event is not fired until all the children are added (and order doesn\'t matter)',
										{
											'#foo:click':{
												handler:_defaultHandler,
												required:['baz', 'bat', 'baf']
											}
										},
										{
											'#foo':{
												click:{
													handler:_defaultHandler,
													required:['baz', 'bat', 'baf']
												}
											}
										},
										{
											node:{
												foo:['click']
											}
										},
										{
											node:{
												foo:{
													click:['bat', 'baf', 'baz']
												}
											}
										}
									)
								]
							},
							{
								title:'Conditional Firing (fireIf)',
								test:Uize.push(
									Uize.map(
										[
											{
												title:'When fireIf is unspecified, the wired DOM event doesn\'t fire if busy or disabled'
											},
											{
												title:'When fireIf is null, the wired DOM event doesn\'t fire if busy or disabled',
												fireIf:null
											},
											{
												title:'When fireIf is undefined, the wired DOM event doesn\'t fire if busy or disabled',
												fireIf:undefined
											},
											{
												title:'When fireIf is empty string, the wired DOM event doesn\'t fire if busy or disabled',
												fireIf:''
											}
										],
										function (_eventBindingsInfo) {
											return {
												title:_eventBindingsInfo.title,
												test:function(_continue) {
													var
														_testWidgetClassInstance = _getTestWidgetClassInstance(
															{
																'#myNode:click':Uize.copyInto(
																	{
																		handler:function() {
																			clearTimeout(_notFiredTimeout);
																			_continue(false);
																		}
																	},
																	_eventBindingsInfo.fireIf ? {fireIf:_eventBindingsInfo.fireIf} : null
																)
															},
															null,
															['myNode']
														),
														_notFiredTimeout
													;

													_testWidgetClassInstance.met('wired');

													// set widget to busy or disabled
													_testWidgetClassInstance.set(
														Math.floor(Math.random() * 2)
															? {enabled:false}
															: {busy:true}
													);

													// fire DOM node event (shouldn't actually be handled by widget)
													_testWidgetClassInstance.getNode('myNode').triggerEvent({
														name:'click'
													});

													_notFiredTimeout = setTimeout(
														function() { _continue(true) },
														0
													);
												}
											};
										}
									),
									[
										{
											title:'When fireIf is specified, the wired DOM event doesn\'t fire if the condition hasn\'t been met',
											test:function(_continue) {
												var
													_testWidgetClassInstance = _getTestWidgetClassInstance(
														{
															'#myNode:click':{
																handler:function() {
																	clearTimeout(_notFiredTimeout);
																	_continue(false);
																},
																fireIf:'foo'
															}
														},
														null,
														['myNode']
													),
													_notFiredTimeout
												;

												_testWidgetClassInstance.met('wired');

												// fire DOM node event (shouldn't actually be handled by widget)
												_testWidgetClassInstance.getNode('myNode').triggerEvent({
													name:'click'
												});

												_notFiredTimeout = setTimeout(
													function() { _continue(true) },
													0
												);
											}
										},
										{
											title:'When fireIf is specified, the wired DOM event fires when the condition has been met',
											test:function(_continue) {
												var
													_testWidgetClassInstance = _getTestWidgetClassInstance(
														{
															'#myNode:click':{
																handler:function() {
																	clearTimeout(_notFiredTimeout);
																	_continue(true);
																},
																fireIf:'foo'
															}
														},
														null,
														['myNode']
													),
													_notFiredTimeout
												;

												_testWidgetClassInstance.met('wired');
												_testWidgetClassInstance.met('foo');

												_notFiredTimeout = setTimeout(
													function() { _continue(false) },
													0
												);

												// fire DOM node event (shouldn't actually be handled by widget)
												_testWidgetClassInstance.getNode('myNode').triggerEvent({
													name:'click'
												});
											}
										}
									]
								)
							}
						]
					},
					{
						title:'Potential Collision Events',
						test:[
							_generateTest(
								'When events for a child and node with the same name are declared, the proper events are bound',
								Uize.lookup(
									[
										'foo:Click',
										'foo:Changed.bar',
										'#foo:click',
										'#foo:unload',
										'#lorem:change',
										'lorem:Changed.ipsum'
									],
									_defaultHandler
								),
								{
									'foo':{
										Click:_defaultHandler,
										'Changed.bar':_defaultHandler
									},
									'#foo':{
										click:_defaultHandler,
										unload:_defaultHandler
									},
									'#lorem':{
										change:_defaultHandler
									},
									'lorem':{
										'Changed.ipsum':_defaultHandler
									}
								},
								{
									child:{
										'foo':['Click', 'Changed.bar'],
										'lorem':['Changed.ipsum']
									},
									node:{
										'foo':['click', 'unload'],
										'lorem':['change']
									}
								}
							),
							_generateTest(
								'When events for a self and root node with the same name are declared, the proper events are bound',
								Uize.copyInto(
									Uize.lookup(
										[
											':Click',
											'#:click',
											'#:unload'
										],
										_defaultHandler
									),
									{
										':Changed.bar':_defaultChangedHandler
									}
								),
								{
									'':{
										Click:_defaultHandler,
										'Changed.bar':_defaultChangedHandler
									},
									'#':{
										click:_defaultHandler,
										unload:_defaultHandler
									}
								},
								{
									self:['Click', 'Changed.bar'],
									node:{
										'':['click', 'unload']
									}
								}
							)
						]
					},
					{
						title:'All Event Types',
						test:[
							_generateTest(
								'When all 3 types of events are declared, some with required blocks, the proper events are bound and fire at the right time',
								{
									':Click':{
										handler:_defaultHandler,
										required:['green']
									},
									':Changed.bar':_defaultChangedHandler,
									'#:click':_defaultHandler,
									'#:unload':_defaultHandler,
									'#lorem:change':{
										handler:_defaultHandler,
										required:['blah']
									},
									'lorem:Changed.ipsum':_defaultHandler,
									'foo:Click':_defaultHandler,
									'foo:Changed.bar':{
										handler:_defaultHandler,
										required:['hiya']
									},
									'#foo:click':_defaultHandler,
									'#foo:unload':_defaultHandler,
									'#a:load':_defaultHandler,
									'#a:blur':{
										handler:_defaultHandler,
										required:['red','blue']
									},
									'#a:focus':_defaultHandler,
									'#a:change':_defaultHandler
								},
								{
									'':{
										Click:{
											handler:_defaultHandler,
											required:['green']
										},
										'Changed.bar':_defaultChangedHandler
									},
									'#':{
										click:_defaultHandler,
										unload:_defaultHandler
									},
									'#lorem':{
										change:{
											handler:_defaultHandler,
											required:['blah']
										}
									},
									'lorem':{
										'Changed.ipsum':_defaultHandler
									},
									'foo':{
										Click:_defaultHandler,
										'Changed.bar':{
											handler:_defaultHandler,
											required:['hiya']
										}
									},
									'#foo':{
										click:_defaultHandler,
										unload:_defaultHandler
									},
									'#a':{
										load:_defaultHandler,
										blur:{
											handler:_defaultHandler,
											required:['red','blue']
										},
										focus:_defaultHandler,
										change:_defaultHandler
									}
								},
								{
									self:['Click', 'Changed.bar'],
									child:{
										'foo':['Click', 'Changed.bar'],
										'lorem':['Changed.ipsum']
									},
									node:{
										'':['click', 'unload'],
										'foo':['click', 'unload'],
										'lorem':['change'],
										a:['load', 'blur', 'focus', 'change']
									}
								},
								{
									node:{
										lorem:{
											change:['blah']
										},
										a:{
											blur:['red','blue']
										}
									},
									child:{
										foo:{
											'Changed.bar':['hiya']
										}
									},
									self:{
										Click:['green']
									}
								}
							)
						]
					},
					{
						title:'Edge cases',
						test:[
							{
								title:'When a bound child is removed, a fired event on the child is properly handled (no errors & not fired on parent)',
								test:function(_continue) {
									var
										_widget = _getTestWidgetClassInstance(
											{
												'childA:Click':function() { _continue(false) }
											},
											['childA']
										),
										_childToRemove = _widget.children.childA // keep reference so we'll have it after removal
									;

									_widget.removeChild(_childToRemove);

									// fire child event (shouldn't actually be handled by the parent)
									_childToRemove.fire('Click');

									setTimeout(
										function() { _continue(true) },
										0
									);
								}
							},
							{
								title:'When a bound child is removed, and a new same-named child is re-added, a child event is handled by the parent',
								test:function(_continue) {
									var
										_widget = _getTestWidgetClassInstance(
											{
												'childA:Click':function() {
													clearTimeout(_failTimeout);
													_continue(true);
												}
											},
											['childA']
										),
										_failTimeout
									;

									// remove child
									_widget.removeChild('childA');

									// add new same-named child
									var _newChild = _widget.addChild('childA', Uize.Widget);

									// this shouldn't happen because the handler should be rebound when new child was added
									_failTimeout = setTimeout(
										function() { _continue(false) },
										0
									);

									_newChild.fire('Click'); // fire child event (should be handled by parent)
								}
							},
							{
								title:'When a subclass declares the same child/event combination, the base class\' handler is called',
								test:function(_continue) {
									var
										_WidgetClass = _getTestWidgetClass(
											{
												'childA:Click':function() {
													clearTimeout(_failTimeout);
													_continue(true);
												}
											},
											['childA']
										),
										_WidgetSubclass = _WidgetClass.subclass(
											_Uize.pairUp(
												_eventBindingsFunctionName,
												{
													'childA:Click':_Uize.nop
												}
											)
										),
										_failTimeout
									;

									// this shouldn't happen because the base class' handler should be called
									_failTimeout = setTimeout(
										function() { _continue(false) },
										0
									);

									_WidgetSubclass().children.childA.fire('Click');
								}
							}
						]
					},
					{
						title:'Restore the global window object',
						test:function() {
							_global.window = _originalWindow;
							return true;
						}
					}
				]
			}
		});
	}
});
//


koh5_pano



Your browser does not support the HTML5 canvas element.


Drag mouse to navigate.

Navigation





17.Aug.2010, Martin Wengenmayer