Skip to content

Commit c8d8a49

Browse files
committed
fix(dev-mode): warn if non-functions are passed to createReducer etc.
fix #4
1 parent b7746cc commit c8d8a49

8 files changed

+115
-2
lines changed

.eslintrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
{
22
"extends": [
33
"@jedwards1211/eslint-config", "@jedwards1211/eslint-config-flow"
4-
]
4+
],
5+
"globals": {
6+
"process": false
7+
}
58
}

src/checkForNonFunctions.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import every from 'lodash.every'
2+
3+
/* global console */
4+
5+
export default function checkForNotFunctions(collection, name) {
6+
if (!every(collection, r => r instanceof Function)) {
7+
const error = new Error(name + ' should all be functions')
8+
console.error(error.stack) // eslint-disable-line no-console
9+
}
10+
}
11+

src/composeMiddleware.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import every from 'lodash.every'
22
import forEach from 'lodash.foreach'
33
import mapValues from 'lodash.mapvalues'
44
import createMiddleware from './createMiddleware'
5+
import checkForNonFunctions from './checkForNonFunctions'
56

67
export default function composeMiddleware(...middlewares) {
78
if (middlewares.length === 0) return store => dispatch => dispatch
89
if (middlewares.length === 1) return middlewares[0]
910

11+
if (process.env.NODE_ENV !== 'production') checkForNonFunctions(middlewares, 'middlewares')
12+
1013
if (every(middlewares, middleware => middleware.actionHandlers)) {
1114
// regroup all the action handlers in the middlewares by action type.
1215
let actionHandlers = {}

src/composeReducers.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import every from 'lodash.every'
33
import forEach from 'lodash.foreach'
44
import mapValues from 'lodash.mapvalues'
55
import createReducer from './createReducer'
6+
import checkForNonFunctions from './checkForNonFunctions'
67

78
export default function composeReducers(...reducers) {
89
if (reducers.length === 0) return state => state
910
if (reducers.length === 1) return reducers[0]
1011

12+
if (process.env.NODE_ENV !== 'production') checkForNonFunctions(reducers, 'reducers')
13+
1114
// if all reducers have actionHandlers maps, merge the maps using composeReducers
1215
if (every(reducers, reducer => reducer.actionHandlers instanceof Object)) {
1316
let actionHandlers = {}

src/createMiddleware.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
import checkForNonFunctions from './checkForNonFunctions'
2+
13
export default function createMiddleware(actionHandlers) {
4+
if (process.env.NODE_ENV !== 'production') checkForNonFunctions(actionHandlers, 'actionHandlers')
5+
26
const result = store => next => action => {
37
const handler = actionHandlers[action.type]
48
if (!handler) return next(action)

src/createPluggableMiddleware.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import memoize from 'lodash.memoize'
2+
import checkForNonFunctions from './checkForNonFunctions'
23

34
/**
45
* This is used for hot reloading redux middleware.
@@ -9,10 +10,15 @@ import memoize from 'lodash.memoize'
910
* hmrMiddleware.replaceMiddleware(myNewMiddleware);
1011
*/
1112
export default function createPluggableMiddleware(middleware) {
13+
if (process.env.NODE_ENV !== 'production') checkForNonFunctions(middleware, 'middleware')
14+
1215
const result = store => next => {
1316
const dispatch = memoize(middleware => middleware ? middleware(store)(next) : next)
1417
return action => dispatch(middleware)(action)
1518
}
16-
result.replaceMiddleware = nextMiddleware => middleware = nextMiddleware
19+
result.replaceMiddleware = nextMiddleware => {
20+
if (process.env.NODE_ENV !== 'production') checkForNonFunctions(nextMiddleware, 'nextMiddleware')
21+
middleware = nextMiddleware
22+
}
1723
return result
1824
}

src/createReducer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import size from 'lodash.size'
2+
import checkForNonFunctions from './checkForNonFunctions'
23

34
export default function createReducer(initialState, actionHandlers) {
45
if (arguments.length === 1) {
56
actionHandlers = initialState
67
initialState = undefined
78
}
89

10+
if (process.env.NODE_ENV !== 'production') checkForNonFunctions(actionHandlers, 'actionHandlers')
11+
912
let result
1013
if (size(actionHandlers)) {
1114
result = (state = initialState, action) => {

test/devWarningTest.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import {expect} from 'chai'
2+
import sinon from 'sinon'
3+
import createReducer from '../src/createReducer'
4+
import composeReducers from '../src/composeReducers'
5+
import createMiddleware from '../src/createMiddleware'
6+
import composeMiddleware from '../src/composeMiddleware'
7+
import createPluggableMiddleware from '../src/createPluggableMiddleware'
8+
9+
/* eslint-disable no-console */
10+
/* eslint-env node */
11+
12+
describe('dev mode warnings', () => {
13+
let origNodeEnv
14+
before(() => {
15+
origNodeEnv = process.env.NODE_ENV
16+
process.env.NODE_ENV = ''
17+
})
18+
after(() => process.env.NODE_ENV = origNodeEnv)
19+
beforeEach(() => {
20+
sinon.spy(console, 'error')
21+
})
22+
afterEach(() => {
23+
console.error.restore()
24+
})
25+
describe('createReducer', () => {
26+
it('warns if any actionHandlers are not functions', () => {
27+
createReducer({hello: 'world'})
28+
expect(console.error.called).to.be.true
29+
})
30+
it("doesn't warn if all actionHandlers are functions", () => {
31+
createReducer({hello: () => 'world'})
32+
expect(console.error.called).to.be.false
33+
})
34+
})
35+
describe('composeReducers', () => {
36+
it('warns if any reducers are not functions', () => {
37+
composeReducers(() => {}, 'hello')
38+
expect(console.error.called).to.be.true
39+
})
40+
it("doesn't warn if all actionHandlers are functions", () => {
41+
composeReducers(() => {})
42+
expect(console.error.called).to.be.false
43+
})
44+
})
45+
describe('createMiddleware', () => {
46+
it('warns if any actionHandlers are not functions', () => {
47+
createMiddleware({hello: 'world'})
48+
expect(console.error.called).to.be.true
49+
})
50+
it("doesn't warn if all actionHandlers are functions", () => {
51+
createMiddleware({hello: () => 'world'})
52+
expect(console.error.called).to.be.false
53+
})
54+
})
55+
describe('composeMiddleware', () => {
56+
it('warns if any reducers are not functions', () => {
57+
composeMiddleware(() => {}, 'hello')
58+
expect(console.error.called).to.be.true
59+
})
60+
it("doesn't warn if all actionHandlers are functions", () => {
61+
composeMiddleware(() => {})
62+
expect(console.error.called).to.be.false
63+
})
64+
})
65+
describe('createPluggableMiddleware', () => {
66+
it('warns if any reducers are not functions', () => {
67+
const middleware = createPluggableMiddleware('hello')
68+
expect(console.error.called).to.be.true
69+
console.error.reset()
70+
middleware.replaceMiddleware('world')
71+
expect(console.error.called).to.be.true
72+
})
73+
it("doesn't warn if all actionHandlers are functions", () => {
74+
const middleware = createPluggableMiddleware(() => {})
75+
expect(console.error.called).to.be.false
76+
middleware.replaceMiddleware(() => () => () => 'world')
77+
expect(console.error.called).to.be.false
78+
})
79+
})
80+
})

0 commit comments

Comments
 (0)