Commit 0ddaa95d by Hugo Häggmark

Added reducerFactory and tests

parent 62341ffe
......@@ -11,7 +11,7 @@ interface Dummy {
b: boolean;
}
const setup = payload => {
const setup = (payload: Dummy) => {
resetAllActionCreatorTypes();
const actionCreator = actionCreatorFactory<Dummy>('dummy').create();
const result = actionCreator(payload);
......
import { reducerFactory } from './reducerFactory';
import { actionCreatorFactory, GrafanaAction } from './actionCreatorFactory';
interface DummyReducerState {
n: number;
s: string;
b: boolean;
o: {
n: number;
s: string;
b: boolean;
};
}
const dummyReducerIntialState: DummyReducerState = {
n: 1,
s: 'One',
b: true,
o: {
n: 2,
s: 'two',
b: false,
},
};
const dummyActionCreator = actionCreatorFactory<DummyReducerState>('dummy').create();
const dummyReducer = reducerFactory(dummyReducerIntialState)
.addHandler({
creator: dummyActionCreator,
handler: ({ state, action }) => {
return { ...state, ...action.payload };
},
})
.create();
describe('reducerFactory', () => {
describe('given it is created with a defined handler', () => {
describe('when reducer is called with no state', () => {
describe('and with an action that the handler can not handle', () => {
it('then the resulting state should be intial state', () => {
const result = dummyReducer(undefined as DummyReducerState, {} as GrafanaAction<any>);
expect(result).toEqual(dummyReducerIntialState);
});
});
describe('and with an action that the handler can handle', () => {
it('then the resulting state should correct', () => {
const payload = { n: 10, s: 'ten', b: false, o: { n: 20, s: 'twenty', b: true } };
const result = dummyReducer(undefined as DummyReducerState, dummyActionCreator(payload));
expect(result).toEqual(payload);
});
});
});
describe('when reducer is called with a state', () => {
describe('and with an action that the handler can not handle', () => {
it('then the resulting state should be intial state', () => {
const result = dummyReducer(dummyReducerIntialState, {} as GrafanaAction<any>);
expect(result).toEqual(dummyReducerIntialState);
});
});
describe('and with an action that the handler can handle', () => {
it('then the resulting state should correct', () => {
const payload = { n: 10, s: 'ten', b: false, o: { n: 20, s: 'twenty', b: true } };
const result = dummyReducer(dummyReducerIntialState, dummyActionCreator(payload));
expect(result).toEqual(payload);
});
});
});
});
describe('given a handler is added', () => {
describe('when a handler with the same creator is added', () => {
it('then is should throw', () => {
const faultyReducer = reducerFactory(dummyReducerIntialState).addHandler({
creator: dummyActionCreator,
handler: ({ state, action }) => {
return { ...state, ...action.payload };
},
});
expect(() => {
faultyReducer.addHandler({
creator: dummyActionCreator,
handler: ({ state }) => {
return state;
},
});
}).toThrow();
});
});
});
});
import { GrafanaAction, GrafanaActionCreator } from './actionCreatorFactory';
import { Reducer } from 'redux';
export interface ActionHandler<State, Payload> {
state: State;
action: GrafanaAction<Payload>;
}
export interface ActionHandlerConfig<State, Payload> {
creator: GrafanaActionCreator<Payload>;
handler: (handler: ActionHandler<State, Payload>) => State;
}
export interface AddActionHandler<State> {
addHandler: <Payload>(config: ActionHandlerConfig<State, Payload>) => CreateReducer<State>;
}
export interface CreateReducer<State> extends AddActionHandler<State> {
create: () => Reducer<State, GrafanaAction<any>>;
}
export const reducerFactory = <State>(initialState: State): AddActionHandler<State> => {
const allHandlerConfigs: Array<ActionHandlerConfig<State, any>> = [];
const addHandler = <Payload>(config: ActionHandlerConfig<State, Payload>): CreateReducer<State> => {
if (allHandlerConfigs.some(c => c.creator.type === config.creator.type)) {
throw new Error(`There is already a handlers defined with the type ${config.creator.type}`);
}
allHandlerConfigs.push(config);
return instance;
};
const create = (): Reducer<State, GrafanaAction<any>> => {
const reducer: Reducer<State, GrafanaAction<any>> = (state: State = initialState, action: GrafanaAction<any>) => {
const validHandlers = allHandlerConfigs
.filter(config => config.creator.type === action.type)
.map(config => config.handler);
return validHandlers.reduce((currentState, handler) => {
return handler({ state: currentState, action });
}, state || initialState);
};
return reducer;
};
const instance: CreateReducer<State> = {
addHandler,
create,
};
return instance;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment