mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Added reducerFactory and tests
This commit is contained in:
parent
62341ffe56
commit
0ddaa95d0e
@ -11,7 +11,7 @@ interface Dummy {
|
|||||||
b: boolean;
|
b: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const setup = payload => {
|
const setup = (payload: Dummy) => {
|
||||||
resetAllActionCreatorTypes();
|
resetAllActionCreatorTypes();
|
||||||
const actionCreator = actionCreatorFactory<Dummy>('dummy').create();
|
const actionCreator = actionCreatorFactory<Dummy>('dummy').create();
|
||||||
const result = actionCreator(payload);
|
const result = actionCreator(payload);
|
||||||
|
99
public/app/core/redux/reducerFactory.test.ts
Normal file
99
public/app/core/redux/reducerFactory.test.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
55
public/app/core/redux/reducerFactory.ts
Normal file
55
public/app/core/redux/reducerFactory.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
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;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user