From b3b1fe15e035f119d5e30bfe8819ee4df36dbf22 Mon Sep 17 00:00:00 2001 From: Umur Kontaci <umur@umur.io> Date: Thu, 16 Jun 2016 23:41:13 -0700 Subject: [PATCH] Add console error for ES6 instance functions in development environments --- client/boot/index.js | 3 + client/lib/wrap-es6-functions/index.js | 28 +++++++++ client/lib/wrap-es6-functions/test/index.js | 70 +++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 client/lib/wrap-es6-functions/index.js create mode 100644 client/lib/wrap-es6-functions/test/index.js diff --git a/client/boot/index.js b/client/boot/index.js index 4f6279301dbea..77d3db97d050b 100644 --- a/client/boot/index.js +++ b/client/boot/index.js @@ -1,5 +1,8 @@ // Initialize localStorage polyfill before any dependencies are loaded require( 'lib/local-storage' )(); +if ( process.env.NODE_ENV === 'development' ) { + require( 'lib/wrap-es6-functions' )(); +} /** * External dependencies diff --git a/client/lib/wrap-es6-functions/index.js b/client/lib/wrap-es6-functions/index.js new file mode 100644 index 0000000000000..0026f4afafd77 --- /dev/null +++ b/client/lib/wrap-es6-functions/index.js @@ -0,0 +1,28 @@ +import partial from 'lodash/partial'; +import isFunction from 'lodash/isFunction'; + +function wrapFnWithWarning( fn, name ) { + const consoleFn = ( console.error || console.log ).bind( console ); + return function() { + const err = new Error( `${ name } is not supported on all browsers. You must use a replacement method from lodash.` ); + consoleFn( err ); + return fn.apply( this, arguments ); + } +} + +function wrapObjectFn( obj, objectName, key ) { + if ( isFunction( obj[ key ] ) ) { + Object.defineProperty( obj, key, { value: wrapFnWithWarning( obj[ key ], `${ objectName }${ key}` ) } ); + } +} + +export default function() { + [ 'keys', 'entries', 'values', 'findIndex', 'fill', 'find' ] + .map( partial( wrapObjectFn, Array.prototype, 'Array#' ) ); + + [ 'codePointAt', 'normalize', 'repeat', 'startsWith', 'endsWith', 'includes' ] + .map( partial( wrapObjectFn, String.prototype, 'String#' ) ); + + [ 'flags' ].map( partial( wrapObjectFn, RegExp.prototype, 'RegExp#' ) ); + +} diff --git a/client/lib/wrap-es6-functions/test/index.js b/client/lib/wrap-es6-functions/test/index.js new file mode 100644 index 0000000000000..cc566a13572e0 --- /dev/null +++ b/client/lib/wrap-es6-functions/test/index.js @@ -0,0 +1,70 @@ +/** + * External Dependencies + */ +import partial from 'lodash/partial'; +import assert from 'assert'; +import isFunction from 'lodash/isFunction'; + +/** + * Internal Dependencies + */ +import { useSandbox } from 'test/helpers/use-sinon'; + + +describe( 'wrapping', () => { + let sandbox, + arrayProps = [ 'keys', 'entries', 'values', 'findIndex', 'fill', 'find' ].filter( key => isFunction( Array.prototype[ key ] ) ), + stringProps = [ 'codePointAt', 'normalize', 'repeat', 'startsWith', 'endsWith', 'includes' ].filter( key => isFunction( String.prototype[ key ] ) ), + consoleSpy, + regExpProps = [ 'flags' ].filter( key => isFunction( RegExp.prototype[ key ] ) ); + + function installSpies( props, obj ) { + props.forEach( key => { + sandbox.spy( obj, key ); + } ); + } + + function assertCall( obj, args, key ) { + it( key, () => { + if ( isFunction( obj[ key ] ) ) { + obj[ key ].apply( obj, args ); + assert( consoleSpy.calledOnce ); + } + } ) + } + + useSandbox( newSandbox => sandbox = newSandbox ); + before( () => { + consoleSpy = sandbox.stub( console, 'error' ); + installSpies( arrayProps, Array.prototype ); + installSpies( stringProps, String.prototype ); + installSpies( regExpProps, RegExp.prototype ); + + require( '../' )(); + } ); + + after( () => { + sandbox.restore(); + } ); + + beforeEach( () => { + consoleSpy.reset(); + } ); + + describe( 'Array', () => { + [ 'keys', 'entries', 'values' ].forEach( partial( assertCall, Array.prototype, [] ) ); + [ 'findIndex', 'find' ].forEach( partial( assertCall, Array.prototype, [ () => true ] ) ); + [ 'fill' ].forEach( partial( assertCall, Array.prototype, [ 1 ] ) ); + } ); + + describe( 'String', () => { + [ 'codePointAt', 'repeat' ].forEach( partial( assertCall, 'hello', [ 1 ] ) ); + [ 'startsWith', 'endsWith', 'includes' ].forEach( partial( assertCall, 'hello', [ 'a' ] ) ); + [ 'normalize' ].forEach( partial( assertCall, 'hello', [] ) ); + } ); + + describe( 'RegExp', () => { + [ 'flags' ].forEach( partial( assertCall, /a/, 'flags', [ 'g' ] ) ); + } ); + +} );