/*______________ | ______ | 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.mModels Class | / / / | | / / / /| | ONLINE : http://uize.com | /____/ /__/_| | COPYRIGHT : (c)2014-2016 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.Class.mModels= module defines a suite of unit tests for the =Uize.Class.mModels= mixin module. *DEVELOPERS:* `Ben Ilegbodu`, original code contributed by `Zazzle Inc.` */ Uize.module ({ name:'Uize.Test.Uize.Class.mModels', superclass:'Uize.Test.Class', required:[ 'Uize.Array.Util', 'Uize.Class', 'Uize.Test.Class.mSpy' ], builder:function (_superclass) { 'use strict'; var _true = true, _false = false, _undefined, _Uize = Uize, _Uize_Class = _Uize.Class, _createClass = function() { return _Uize_Class.subclass({ mixins:_class.getModule() }); }, _createInstance = function(_properties) { return _createClass()(_properties); }, _class = _superclass.subclass({ mixins:_Uize.Test.Class.mSpy, moduleToTest:'Uize.Class.mModels' }) ; return _class.declare({ set:{ test:[ _class.requiredModulesTest(), _class.instanceMethodsTest([ { methodName:'addModel', cases:_Uize.Array.Util.flatten( _Uize.map( [ { _title:'When model is added with model class, model is created, added and returned', _params:['model', _Uize_Class] }, { _title:'When model is added with model class with properties, model is created, added and returned', _params:['model', _Uize_Class, {prop1:'prop1', prop2:'prop2', prop3:'prop3'}] }, { _title:'When model is added with model class without a model name, but with properties that specify name, model is created, added and returned', _params:[_undefined, _Uize_Class, {name:'model', prop1:'prop1', prop2:'prop2', prop3:'prop3'}] }, { _title:'When model is added with model instance, model is added and returned', _params:['model', new _Uize_Class()] }, { _title:'When model is added with model instance with additional override properties, model is added and returned', _params:['model', new _Uize_Class(), {prop1:'prop1', prop2:'prop2', prop3:'prop3'}] }, { _title:'When model is added with model instance without a model name, but with additional override properties that specify name, model is added and returned', _params:[_undefined, new _Uize_Class(), {name:'model', prop1:'prop1', prop2:'prop2', prop3:'prop3'}] }, { _title:'When model is added with model class with unapplied data, model is created, added and returned', _existingModels:{ model:{prop1:'value1', prop2:'value2'} }, _params:['model', _Uize_Class] }, { _title:'When model is added with model class with properties as well as unapplied data, model is created, added and returned', _existingModels:{ model:{prop4:'value4', prop5:'value5'} }, _params:['model', _Uize_Class, {prop1:'prop1', prop2:'prop2', prop3:'prop3'}] }, { _title:'When model is added with model class with properties as well as unapplied data (unapplied overrides), model is created, added and returned', _existingModels:{ model:{prop1:'value1', prop2:'value2'} }, _params:['model', _Uize_Class, {prop1:'prop1', prop2:'prop2', prop3:'prop3'}] } ], function(_case) { var _caseTitle = _case._title, _caseParams = _case._params, _modelClass = _Uize.isInstance(_caseParams[1]) ? _caseParams[1].Class : _caseParams[1], _modelProperties = _caseParams[2] || {}, _modelName = _caseParams[0] || _modelProperties.name, _existingModelsData = _case._existingModels ; return _Uize.map( [ { _title:'not null', _expectFunc:function(_addedModel) { return this.expectNonNull(_addedModel) } }, { _title:'Uize.Class instance', _expectFunc:function(_addedModel) { return this.expect(_modelClass, _addedModel.Class) } }, { _title:'model is added to models instance property', _expectFunc:function(_addedModel) { return this.expect(_addedModel, this.get('instance').models[_modelName]) } }, { _title:'model is initialized with properties', _expectFunc:function(_addedModel) { var _expectedModelProperties = _existingModelsData ? _Uize.copy(_modelProperties, _existingModelsData[_modelName]) : _modelProperties; return this.expect( _expectedModelProperties, _addedModel.get(_Uize.keys(_expectedModelProperties)) ); } }, { _title:'addedModels is marked as met', _expectFunc:function() { return this.expect( _true, this.get('instance').addedModels.isMet(_modelName) ); } } ], function(_subCase) { return { title:_caseTitle + ' (' + _subCase._title + ')', instanceProperties:{ models:_existingModelsData }, params:_caseParams, expectFunc:_subCase._expectFunc }; } ); } ).concat( [ (function() { var _existingModel = new _Uize_Class(); return { title:'When model already exists and model to add is the same model, no-op (existing model is not removed)', initialize:function(_instance) { this._spyObject = this.spyOn(_instance, 'removeModel'); _instance.addModel('model', _existingModel); }, params:['model', _existingModel], expectFunc:function() { var m = this; return m.expectToNotHaveBeenCalled(m._spyObject); } }; })(), { title:'When model already exists and new model is added by Class, old model is removed', initialize:function(_instance) { var m = this; m._spyObject = this.spyOn(_instance, 'removeModel'); m._existingModel = _instance.addModel('model', _Uize_Class); }, params:['model', _Uize_Class], expectFunc:function() { var m = this; return m.expectToHaveBeenCalledWith(m._spyObject, [m._existingModel]); } }, { title:'When model already exists and new model is added by instance, old model is removed', initialize:function(_instance) { var m = this; m._spyObject = this.spyOn(_instance, 'removeModel'); m._existingModel = _instance.addModel('model', _Uize_Class); }, params:['model', new _Uize_Class()], expectFunc:function() { var m = this; return m.expectToHaveBeenCalledWith(m._spyObject, [m._existingModel]); } }, { title:'When model already exists and new model is added by Class, addModel returns new model', initialize:function(_instance) { var m = this; m._spyObject = this.spyOn(_instance, 'removeModel'); m._existingModel = _instance.addModel('model', _Uize_Class); }, params:['model', _Uize_Class], expectFunc:function(_addedModel) { var m = this; return m.expectNotSameAs(_addedModel, m._existingModel); } }, (function() { var _newModel = new _Uize_Class(); return { title:'When model already exists and new model is added by instance, old model is removed', initialize:function(_instance) { var m = this; m._spyObject = this.spyOn(_instance, 'removeModel'); m._existingModel = _instance.addModel('model', _Uize_Class); }, params:['model', _newModel], expectFunc:function(_addedModel) { var m = this; return m.expect(_addedModel, _newModel); } }; })(), { title:'When model already exists and new model is added by Class, models proprety is correct', initialize:function(_instance) { var m = this; m._spyObject = this.spyOn(_instance, 'removeModel'); m._existingModel = _instance.addModel('model', _Uize_Class); }, params:['model', _Uize_Class], expectFunc:function(_addedModel) { var m = this; return m.expect(_addedModel, m.get('instance').models.model); } }, { title:'When model already exists and new model is added by instance, models proprety is correct', initialize:function(_instance) { var m = this; m._spyObject = this.spyOn(_instance, 'removeModel'); m._existingModel = _instance.addModel('model', _Uize_Class); }, params:['model', new _Uize_Class()], expectFunc:function(_addedModel) { var m = this; return m.expect(_addedModel, m.get('instance').models.model); } } ] ) ), create:_createInstance }, { methodName:'removeModel', cases:(function() { var _existingModel = new _Uize_Class(); return _Uize.Array.Util.flatten( _Uize.map( [ { _title:'When model is removed by name', _param:'model' }, { _title:'When model is removed by instance reference', _param:_existingModel }, { _title:'When specified model name is not an existing model', _param:'foo' } ], function(_case) { var _caseTitle = _case._title, _caseParam = _case._param, _modelName = _Uize.isString(_caseParam) ? _caseParam : 'model' ; return _Uize.map( [ { _title:'models instance property no longer has reference', _expectFunc:function() { return this.expectNully(this.get('instance').models[_modelName]) } }, { _title:'addedModels instance property is unmet', _expectFunc:function() { return this.expect(_false, !!this.get('instance').addedModels.isMet(_modelName)) } } ], function(_subCase) { return { title:_caseTitle + ', ' + _subCase._title, initialize:function(_instance) { _instance.addModel('model', _existingModel); }, params:[_caseParam], expectFunc:_subCase._expectFunc }; } ); } ) ); }) (), create:_createInstance } ]), _class.propertyConformersTest([ { propertyName:'models', cases:_Uize.Array.Util.flatten( _Uize.map( [ { _title:'When there are no existing models and single model data specified', _modelsData:{ model:{ prop1:'value1', prop2:'value2', prop3:'value3' } } }, { _title:'When there are no existing models and multiple models data specified', _modelsData:{ model:{ prop1:'value1', prop2:'value2', prop3:'value3' }, model2:{ prop4:'value4', prop5:'value5', prop6:'value6' } } }, { _title:'When there is one existing model and multiple models data specified', _models:[ ['model2', _Uize_Class] ], _modelsData:{ model:{ prop1:'value1', prop2:'value2', prop3:'value3' }, model2:{ prop4:'value4', prop5:'value5', prop6:'value6' } } }, { _title:'When there are multiple existing models and multiple models data specified', _models:[ ['model2', _Uize_Class], ['model3', _Uize_Class] ], _modelsData:{ model:{ prop1:'value1', prop2:'value2', prop3:'value3' }, model2:{ prop4:'value4', prop5:'value5', prop6:'value6' }, model3:{ prop7:'value7', prop8:'value8', prop9:'value9' }, model4:{ prop10:'value10', prop11:'value11', prop12:'value12' } } }, { _title:'When there are multiple existing models and multiple models data specified, but not all have data specified', _models:[ ['model2', _Uize_Class], ['model3', _Uize_Class] ], _modelsData:{ model:{ prop1:'value1', prop2:'value2', prop3:'value3' }, model2:{ prop4:'value4', prop5:'value5', prop6:'value6' }, model4:{ prop10:'value10', prop11:'value11', prop12:'value12' } } }, { _title:'When there are multiple existing models and all have data specified', _models:[ ['model2', _Uize_Class], ['model3', _Uize_Class], ['model1', _Uize_Class], ['model4', _Uize_Class] ], _modelsData:{ model:{ prop1:'value1', prop2:'value2', prop3:'value3' }, model2:{ prop4:'value4', prop5:'value5', prop6:'value6' }, model3:{ prop7:'value7', prop8:'value8', prop9:'value9' }, model4:{ prop10:'value10', prop11:'value11', prop12:'value12' } } } ], function(_case) { var _caseTitle = _case._title, _modelsData = _case._modelsData, _existingModels = _case._models ; return _Uize.map( [ { _title:'existing models have properties updated', _expectFunc:function() { var m = this, _instance = m.get('instance'), _propertiesUpdated = _true ; _Uize.forEach( _modelsData, function(_modelData, _modelName) { var _model = _instance.models[_modelName]; if (_model) _propertiesUpdated = _propertiesUpdated && m.expect(_modelData, _model.get(_Uize.keys(_modelData))) ; } ); return m.expect(_true, _propertiesUpdated); } }, { _title:'mModels_unappliedModelsProperties has leftover data', _expectFunc:function() { var _expectedUnappliedModelsProperties = _Uize.copy(_modelsData); _Uize.forEach( _existingModels, function(_existingModel) { delete _expectedUnappliedModelsProperties[_existingModel[0]]; } ); return this.expect( _expectedUnappliedModelsProperties, this.get('instance').mModels_unappliedModelsProperties ); } } ], function(_subCase) { return { title:_caseTitle + ', ' + _subCase._title, setup:function(_instance) { _Uize.forEach( _existingModels, function(_existingModel) { _instance.addModel.apply(_instance, _existingModel) } ); }, instanceProperties:{ models:_modelsData }, expectFunc:_subCase._expectFunc }; } ); } ) ).concat([ (function() { var _modelInstanceToAdd = new _Uize_Class(); return { title:'When instances are included, they are added', instanceProperties:{ models:{ model:_modelInstanceToAdd } }, expectFunc:function() { return this.expectSameAs( _modelInstanceToAdd, this.get('instance').models.model ); } }; }) (), (function() { var _existingModel = new _Uize_Class(), _spyObject ; return { title:'When instances are included but already exist, they are removed', setup:function(_instance) { _instance.addModel('model', _existingModel); _spyObject = this.spyOn(_instance, 'removeModel'); }, instanceProperties:{ models:{ model:new _Uize_Class() } }, expectFunc:function() { return this.expectToHaveBeenCalledWith(_spyObject, [_existingModel]); } }; }) (), (function() { var _modelInstanceToAdd = new _Uize_Class(); return { title:'When instances are included but already exist, they are added', setup:function(_instance) { _instance.addModel('model', new _Uize_Class()); }, instanceProperties:{ models:{ model:_modelInstanceToAdd } }, expectFunc:function() { return this.expectSameAs( _modelInstanceToAdd, this.get('instance').models.model ); } }; }) (), (function() { var _model = new _Uize_Class(), _spyObject ; return { title:'When instances are included but already exist, they are *not* removed if it\'s the same instance', setup:function(_instance) { _instance.addModel('model', _model); _spyObject = this.spyOn(_instance, 'removeModel'); }, instanceProperties:{ models:{ model:_model } }, expectFunc:function() { return this.expectToNotHaveBeenCalled(_spyObject); } }; }) (), (function() { var _model = new _Uize_Class(), _spyObject ; return { title:'When instances are included but already exist, models has correct reference', setup:function(_instance) { _instance.addModel('model', _model); _spyObject = this.spyOn(_instance, 'addModel'); }, instanceProperties:{ models:{ model:_model } }, expectFunc:function() { return this.expectSameAs( _model, this.get('instance').models.model ); } }; }) () ]), create:_createInstance } ]) ] } }); } });