Skip to content

Commit 71393b7

Browse files
Daniel Martinezgaearon
Daniel Martinez
authored andcommitted
Require type to be specified on actions
1 parent f6e0723 commit 71393b7

File tree

4 files changed

+33
-15
lines changed

4 files changed

+33
-15
lines changed

src/createStore.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ export default function createStore(reducer, initialState) {
9494
throw new Error('Actions must be plain objects. Use custom middleware for async actions.');
9595
}
9696

97+
if (!action.type) {
98+
throw new Error('Actions must specify a `type`.');
99+
}
100+
97101
if (isDispatching) {
98102
throw new Error('Reducers may not dispatch actions.');
99103
}

test/createStore.spec.js

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import expect from 'expect';
22
import { createStore, combineReducers } from '../src/index';
3-
import { addTodo, dispatchInMiddle, throwError } from './helpers/actionCreators';
3+
import { addTodo, dispatchInMiddle, throwError, unknownAction } from './helpers/actionCreators';
44
import * as reducers from './helpers/reducers';
55

66
describe('createStore', () => {
@@ -48,7 +48,7 @@ describe('createStore', () => {
4848
const store = createStore(reducers.todos);
4949
expect(store.getState()).toEqual([]);
5050

51-
store.dispatch({});
51+
store.dispatch(unknownAction());
5252
expect(store.getState()).toEqual([]);
5353

5454
store.dispatch(addTodo('Hello'));
@@ -77,7 +77,7 @@ describe('createStore', () => {
7777
text: 'Hello'
7878
}]);
7979

80-
store.dispatch({});
80+
store.dispatch(unknownAction());
8181
expect(store.getState()).toEqual([{
8282
id: 1,
8383
text: 'Hello'
@@ -160,43 +160,43 @@ describe('createStore', () => {
160160
const listenerB = expect.createSpy(() => {});
161161

162162
let unsubscribeA = store.subscribe(listenerA);
163-
store.dispatch({});
163+
store.dispatch(unknownAction());
164164
expect(listenerA.calls.length).toBe(1);
165165
expect(listenerB.calls.length).toBe(0);
166166

167-
store.dispatch({});
167+
store.dispatch(unknownAction());
168168
expect(listenerA.calls.length).toBe(2);
169169
expect(listenerB.calls.length).toBe(0);
170170

171171
const unsubscribeB = store.subscribe(listenerB);
172172
expect(listenerA.calls.length).toBe(2);
173173
expect(listenerB.calls.length).toBe(0);
174174

175-
store.dispatch({});
175+
store.dispatch(unknownAction());
176176
expect(listenerA.calls.length).toBe(3);
177177
expect(listenerB.calls.length).toBe(1);
178178

179179
unsubscribeA();
180180
expect(listenerA.calls.length).toBe(3);
181181
expect(listenerB.calls.length).toBe(1);
182182

183-
store.dispatch({});
183+
store.dispatch(unknownAction());
184184
expect(listenerA.calls.length).toBe(3);
185185
expect(listenerB.calls.length).toBe(2);
186186

187187
unsubscribeB();
188188
expect(listenerA.calls.length).toBe(3);
189189
expect(listenerB.calls.length).toBe(2);
190190

191-
store.dispatch({});
191+
store.dispatch(unknownAction());
192192
expect(listenerA.calls.length).toBe(3);
193193
expect(listenerB.calls.length).toBe(2);
194194

195195
unsubscribeA = store.subscribe(listenerA);
196196
expect(listenerA.calls.length).toBe(3);
197197
expect(listenerB.calls.length).toBe(2);
198198

199-
store.dispatch({});
199+
store.dispatch(unknownAction());
200200
expect(listenerA.calls.length).toBe(4);
201201
expect(listenerB.calls.length).toBe(2);
202202
});
@@ -214,8 +214,8 @@ describe('createStore', () => {
214214
});
215215
store.subscribe(listenerC);
216216

217-
store.dispatch({});
218-
store.dispatch({});
217+
store.dispatch(unknownAction());
218+
store.dispatch(unknownAction());
219219

220220
expect(listenerA.calls.length).toBe(2);
221221
expect(listenerB.calls.length).toBe(1);
@@ -237,7 +237,7 @@ describe('createStore', () => {
237237
it('should only accept plain object actions', () => {
238238
const store = createStore(reducers.todos);
239239
expect(() =>
240-
store.dispatch({})
240+
store.dispatch(unknownAction())
241241
).toNotThrow();
242242

243243
function AwesomeMap() { }
@@ -277,7 +277,7 @@ describe('createStore', () => {
277277
const store = createStore(reducers.dispatchInTheMiddleOfReducer);
278278

279279
expect(() =>
280-
store.dispatch(dispatchInMiddle(store.dispatch.bind(store, {})))
280+
store.dispatch(dispatchInMiddle(store.dispatch.bind(store, unknownAction())))
281281
).toThrow(/may not dispatch/);
282282
});
283283

@@ -288,7 +288,14 @@ describe('createStore', () => {
288288
).toThrow();
289289

290290
expect(() =>
291-
store.dispatch({})
291+
store.dispatch(unknownAction())
292292
).toNotThrow();
293293
});
294+
295+
it('should only accept actions with a `type`', () => {
296+
const store = createStore(reducers.todos);
297+
expect(() =>
298+
store.dispatch({})
299+
).toThrow(/Actions must specify a `type`/);
300+
});
294301
});

test/helpers/actionCreators.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ADD_TODO, DISPATCH_IN_MIDDLE, THROW_ERROR } from './actionTypes';
1+
import { ADD_TODO, DISPATCH_IN_MIDDLE, THROW_ERROR, UNKNOWN_ACTION } from './actionTypes';
22

33
export function addTodo(text) {
44
return { type: ADD_TODO, text };
@@ -31,3 +31,9 @@ export function throwError() {
3131
type: THROW_ERROR
3232
};
3333
}
34+
35+
export function unknownAction() {
36+
return {
37+
type: UNKNOWN_ACTION
38+
}
39+
}

test/helpers/actionTypes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export const ADD_TODO = 'ADD_TODO';
22
export const DISPATCH_IN_MIDDLE = 'DISPATCH_IN_MIDDLE';
33
export const THROW_ERROR = 'THROW_ERROR';
4+
export const UNKNOWN_ACTION = 'UNKNOWN_ACTION';

0 commit comments

Comments
 (0)