/*______________ | ______ | 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.Class 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: Class importance: 4 codeCompleteness: 100 docCompleteness: 5 */ /*? Introduction The =Uize.Test.Class= module provides convenience methods for writing test cases against =Uize.Class= subclass modules. *DEVELOPERS:* `Ben Ilegbodu` */ Uize.module ({ name:'Uize.Test.Class', required:[ 'Uize.Test', 'Uize.Util.Oop', 'Uize.Json' ], builder:function (_superclass) { 'use strict'; var _Uize = Uize, _Uize_Json_to = _Uize.Json.to, _superclass_requiredModulesTest = _superclass.requiredModulesTest ; // This is probably universally useful for all test modules function _makeDeclarativeCasesTest(_testTitlePrefix, _testParams, _testFunc) { var _class = this, _propertyName = _testParams.propertyName, _cases = _testParams.cases, _caseTestProperties = _testParams.caseTestProperties, _tests = [] ; function _getCaseTest(_case) { var _caseIsTestObject = _Uize.Util.Oop.inheritsFrom (_case,_Uize.Test), _caseTest = !_caseIsTestObject ? { title:_case.title || ( 'When ' + _Uize_Json_to(_case.instanceProperties, 'mini') + ', ' + _propertyName + ' is ' + (_case.expected ? _Uize_Json_to(_case.expected, 'mini') : '*expected*') ), test:function (_continue) { return _testFunc.call( this, _class.getModule(), _case, _continue ); } } : _case ; if (_caseIsTestObject && _Uize.isArray (_case.test)) _case.test = _Uize.map (_case.test,_getCaseTest) ; if (_caseTestProperties) _caseIsTestObject ? _caseTest.set (_caseTestProperties) : _Uize.copyInto (_caseTest,_caseTestProperties) ; return _caseTest; } for (var _caseNo = -1, _casesLength = _cases.length; ++_caseNo < _casesLength;) _tests.push (_getCaseTest (_cases [_caseNo])) ; return _class.resolve ( _Uize.copyInto ( { title:_testTitlePrefix + ': ' + _propertyName, test:_tests }, _testParams.testProperties ) ); } function _makeMultipleDeclarativeCasesTest(_testTitle, _tests, _makeTestFunc) { var _class = this; return _class.resolve ({ title:_testTitle, test:Uize.map ( _tests, function (_test) { return ( _Uize.isArray (_test) ? _makeTestFunc.apply (_class, _test) : (_Uize.isPlainObject(_test) ? _makeTestFunc.call (_class, _test) : _test ) ); } ) }); } function _makeDeclarativeCasesPropertyTest(_testTitlePrefix, _testParams) { var _propertyName = _testParams.propertyName, _instanceProperties = _testParams.instanceProperties, _create = _testParams.create, _testParamsCreateParams = _testParams.createParams ; // TODO: Add an initial test that verifies the state property actually exists? return _makeDeclarativeCasesTest.call( this, _testTitlePrefix, _testParams, function(_moduleToTest, _case, _continue) { function _getInstance(m, _caseCreateParams) { return _Uize.isFunction(_create) ? m.setInstance(_create, _caseCreateParams || _testParamsCreateParams || [_instanceProperties]) : m.setInstance(_instanceProperties) ; } var m = this, _instance = _getInstance(m, _case.createParams), _setup = _case.setup, _expectFunc = _case.expectFunc ; // Provide opportunity for test to do some set up work (like set up spies) _Uize.isFunction(_setup) && _setup.call(m, _instance, _continue); // cause property change _instance.set(_case.instanceProperties); var _propertyActualValue = _instance.get(_propertyName); if ('expected' in _case) return m.expect(_case.expected, _propertyActualValue); else if (_Uize.isFunction(_expectFunc)) return _expectFunc.call(m, _propertyActualValue, _instance, _continue); } ); } return _superclass.subclass({ staticMethods:{ derivedPropertyTest:function(_testParams) { // TODO: Add an intial test that verifies that state property is derived? return _makeDeclarativeCasesPropertyTest.call( this, 'DERIVED PROPERTY TEST', _testParams ); /*? Static Methods Uize.Test.Class.derivedPropertyTest . SYNTAX .................................................................. testCLASS = Uize.Test.Class.derivedPropertyTest ( testParamsOBJ ); .................................................................. testParamsOBJ . propertyName . cases . title The title of the test case instanceProperties Properties to set on instance to cause derivation expected The expected derived value for the test case expectFunc A function (in lieu of the =expected= property) that takes the derived property value and a reference to the instance as parameters. It will return =true= if the derived property value is what is expected, =false= otherwise. createParams Optional parameters to pass to the =create= function (that override =createParams= for the =testParamsObBJ=). instanceProperties . create An alternative function for creating a model instance that would be different than just calling the constructor. createParams Optional parameters to pass to the =create= function. testProperties . caseTestProperties . EXAMPLE ....... Uize.Test.Class.derivedPropertyTest ( { propertyName:'isEmpty', cases:[ { title:'No total items', instanceProperties:{totalItems:0}, expected:true }, { title:'1 total items', instanceProperties:{totalItems:1}, expected:false }, { title:'Many total items', instanceProperties:{totalItems:2}, expectFunc:function(derivedPropertyValue, instance) { return this.expect(false, derivedPropertyValue); } } ] } ); ...... NOTES - see the related =Uize.Test.Class.derivedPropertiesTest= static method */ }, derivedPropertiesTest:function(_derivedPropertiesTests) { return _makeMultipleDeclarativeCasesTest.call( this, 'Derived Property Tests', _derivedPropertiesTests, this.derivedPropertyTest ); /*? Static Methods Uize.Test.Class.derivedPropertiesTest . SYNTAX .................................................................. testCLASS = Uize.Test.Class.derivedPropertiesTest ( derivedPropertiesTestsARRAYorOBJ ); .................................................................. derivedPropertiesTestARRAYorOBJ See =Uize.Test.Class.derivedPropertyTest= static method for the structure for each set of derived property tests. EXAMPLE ....... Uize.Test.Class.derivedPropertiesTest ( [ { propertyName:'isEmpty', cases:[ ] }, { propertyName:'oneSelected', cases:[ ] }, { propertyName:'someSelected', cases:[ ] } ] ); ...... NOTES - see the related =Uize.Test.Class.derivedPropertyTest= static method */ }, instanceMethodTest:function(_testParams) { var _testClass = this, _methodName = _testParams.methodName, _cases = _testParams.cases, _testParamsInitialize = _testParams.initialize, _instanceProperties = _testParams.instanceProperties, _create = _testParams.create, _testParamsCreateParams = _testParams.createParams ; function _getInstance(m, _caseCreateParams) { return _Uize.isFunction(_create) ? m.setInstance(_create, _caseCreateParams || _testParamsCreateParams || [_instanceProperties]) : m.setInstance(_instanceProperties) ; } return _testClass.resolve( _Uize.copyInto( { title:_testParams.title || ('INSTANCE METHOD TEST: ' + _methodName), test:Uize.map( _cases, function(_case) { var _methodParams = _case.params || [], _expected = _case.expected, _initializeFunc = _case.initialize ; return { title:_case.title || 'When ' + _Uize.Json.to(_methodParams, 'mini') + ' is passed, ' + _Uize_Json_to(_expected, 'mini') + ' is returned', test:function(_continue) { var m = this, _instance = _getInstance(m, _case.createParams), _test = _case.test ; // Allow for any initialization work that needs to happen before // calling the method _Uize.isFunction(_testParamsInitialize) && _testParamsInitialize.call(m, _instance) ; _Uize.isFunction(_initializeFunc) && _initializeFunc.call(m, _instance) ; // set initial state properties // this isn't done on construction in case spies need to be set // with initialize functions _instance.set(_case.instanceProperties); return _Uize.isFunction(_test) ? _test.call(m, _continue) : ( function() { // Call method w/ params var _returnValue = _instance[_methodName].apply(_instance, _methodParams); // If expected parameter, than compare the returnValue // otherwise call the expect function return 'expected' in _case ? m.expect(_expected, _returnValue) : _case.expectFunc.call(m, _returnValue, _continue) ; } ) () ; } }; } ) }, _testParams.testProperties ) ); /*? Static Methods Uize.Test.Class.instanceMethodTest . SYNTAX .................................................................. testCLASS = Uize.Test.Class.instanceMethodTest ( paramsOBJ ); .................................................................. paramsOBJ . methodName . cases . title . params . instanceProperties . expected . expectFunc . initialize . createParams Optional parameters to pass to the =create= function (that override =createParams= for the =testParamsObBJ=). instanceProperties . initialize . title optional create An alternative function for creating a instance that would be different than just calling the constructor. createParams Optional parameters to pass to the =create= function. testProperties . EXAMPLE ....... Uize.Test.Class.instanceMethodTest ( { methodName:'getCurve', cases:[ { params:['position'], expected:true } ] } ); ...... NOTES - see the related =Uize.Test.Class.instanceMethodsTest= static method */ }, instanceMethodsTest:function(_instanceMethodsTests) { return _makeMultipleDeclarativeCasesTest.call( this, 'Instance Method Tests', _instanceMethodsTests, this.instanceMethodTest ); /*? Static Methods Uize.Test.Class.instanceMethodsTest . SYNTAX .................................................................. testCLASS = Uize.Test.Class.instanceMethodsTest ( instanceMethodsTestsARRAYorOBJ ); .................................................................. instanceMethodsTestsARRAYorOBJ See =Uize.Test.Class.instanceMethodTest= static method for the structure for each set of instance method tests. EXAMPLE ....... Uize.Test.Class.instanceMethodsTest ( [ { methodName:'getCurve', cases:[ ] }, { methodName:'getDialogProperties', cases:[ ] } ] ); ...... NOTES - see the related =Uize.Test.Class.instanceMethodTest= static method */ }, getInstance:function(_instanceProperties) { return new (this.getModule()) (_instanceProperties); /*? Static Methods Uize.Test.Class.getInstance Gets an instantiation of class defined by the =moduleToTest= state property. */ }, getModule:function() { return _Uize.getModuleByName(this.get('moduleToTest')); /*? Static Methods Uize.Test.Class.getModule Gets a reference to the class defined by the =moduleToTest= state property. */ }, makeDeclarativeCasesTest:_makeDeclarativeCasesTest, /*? Static Methods Uize.Test.Class.makeDeclarativeCasesTest . SYNTAX .................................................................. testCLASS = Uize.Test.Class.makeDeclarativeCasesTest ( testTitleSTR, casesARRAY, testFUNC, testPropertiesOBJ, caseTestPropertiesOBJ ); .................................................................. NOTES - see the related =Uize.Test.Class.makeMultipleDeclarativeCasesTest= static method */ makeDeclarativeCasesPropertyTest:_makeDeclarativeCasesPropertyTest, /*? Static Methods Uize.Test.Class.makeDeclarativeCasesPropertyTest . SYNTAX .................................................................. testCLASS = Uize.Test.Class.makeDeclarativeCasesPropertyTest ( testTitleSTR, testParamsOBJ ); .................................................................. NOTES - see the related =Uize.Test.Class.makeDeclarativeCasesTest= and =Uize.Test.Class.makeMultipleDeclarativeCasesTest= static methods */ makeMultipleDeclarativeCasesTest:_makeMultipleDeclarativeCasesTest, /*? Static Methods Uize.Test.Class.makeMultipleDeclarativeCasesTest . SYNTAX .................................................................. testCLASS = Uize.Test.Class.makeMultipleDeclarativeCasesTest ( testTitleSTR, makeTestFUNC, casesARRAY ); .................................................................. NOTES - see the related and =Uize.Test.Class.makeDeclarativeCasesPropertyTest= =Uize.Test.Class.makeDeclarativeCasesTest= static methods */ moduleToTest:function(_moduleToTest) { this.set({ title:'Test for ' + _moduleToTest, _moduleToTest:_moduleToTest }); }, propertyConformerTest:function(_testParams) { return _makeDeclarativeCasesPropertyTest.call( this, 'PROPERTY CONFORMER TEST', _testParams ); /*? Static Methods Uize.Test.Class.propertyConformerTest . SYNTAX .................................................................. testCLASS = Uize.Test.Class.propertyConformerTest ( testParamsOBJ ); .................................................................. testParamsOBJ . propertyName . cases . title The title of the test case instanceProperties Properties to set on instance to cause derivation expected The expected derived value for the test case instanceProperties . testProperties . caseTestProperties . EXAMPLE ....... Uize.Test.Class.propertyConformerTest ( { propertyName:'listName', cases:[ { title:'Caps are lowercase', instanceProperties:{listName:'FOO'}, expected:'foo' }, { title:'Mixed case is lowercase', instanceProperties:{listName:'FoO'}, expected:'foo' }, { title:'Lower case is still lowercase', instanceProperties:{listName:'foo'}, expected:'foo' ] ] } ); ...... NOTES - see the related =Uize.Test.Class.propertyConformersTest= static method */ }, propertyConformersTest:function(_propertyConformerTests) { return _makeMultipleDeclarativeCasesTest.call( this, 'Property Conformer Tests', _propertyConformerTests, this.propertyConformerTest ); /*? Static Methods Uize.Test.Class.propertyConformersTest . SYNTAX .................................................................. testCLASS = Uize.Test.Class.propertyConformersTest ( propertyConformersTestARRAYorOBJ ); .................................................................. propertyConformersTestARRAYorOBJ See =Uize.Test.Class.propertyConformerTest= static method for the structure for each set of property conformer tests. EXAMPLE ....... Uize.Test.Class.propertyConformersTest ( [ { propertyName:'listName', cases:[ ] } .. ] ); ...... NOTES - see the related =Uize.Test.Class.propertyConformerTest= static method */ }, requiredModulesTest:function() { return _superclass_requiredModulesTest.call(this, this.get('moduleToTest')) } }, instanceMethods:{ setInstance:function(_param1, _param2) { var m = this, _instance = _Uize.isFunction(_param1) ? _param1.apply(m, _param2) : m.Class.getInstance(_param1) ; m.set({_instance:_instance}); return _instance; } }, stateProperties:{ _instance:'instance', _moduleToTest:'moduleToTest' } }); } });