SOURCE CODE: Uize.Test.Uize.Widget.mDeclarativeChildren

VIEW REFERENCE

/*______________
|       ______  |   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.Widget.mDeclarativeChildren Class
|   /    / /    |
|  /    / /  /| |    ONLINE : http://uize.com
| /____/ /__/_| | COPYRIGHT : (c)2014 UIZE
|          /___ |   LICENSE : Available under MIT License or GNU General Public License
|_______________|             http://uize.com/license.html
*/

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

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

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

Uize.module ({
  name:'Uize.Test.Uize.Widget.mDeclarativeChildren',
  builder:function () {
    'use strict';

    function _expectAll(_children, _expectFunc) {
      for (var _childName in _children) {
        if (!_expectFunc(_children[_childName], _childName))
          return false;
      }

      return true;
    }

    function _getDeclaredChildren(_declarativeChildren, _getContainerMethod) {
      return (Uize.Widget.subclass (
        Uize.copyInto(
          {
            mixins:Uize.Widget.mDeclarativeChildren,
            children:_declarativeChildren
              ? Uize.map(
                _declarativeChildren,
                function(_childProperties) {
                  if (Uize.isPlainObject(_childProperties) && _childProperties.widgetClass)
                    _childProperties.widgetClass = Uize.getModuleByName(_childProperties.widgetClass);
                  else if (Uize.isString(_childProperties))
                    _childProperties = Uize.getModuleByName(_childProperties);

                  return _childProperties;
                }
              )
              : _declarativeChildren,
            stateProperties:{
              _propertyA:{
                name:'propertyA',
                value:14
              },
              _propertyB:{
                name:'propertyB',
                value:'hello'
              }
            }
          },
          _getContainerMethod
            ? {instanceMethods:{mDeclarativeChildren_getContainer:_getContainerMethod}}
            : null
        )
      ) ({name:'parent'})).children;
    }

    function _generateTest(_title, _declarativeChildren, _expectedChildren) {
      function _getDeclaredChildrenForTest() { return _getDeclaredChildren(_declarativeChildren) }
      function _expectAllDeclaredChildren(_expectFunc) { return _expectAll(_getDeclaredChildrenForTest(), _expectFunc) }

      return {
        title:_title,
        test:[
          {
            title:'Children object is not null',
            test:function() { return this.expectObject(_getDeclaredChildrenForTest()) }
          },
          {
            title:'Children object has the same child names as defined in declarative children w/ a widgetClass',
            test:function() {
              var m = this;
              return _expectAllDeclaredChildren(function(_child, _childName) { return m.expect(true, _childName in _expectedChildren) });
            }
          },
          {
            title:'None of the children are null',
            test:function() {
              var m = this;
              return _expectAllDeclaredChildren(function(_child) { return m.expectNonNull(_child) });
            }
          },
          {
            title:'Each child should be an object',
            test:function() {
              var m = this;
              return _expectAllDeclaredChildren(function(_child) { return m.expectObject(_child) });
            }
          },
          {
            title:'Each child has the correct widget class',
            test:function() {
              var m = this;
              return _expectAll(
                _getDeclaredChildrenForTest(),
                function(_child, _childName) {
                  return m.expect(_expectedChildren[_childName].widgetClass, _child.Class.moduleName);
                }
              );
            }
          },
          {
            title:'Each child has the correct initial state',
            test:function() {
              var m = this;
              return _expectAll(
                _getDeclaredChildrenForTest(),
                function(_child, _childName) {
                  return m.expect(true, Uize.recordMatches(_child.get(), _expectedChildren[_childName].state));
                }
              );
            }
          }
        ]
      };
    }

    return Uize.Test.resolve ({
      title:'Uize.Widget.mDeclarativeChildren Module Test',
      test:[
        Uize.Test.requiredModulesTest ([
          'Uize.Widget',
          'Uize.Widget.mDeclarativeChildren'
        ]),
        {
          title:'Empty',
          test:[
            _generateTest('When no declarative children are specified, no children are added to the widget'),
            _generateTest('When an empty declarative children is specified, no children are added to the widget', {})
          ]
        },
        {
          title:'Verbose Syntax',
          test:[
            _generateTest(
              'When a single declarative children is specified, only one child is added to the widget with appopriate state properties',
              {
                foo:{
                  widgetClass:'Uize.Widget',
                  enabled:false,
                  busy:true,
                  container:'shell'
                }
              },
              {
                foo:{
                  widgetClass:'Uize.Widget',
                  state:{
                    enabled:false,
                    busy:true,
                    container:'shell'
                  }
                }
              }
            ),
            _generateTest(
              'When multiple declarative children are specified, an equal number of children are added added to the widget, each with their appopriate state properties',
              {
                foo:{
                  widgetClass:'Uize.Widget',
                  enabled:false,
                  busy:true,
                  container:'shell'
                },
                bar:{
                  widgetClass:'Uize.Widget',
                  propretyA:1,
                  propertyB:'valueB'
                },
                lorem:{
                  widgetClass:'Uize.Widget',
                  foo:2
                }
              },
              {
                foo:{
                  widgetClass:'Uize.Widget',
                  state:{
                    enabled:false,
                    busy:true,
                    container:'shell'
                  }
                },
                bar:{
                  widgetClass:'Uize.Widget',
                  state:{
                    propretyA:1,
                    propertyB:'valueB'
                  }
                },
                lorem:{
                  widgetClass:'Uize.Widget',
                  state:{
                    foo:2
                  }
                }
              }
            ),
            _generateTest(
              'When a declared child omits its widgetClass, it does not get added to the widget',
              {
                ipsum:{
                  enabled:false,
                  busy:true,
                  container:'shell'
                },
                dolor:{
                  widgetClass:'Uize.Widget',
                  value:'foo'
                },
                sit:{
                  widgetClass:'Uize.Widget',
                  foo:2
                },
                blah:{}
              },
              {
                dolor:{
                  widgetClass:'Uize.Widget',
                  state:{
                    value:'foo'
                  }
                },
                sit:{
                  widgetClass:'Uize.Widget',
                  state:{
                    foo:2
                  }
                }
              }
            ),
            _generateTest(
              'When a declared child has a falsy value for widgetClass, it does not getting added to the widget',
              {
                foo:{
                  widgetClass:''
                },
                bar:{
                  widgetClass:null
                },
                bat:{
                  widgetClass:undefined
                },
                baz:{
                  widgetClass:0
                },
                lorem:{
                  widgetClass:false
                },
                ipsum:{
                  widgetClass:NaN
                }
              },
              {

              }
            )
          ]
        },
        {
          title:'Shorthand Syntax',
          test:[
            _generateTest(
              'When a single declarative children is specified, only one child is added to the widget with appopriate state properties',
              {
                foo:'Uize.Widget'
              },
              {
                foo:{
                  widgetClass:'Uize.Widget'
                }
              }
            ),
            _generateTest(
              'When multiple declarative children are specified, an equal number of children are added added to the widget, each with their appopriate state properties',
              {
                foo:'Uize.Widget',
                bar:'Uize.Widget',
                lorem:'Uize.Widget'
              },
              {
                foo:{
                  widgetClass:'Uize.Widget'
                },
                bar:{
                  widgetClass:'Uize.Widget'
                },
                lorem:{
                  widgetClass:'Uize.Widget'
                }
              }
            ),
            _generateTest(
              'When a declared child omits its widgetClass, it does not get added to the widget',
              {
                ipsum:'',
                dolor:'Uize.Widget',
                sit:'Uize.Widget'
              },
              {
                dolor:{
                  widgetClass:'Uize.Widget'
                },
                sit:{
                  widgetClass:'Uize.Widget'
                }
              }
            ),
            _generateTest(
              'When a falsy value is specified for widgetClass of a declared child, it does not get added to the widget',
              {
                foo:'',
                bar:null,
                bat:undefined,
                baz:0,
                lorem:false,
                ipsum:NaN
              },
              {

              }
            )
          ]
        },
        {
          title:'Function Syntax',
          test:[
            {
              title:'Function context is parent widget',
              test:function() {
                var
                  m = this,
                  _returnValue = false
                ;

                _getDeclaredChildren({
                  childA:function() {
                    _returnValue = m.expect('parent', this.get('name'));
                    return {};
                  }
                });

                return _returnValue;
              }
            },
            {
              title:'Function\'s first parameter value is the child name',
              test:function() {
                var
                  m = this,
                  _returnValue = false
                ;

                _getDeclaredChildren({
                  childA:function(_childName) {
                    _returnValue = m.expect('childA', _childName);
                    return {};
                  }
                });

                return _returnValue;
              }
            },
            _generateTest(
              'When a single declarative children is specified (verbose synax), only one child is added to the widget with appopriate state properties',
              {
                childA:function(_childName) {
                  return {
                    widgetClass:Uize.Widget,
                    propertyA:_childName,
                    propertyB:this._propertyB,
                    propertyC:Math.sqrt(16)
                  };
                }
              },
              {
                childA:{
                  widgetClass:'Uize.Widget',
                  state:{
                    propertyA:'childA',
                    propertyB:'hello',
                    propertyC:4
                  }
                }
              }
            ),
            _generateTest(
              'When multiple declarative children are specified, an equal number of children are added added to the widget, each with their appopriate state properties',
              {
                foo:function() {
                  return {
                    widgetClass:Uize.Widget,
                    enabled:false,
                    busy:true,
                    container:'shell'
                  };
                },
                bar:function() {
                  return {
                    widgetClass:Uize.Widget
                  };
                },
                lorem:function() {
                  return {
                    widgetClass:Uize.Widget,
                    foo:2
                  };
                }
              },
              {
                foo:{
                  widgetClass:'Uize.Widget',
                  state:{
                    enabled:false,
                    busy:true,
                    container:'shell'
                  }
                },
                bar:{
                  widgetClass:'Uize.Widget'
                },
                lorem:{
                  widgetClass:'Uize.Widget',
                  state:{
                    foo:2
                  }
                }
              }
            ),
            _generateTest(
              'When a declared child omits its widgetClass, it does not get added to the widget',
              {
                ipsum:function() {
                  return {
                    enabled:false,
                    busy:true,
                    container:'shell'
                  };
                },
                dolor:function() {
                  return {
                    widgetClass:Uize.Widget,
                    value:'foo'
                  };
                },
                sit:function() {
                  return {
                    widgetClass:Uize.Widget
                  };
                },
                blah:function() { return {} }
              },
              {
                dolor:{
                  widgetClass:'Uize.Widget',
                  state:{
                    value:'foo'
                  }
                },
                sit:{
                  widgetClass:'Uize.Widget'
                }
              }
            ),
            _generateTest(
              'When a declared child has a falsy value for widgetClass, it does not getting added to the widget',
              {
                foo:function() {
                  return {
                    widgetClass:''
                  };
                },
                bar:function() {
                  return {
                    widgetClass:null
                  };
                },
                bat:function() {
                  return {
                    widgetClass:undefined
                  };
                },
                baz:function() {
                  return {
                    widgetClass:0
                  };
                },
                lorem:function() {
                  return {
                    widgetClass:false
                  }
                },
                ipsum:function() {
                  return {
                    widgetClass:NaN
                  };
                }
              },
              {}
            )
          ]
        },
        {
          title:'A Subclass can override the getContainer method',
          test:function() {
            var _returnValue = false;

            _getDeclaredChildren(
              {childA:'Uize.Widget'},
              function() {
                _returnValue = true;
                return this;
              }
            );

            return _returnValue
          }
        }
      ]
    });
  }
});