From d347b6143cfda5828e76f55a883924f64bf84057 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Fri, 8 Jun 2018 17:51:57 +0200 Subject: [PATCH] [BUGFIX beta] Throw error if run.bind receives no method This commit uses the same logic as backburner.join to know which method is being bound. Fixes #16652 --- packages/@ember/runloop/index.js | 34 ++++++++++++++++++- .../@ember/runloop/tests/run_bind_test.js | 19 +++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/@ember/runloop/index.js b/packages/@ember/runloop/index.js index fdca2d426ca..264c9f769c4 100644 --- a/packages/@ember/runloop/index.js +++ b/packages/@ember/runloop/index.js @@ -217,7 +217,39 @@ export function join() { @since 1.4.0 @public */ -export const bind = (...curried) => (...args) => join(...curried.concat(args)); +export const bind = (...curried) => { + if (!bindMethodPresent(...curried)) { + throw new Error('could not find a suitable method to bind'); + } + return (...args) => join(...curried.concat(args)); +}; + +/** + * Applies the same logic as backburner parseArgs for detecting if a method + * is actually being passed. + * + * @method bindMethodPresent + * @param {Object|Function} methodOrTarget Same as first argument for backburner.join + * @param {Function|string} methodOrArg Same as second argument for backburner.join + * @return {Boolean} whether there is a method present or not + * @private + */ +function bindMethodPresent(methodOrTarget, methodOrArg) { + let length = arguments.length; + + if (length === 0) { + return false; + } else if (length === 1) { + return typeof methodOrTarget === 'function'; + } else { + let type = typeof methodOrArg; + return ( + type === 'function' || // second argument is a function + (methodOrTarget !== null && type === 'string' && methodOrArg in methodOrTarget) || // second argument is the name of a method in first argument + typeof methodOrTarget === 'function' //first argument is a function + ); + } +} /** Begins a new RunLoop. Any deferred actions invoked after the begin will diff --git a/packages/@ember/runloop/tests/run_bind_test.js b/packages/@ember/runloop/tests/run_bind_test.js index bd04427a6c4..82c112a0203 100644 --- a/packages/@ember/runloop/tests/run_bind_test.js +++ b/packages/@ember/runloop/tests/run_bind_test.js @@ -36,5 +36,24 @@ moduleFor( asyncFunction(bind(asyncCallback, asyncCallback, 1)); } + + ['@test bind throws an error if callback is undefined'](assert) { + let assertBindThrows = (msg, ...args) => { + assert.throws( + function() { + bind(...args); + }, + /could not find a suitable method to bind/, + msg + ); + }; + assertBindThrows('without arguments'); + assertBindThrows('with one arguments that is not a function', 'myMethod'); + assertBindThrows( + 'if second parameter is not a function and not a property in first parameter', + Object.create(null), + 'myMethod' + ); + } } );