Skip to content

Commit

Permalink
Require type to be specified on actions
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Martinez authored and gaearon committed Sep 12, 2015
1 parent f6e0723 commit 71393b7
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 15 deletions.
4 changes: 4 additions & 0 deletions src/createStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ export default function createStore(reducer, initialState) {
throw new Error('Actions must be plain objects. Use custom middleware for async actions.');
}

if (!action.type) {
throw new Error('Actions must specify a `type`.');
}

if (isDispatching) {
throw new Error('Reducers may not dispatch actions.');
}
Expand Down
35 changes: 21 additions & 14 deletions test/createStore.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import expect from 'expect';
import { createStore, combineReducers } from '../src/index';
import { addTodo, dispatchInMiddle, throwError } from './helpers/actionCreators';
import { addTodo, dispatchInMiddle, throwError, unknownAction } from './helpers/actionCreators';
import * as reducers from './helpers/reducers';

describe('createStore', () => {
Expand Down Expand Up @@ -48,7 +48,7 @@ describe('createStore', () => {
const store = createStore(reducers.todos);
expect(store.getState()).toEqual([]);

store.dispatch({});
store.dispatch(unknownAction());
expect(store.getState()).toEqual([]);

store.dispatch(addTodo('Hello'));
Expand Down Expand Up @@ -77,7 +77,7 @@ describe('createStore', () => {
text: 'Hello'
}]);

store.dispatch({});
store.dispatch(unknownAction());
expect(store.getState()).toEqual([{
id: 1,
text: 'Hello'
Expand Down Expand Up @@ -160,43 +160,43 @@ describe('createStore', () => {
const listenerB = expect.createSpy(() => {});

let unsubscribeA = store.subscribe(listenerA);
store.dispatch({});
store.dispatch(unknownAction());
expect(listenerA.calls.length).toBe(1);
expect(listenerB.calls.length).toBe(0);

store.dispatch({});
store.dispatch(unknownAction());
expect(listenerA.calls.length).toBe(2);
expect(listenerB.calls.length).toBe(0);

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

store.dispatch({});
store.dispatch(unknownAction());
expect(listenerA.calls.length).toBe(3);
expect(listenerB.calls.length).toBe(1);

unsubscribeA();
expect(listenerA.calls.length).toBe(3);
expect(listenerB.calls.length).toBe(1);

store.dispatch({});
store.dispatch(unknownAction());
expect(listenerA.calls.length).toBe(3);
expect(listenerB.calls.length).toBe(2);

unsubscribeB();
expect(listenerA.calls.length).toBe(3);
expect(listenerB.calls.length).toBe(2);

store.dispatch({});
store.dispatch(unknownAction());
expect(listenerA.calls.length).toBe(3);
expect(listenerB.calls.length).toBe(2);

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

store.dispatch({});
store.dispatch(unknownAction());
expect(listenerA.calls.length).toBe(4);
expect(listenerB.calls.length).toBe(2);
});
Expand All @@ -214,8 +214,8 @@ describe('createStore', () => {
});
store.subscribe(listenerC);

store.dispatch({});
store.dispatch({});
store.dispatch(unknownAction());
store.dispatch(unknownAction());

expect(listenerA.calls.length).toBe(2);
expect(listenerB.calls.length).toBe(1);
Expand All @@ -237,7 +237,7 @@ describe('createStore', () => {
it('should only accept plain object actions', () => {
const store = createStore(reducers.todos);
expect(() =>
store.dispatch({})
store.dispatch(unknownAction())
).toNotThrow();

function AwesomeMap() { }
Expand Down Expand Up @@ -277,7 +277,7 @@ describe('createStore', () => {
const store = createStore(reducers.dispatchInTheMiddleOfReducer);

expect(() =>
store.dispatch(dispatchInMiddle(store.dispatch.bind(store, {})))
store.dispatch(dispatchInMiddle(store.dispatch.bind(store, unknownAction())))
).toThrow(/may not dispatch/);
});

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

expect(() =>
store.dispatch({})
store.dispatch(unknownAction())
).toNotThrow();
});

it('should only accept actions with a `type`', () => {
const store = createStore(reducers.todos);
expect(() =>
store.dispatch({})
).toThrow(/Actions must specify a `type`/);
});
});
8 changes: 7 additions & 1 deletion test/helpers/actionCreators.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ADD_TODO, DISPATCH_IN_MIDDLE, THROW_ERROR } from './actionTypes';
import { ADD_TODO, DISPATCH_IN_MIDDLE, THROW_ERROR, UNKNOWN_ACTION } from './actionTypes';

export function addTodo(text) {
return { type: ADD_TODO, text };
Expand Down Expand Up @@ -31,3 +31,9 @@ export function throwError() {
type: THROW_ERROR
};
}

export function unknownAction() {
return {
type: UNKNOWN_ACTION
}
}
1 change: 1 addition & 0 deletions test/helpers/actionTypes.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const ADD_TODO = 'ADD_TODO';
export const DISPATCH_IN_MIDDLE = 'DISPATCH_IN_MIDDLE';
export const THROW_ERROR = 'THROW_ERROR';
export const UNKNOWN_ACTION = 'UNKNOWN_ACTION';

0 comments on commit 71393b7

Please sign in to comment.