/** @class MockMethod */ export default class MockMethod { /** * @access private **/ constructor(obj, methodName) { this.excuteObjs = new Map(); // { // key:{ // arg:[], // type:'function', // excute : function(){} // } // }; this.record = { total: 0, param: {} }; this.currentParam = this.transformParamToString([]); this.excuteObjs.set(this.currentParam, new Map()); this.setup(obj, methodName); } /** * @access private **/ transformParamToString(obj) { return JSON.stringify(obj); } /** * @access private **/ setup(obj, methodName) { const that = this; const target = obj; target[methodName] = (...params) => { that.record.total++; const argString = that.transformParamToString(params); if (that.record.param[argString]) { that.record.param[argString] += 1; } else { that.record.param[argString] = 1; } const dataObj = that.excuteObjs.get(argString); if (dataObj) { const type = dataObj.get('type'); const excute = dataObj.get('excute'); if (type === 'function') { return excute.apply(dataObj, params); } else if (type === 'exception') { throw excute; } else if (type === 'return') { return excute; } } else { for (const [, info] of that.excuteObjs) { const arg = info.get('arg'); if ( arg && (arg.length === params.length) && !arg.find((v, i) => (v !== params[i] && v !== '_js_mock_anything_param')) ) { return info.get('excute'); } } } }; } /** * set parameters of should_receive. * If you use `with_param` that `and_xxx` method execute matching param. * @instance * @memberof MockMethod * @param {...anything} params - list up parameters. * @function with_param * @returns {MockMethod} * @example mock("obj").should_receive("something").with_param(1,2).and_return("1"); // obj.something(1); => not return anything // obj.something(1, 2); => "1" // You can use `mock.anything`. mock("obj").should_receive("something").with_param(1,mock.anything()).and_return("1"); // obj.something(1, 1); => "1" // obj.something(1, 2); => "1" // obj.something(1, 3); => "1" **/ with_param(...params) { this.currentParam = this.transformParamToString(params); this.excuteObjs.set(this.currentParam, (new Map()).set('arg', params)); return this; } /** * @access private **/ and_template(type, excute) { this.excuteObjs .get(this.currentParam) .set('type', type) .set('excute', excute); this.currentParam = this.transformParamToString([]); } /** * set return value when should_receive called. * @instance * @memberof MockMethod * @param {Object} returnVal - return value * @function and_return * @example mock("obj").should_receive("something").and_return("1"); // obj.something(1); => "1" // obj.something(1, 2); => "1" **/ and_return(returnVal) { this.and_template('return', returnVal); } /** * Set execution function when should_receive called. * @instance * @memberof MockMethod * @param {Function} returnFunction - execute function * @function and_function * @example mock("obj").should_receive("something").and_function(function(){ return "1"; }); // obj.something(1); => "1" // obj.something(1, 2); => "1" **/ and_function(returnFunction) { this.and_template('function', returnFunction); } /** * Set exception error when should_receive called. * @instance * @memberof MockMethod * @param {String} returnException - exception message * @function and_throw * @example mock("obj").should_receive("something").and_throw("error"); // obj.something(1); => new Error("error") // obj.something(1, 2); => new Error("error") **/ and_throw(returnException) { this.and_template('exception', returnException); } }