Skip to content

Commit

Permalink
renaming action creator function and added path helper for plucking s…
Browse files Browse the repository at this point in the history
…tate
  • Loading branch information
okwolf committed Mar 19, 2017
1 parent 89ef8f7 commit 87c809f
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 28 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "erux",
"version": "0.0.7",
"version": "0.0.7-alpha.1",
"description": "Reduced Redux for great justice.",
"author": "Wolfgang Wedemeyer <wolf@okwolf.com>",
"license": "MIT",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@ const addUnderscoresBetween = (match, offset) => `${offset ? '_' : ''}${match}`;
const actionFormat = name =>
name.replace(/[A-Z]/g, addUnderscoresBetween).toUpperCase();

export default ({ store: { dispatch }, path, actions }) =>
actions &&
Object.keys(actions).reduce(
export default ({ path, reducers = {} }) =>
Object.keys(reducers).reduce(
(actionCreators, functionName) => {
const type = actionFormat(functionName);
const reducer = actions[functionName];
const reducer = reducers[functionName];
// eslint-disable-next-line fp/no-unused-expression
addActionMapping({ type, path, reducer });
return {
...actionCreators,
[functionName]: action =>
dispatch({
type,
...action
})
[functionName]: action => ({
...action,
type
})
};
},
{}
Expand Down
5 changes: 4 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export { default as enhancer } from './enhancer';
export { default as withStorePathAndActions } from './withStorePathAndActions';
export {
default as actionsWithPathAndReducers
} from './actionsWithPathAndReducers';
export { stateAtPath } from './paths';
8 changes: 8 additions & 0 deletions src/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,11 @@ export const updateStatePathWithReducer = (
})
}
: reducer(state, action);

export const stateAtPath = ({ state = {}, path }) =>
path
? stateAtPath({
state: state[nextPart(path)],
path: remainingPart(path)
})
: state;
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { assert, expect } from 'chai';
import sinon, { spy } from 'sinon';
import { enhancer, withStorePathAndActions } from '../src';
import { enhancer, actionsWithPathAndReducers } from '../src';
import createMockStore from './createMockStore';

describe('withStorePathAndActions', () => {
describe('actionsWithPathAndReducers', () => {
it('should be a function', () => {
assert.isFunction(withStorePathAndActions);
assert.isFunction(actionsWithPathAndReducers);
});
describe('when called', () => {
describe('without a store', () => {
it('should throw an error', () => {
assert.throws(() => withStorePathAndActions(), TypeError);
assert.throws(() => actionsWithPathAndReducers(), TypeError);
});
});
describe('with a store', () => {
Expand All @@ -32,8 +32,16 @@ describe('withStorePathAndActions', () => {
});
describe('and path', () => {
const path = 'state.path';
describe('and actions', () => {
const actions = {
describe('without actions', () => {
it('should return an empty object', () => {
const withAPathOnly = actionsWithPathAndReducers({
path
});
expect(withAPathOnly).to.deep.equal({});
});
});
describe('and reducers', () => {
const reducers = {
inc: ({ counter = 0 }) => ({
counter: counter + 1
}),
Expand All @@ -42,24 +50,24 @@ describe('withStorePathAndActions', () => {
}),
CapitalAction: Function.prototype
};
const withAStoreAndAPathAndActions = withStorePathAndActions({
store,
const withAPathAndReducers = actionsWithPathAndReducers({
path,
actions
reducers
});
it('should return an object of action creators', () => {
assert.isObject(withAStoreAndAPathAndActions);
assert.isObject(withAPathAndReducers);
});
describe('inc property', () => {
const { inc } = withAStoreAndAPathAndActions;
const { inc } = withAPathAndReducers;
it('should be a function', () => {
assert.isFunction(inc);
});
it('should dispatch the INC action when called', () => {
it('should create the INC action when called and handle the action when dispatched', () => {
const action = inc();
expect(action).to.deep.equal({
type: 'INC'
});
dispatch(action);
sinon.assert.alwaysCalledWithExactly(dispatch, action);
expect(store.getState()).to.deep.equal({
state: {
Expand All @@ -68,7 +76,7 @@ describe('withStorePathAndActions', () => {
}
}
});
inc();
dispatch(action);
expect(store.getState()).to.deep.equal({
state: {
path: {
Expand All @@ -79,7 +87,7 @@ describe('withStorePathAndActions', () => {
});
});
describe('incBy property', () => {
const { incBy } = withAStoreAndAPathAndActions;
const { incBy } = withAPathAndReducers;
it('should be a function', () => {
assert.isFunction(incBy);
});
Expand All @@ -89,6 +97,7 @@ describe('withStorePathAndActions', () => {
type: 'INC_BY',
by: 2
});
dispatch(action);
sinon.assert.alwaysCalledWithExactly(dispatch, action);
expect(store.getState()).to.deep.equal({
state: {
Expand All @@ -97,7 +106,7 @@ describe('withStorePathAndActions', () => {
}
}
});
incBy({ by: 3 });
dispatch(incBy({ by: 3 }));
expect(store.getState()).to.deep.equal({
state: {
path: {
Expand All @@ -108,7 +117,7 @@ describe('withStorePathAndActions', () => {
});
});
describe('CapitalAction property', () => {
const { CapitalAction } = withAStoreAndAPathAndActions;
const { CapitalAction } = withAPathAndReducers;
it('should be a function', () => {
assert.isFunction(CapitalAction);
});
Expand All @@ -117,6 +126,7 @@ describe('withStorePathAndActions', () => {
expect(action).to.deep.equal({
type: 'CAPITAL_ACTION'
});
dispatch(action);
sinon.assert.alwaysCalledWithExactly(dispatch, action);
});
});
Expand Down
54 changes: 53 additions & 1 deletion test/paths.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { assert, expect } from 'chai';
import {
nextPart,
remainingPart,
updateStatePathWithReducer
updateStatePathWithReducer,
stateAtPath
} from '../src/paths';

describe('Path utility function', () => {
Expand Down Expand Up @@ -93,5 +94,56 @@ describe('Path utility function', () => {
}
});
});
it('should merge Parent and Child state', () => {
const reducer = ({ counter = 0 }) => ({ counter: counter + 1 });
expect(
updateStatePathWithReducer({
state: {
Parent: {
Child: {}
}
},
path: 'Parent.Child',
reducer
})
).to.deep.equal({
Parent: {
Child: {
counter: 1
}
}
});
});
});
describe('stateAtPath', () => {
it('should be a function', () => {
assert.isFunction(stateAtPath);
});
it('should return same state with no path', () => {
const state = {};
expect(stateAtPath({ state })).to.deep.equal(state);
});
it('should return new object for nonexistant path', () => {
const state = {
existing: 'value'
};
expect(stateAtPath({ state, path: 'wrong.value' })).to.deep.equal({});
});
it('should return nested state with a path', () => {
const state = {
deeply: {
nested: {
values: {
here: 42
}
}
}
};
expect(
stateAtPath({ state, path: 'deeply.nested.values' })
).to.deep.equal({
here: 42
});
});
});
});

0 comments on commit 87c809f

Please sign in to comment.