Add & test createReducer

This commit is contained in:
Jerko Steiner 2019-08-01 16:35:40 +07:00
parent dca9691d7d
commit 82ec4c321a
2 changed files with 56 additions and 38 deletions

View File

@ -6,11 +6,12 @@ import bodyParser from 'body-parser'
import express from 'express' import express from 'express'
import {AddressInfo} from 'net' import {AddressInfo} from 'net'
import {Server} from 'http' import {Server} from 'http'
import {TPendingActions, TAllActions} from './types'
import {createReduxClient, createReducer} from './redux' import {createReduxClient, createReducer} from './redux'
import {createRemoteClient} from './remote' import {createRemoteClient} from './remote'
import {createStore} from '@rondo/client'
import {jsonrpc} from './express' import {jsonrpc} from './express'
import {keys} from 'ts-transformer-keys' import {keys} from 'ts-transformer-keys'
import {TPendingActions, TAllActions} from './types'
describe('createReduxClient', () => { describe('createReduxClient', () => {
@ -77,29 +78,37 @@ describe('createReduxClient', () => {
type AllActions = TAllActions<typeof client> type AllActions = TAllActions<typeof client>
const defaultState = { const defaultState = {
sum: 1, loading: 0,
error: '',
add: 0,
addStringsAsync: '',
} }
const create = createReducer('myService', defaultState) const reducer = createReducer('myService', defaultState)
<typeof client>((state, action) => { <typeof client>((state, action) => {
switch (action.method) { switch (action.method) {
case 'add': case 'add':
const r1: number = action.payload
return state
case 'addAsync': case 'addAsync':
const r2: number = action.payload
return state
case 'addStringsAsync':
const r3: string = action.payload
return state
case 'addWithContext': case 'addWithContext':
const r4: number = action.payload case 'addAsyncWithContext':
return state const r1: number = action.payload
return {
...state,
add: r1,
}
case 'addStringsAsync':
const r2: string = action.payload
return {
...state,
addStringsAsync: r2,
}
default: default:
return state return state
} }
}) })
const store = createStore({reducer})()
function handleAction(state: any, action: AllActions) { function handleAction(state: any, action: AllActions) {
if (action.type !== 'myService') { if (action.type !== 'myService') {
return return
@ -123,60 +132,56 @@ describe('createReduxClient', () => {
} }
} }
return client return {client, store}
} }
describe('action creators', () => { describe('action creators', () => {
describe('add', () => { describe('add', () => {
it('creates a redux action with type, method and status', async () => { it('creates a redux action with type, method and status', async () => {
const client = getClient() const {client, store} = getClient()
const action = client.add(3, 7) const action = client.add(3, 7)
expect(action.method).toEqual('add') expect(action.method).toEqual('add')
expect(action.type).toEqual('myService') expect(action.type).toEqual('myService')
expect(action.status).toEqual('pending') expect(action.status).toEqual('pending')
const result = await action.payload const result: number = await store.dispatch(action).payload
expect(result).toEqual(3 + 7) expect(result).toEqual(3 + 7)
// compilation test expect(store.getState().add).toEqual(10)
expect(result + 2).toEqual(12)
}) })
}) })
describe('addAsync', () => { describe('addAsync', () => {
it('creates a redux action with type, method and status', async () => { it('creates a redux action with type, method and status', async () => {
const client = getClient() const {client, store} = getClient()
const action = client.addAsync(3, 7) const action = client.addAsync(3, 7)
expect(action.method).toEqual('addAsync') expect(action.method).toEqual('addAsync')
expect(action.type).toEqual('myService') expect(action.type).toEqual('myService')
expect(action.status).toEqual('pending') expect(action.status).toEqual('pending')
const result = await action.payload const result: number = await store.dispatch(action).payload
expect(result).toEqual(3 + 7) expect(result).toEqual(3 + 7)
// compilation test expect(store.getState().add).toEqual(10)
expect(result + 2).toEqual(12)
}) })
}) })
describe('addWithContext', () => { describe('addWithContext', () => {
it('creates a redux action with type, method and status', async () => { it('creates a redux action with type, method and status', async () => {
const client = getClient() const {client, store} = getClient()
const action = client.addWithContext(3, 7) const action = client.addWithContext(3, 7)
expect(action.method).toEqual('addWithContext') expect(action.method).toEqual('addWithContext')
expect(action.type).toEqual('myService') expect(action.type).toEqual('myService')
expect(action.status).toEqual('pending') expect(action.status).toEqual('pending')
const result = await action.payload const result: number = await store.dispatch(action).payload
expect(result).toEqual(3 + 7 + 1000) expect(result).toEqual(3 + 7 + 1000)
// compilation test expect(store.getState().add).toEqual(1010)
expect(result + 2).toEqual(1012)
}) })
}) })
describe('addAsyncWithContext', () => { describe('addAsyncWithContext', () => {
it('creates a redux action with type, method and status', async () => { it('creates a redux action with type, method and status', async () => {
const client = getClient() const {client, store} = getClient()
const action = client.addAsyncWithContext(3, 7) const action = client.addAsyncWithContext(3, 7)
expect(action.method).toEqual('addAsyncWithContext') expect(action.method).toEqual('addAsyncWithContext')
expect(action.type).toEqual('myService') expect(action.type).toEqual('myService')
expect(action.status).toEqual('pending') expect(action.status).toEqual('pending')
const result = await action.payload const result: number = await store.dispatch(action).payload
expect(result).toEqual(3 + 7 + 1000) expect(result).toEqual(3 + 7 + 1000)
// compilation test expect(store.getState().add).toEqual(1010)
expect(result + 2).toEqual(1012)
}) })
}) })
}) })

View File

@ -27,25 +27,38 @@ export function createReduxClient<T, ActionType extends string>(
return service as TReduxed<T, ActionType> return service as TReduxed<T, ActionType>
} }
export const createReducer = <ActionType extends string, State>( export interface IState {
loading: number
error: string
}
export const createReducer = <ActionType extends string, State extends IState>(
actionType: ActionType, actionType: ActionType,
defaultState: State, defaultState: State,
) => <R extends IReduxed<ActionType>>( ) => <R extends IReduxed<ActionType>>(
handleAction: (state: State, action: TResolvedActions<R>) => State, handleAction: (state: State, action: TResolvedActions<R>) => State,
) => (state: State = defaultState, action?: TAllActions<R>): State => { ) => (state: State = defaultState, action: TAllActions<R>): State => {
if (!action) {
return state
}
if (action.type !== actionType) { if (action.type !== actionType) {
return state return state
} }
if (action.status === 'pending') { if (action.status === 'pending') {
// TODO handle loading return {
...state,
loading: state.loading + 1,
error: '',
}
return state return state
} }
if (action.status === 'rejected') { if (action.status === 'rejected') {
// TODO handle rejected return {
return state ...state,
loading: state.loading - 1,
error: action.payload.message,
} }
return handleAction(state, action) }
return handleAction({
...state,
loading: state.loading - 1,
error: '',
}, action)
} }