Remove redux-promise-middleware (#1022)

* Use shapeshift for all swaps.

* Replace existing redux-promise-middleware based CCRequest action with saga based action.

* Remove module from package.json, store middleware, webpack_config.

* fix snapshot

* Add return typing

* Add test for saga
This commit is contained in:
Daniel Ternyak 2018-02-07 17:59:55 -06:00 committed by GitHub
parent 6d041ba581
commit e7f88a6a0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 73 additions and 39 deletions

View File

@ -1,12 +1,12 @@
import * as interfaces from './actionTypes'; import * as interfaces from './actionTypes';
import { TypeKeys } from './constants'; import { TypeKeys } from './constants';
import { fetchRates, CCResponse } from './actionPayloads'; import { CCResponse } from 'api/rates';
export type TFetchCCRates = typeof fetchCCRates; export type TFetchCCRatesRequested = typeof fetchCCRatesRequested;
export function fetchCCRates(symbols: string[] = []): interfaces.FetchCCRates { export function fetchCCRatesRequested(symbols: string[] = []): interfaces.FetchCCRatesRequested {
return { return {
type: TypeKeys.RATES_FETCH_CC, type: TypeKeys.RATES_FETCH_CC_REQUESTED,
payload: fetchRates(symbols) payload: symbols
}; };
} }

View File

@ -1,9 +1,9 @@
import { TypeKeys } from './constants'; import { TypeKeys } from './constants';
import { CCResponse } from './actionPayloads'; import { CCResponse } from 'api/rates';
export interface FetchCCRates { export interface FetchCCRatesRequested {
type: TypeKeys.RATES_FETCH_CC; type: TypeKeys.RATES_FETCH_CC_REQUESTED;
payload: Promise<CCResponse>; payload: string[];
} }
/*** Set rates ***/ /*** Set rates ***/
@ -17,4 +17,4 @@ export interface FetchCCRatesFailed {
} }
/*** Union Type ***/ /*** Union Type ***/
export type RatesAction = FetchCCRates | FetchCCRatesSucceeded | FetchCCRatesFailed; export type RatesAction = FetchCCRatesRequested | FetchCCRatesSucceeded | FetchCCRatesFailed;

View File

@ -1,5 +1,5 @@
export enum TypeKeys { export enum TypeKeys {
RATES_FETCH_CC = 'RATES_FETCH_CC', RATES_FETCH_CC_REQUESTED = 'RATES_FETCH_CC_REQUESTED',
RATES_FETCH_CC_FAILED = 'RATES_FETCH_CC_FAILED', RATES_FETCH_CC_FAILED = 'RATES_FETCH_CC_FAILED',
RATES_FETCH_CC_SUCCEEDED = 'RATES_FETCH_CC_SUCCEEDED' RATES_FETCH_CC_SUCCEEDED = 'RATES_FETCH_CC_SUCCEEDED'
} }

View File

@ -1,3 +1,2 @@
export * from './actionCreators'; export * from './actionCreators';
export * from './actionTypes'; export * from './actionTypes';
export * from './actionPayloads';

View File

@ -2,7 +2,8 @@ import React from 'react';
import translate from 'translations'; import translate from 'translations';
import { UnitDisplay, Spinner } from 'components/ui'; import { UnitDisplay, Spinner } from 'components/ui';
import Select from 'react-select'; import Select from 'react-select';
import { TFetchCCRates, fetchCCRates, rateSymbols } from 'actions/rates'; import { TFetchCCRatesRequested, fetchCCRatesRequested } from 'actions/rates';
import { rateSymbols } from 'api/rates';
import { chain, flatMap } from 'lodash'; import { chain, flatMap } from 'lodash';
import { TokenBalance, getShownTokenBalances } from 'selectors/wallet'; import { TokenBalance, getShownTokenBalances } from 'selectors/wallet';
import { Balance } from 'libs/wallet'; import { Balance } from 'libs/wallet';
@ -43,7 +44,7 @@ interface StateProps {
} }
interface DispatchProps { interface DispatchProps {
fetchCCRates: TFetchCCRates; fetchCCRates: TFetchCCRatesRequested;
} }
type Props = StateProps & DispatchProps; type Props = StateProps & DispatchProps;
@ -266,4 +267,4 @@ function mapStateToProps(state: AppState): StateProps {
}; };
} }
export default connect(mapStateToProps, { fetchCCRates })(EquivalentValues); export default connect(mapStateToProps, { fetchCCRates: fetchCCRatesRequested })(EquivalentValues);

View File

@ -12,7 +12,7 @@ import {
reset, reset,
TReset TReset
} from 'actions/transaction'; } from 'actions/transaction';
import { fetchCCRates, TFetchCCRates } from 'actions/rates'; import { fetchCCRatesRequested, TFetchCCRatesRequested } from 'actions/rates';
import { getNetworkConfig, getOffline } from 'selectors/config'; import { getNetworkConfig, getOffline } from 'selectors/config';
import { AppState } from 'reducers'; import { AppState } from 'reducers';
import { Units } from 'libs/units'; import { Units } from 'libs/units';
@ -32,7 +32,7 @@ interface StateProps {
interface DispatchProps { interface DispatchProps {
inputGasPrice: TInputGasPrice; inputGasPrice: TInputGasPrice;
inputGasPriceIntent: TInputGasPriceIntent; inputGasPriceIntent: TInputGasPriceIntent;
fetchCCRates: TFetchCCRates; fetchCCRates: TFetchCCRatesRequested;
getNonceRequested: TGetNonceRequested; getNonceRequested: TGetNonceRequested;
reset: TReset; reset: TReset;
} }
@ -144,7 +144,7 @@ function mapStateToProps(state: AppState): StateProps {
export default connect(mapStateToProps, { export default connect(mapStateToProps, {
inputGasPrice, inputGasPrice,
inputGasPriceIntent, inputGasPriceIntent,
fetchCCRates, fetchCCRates: fetchCCRatesRequested,
getNonceRequested, getNonceRequested,
reset reset
})(TXMetaDataPanel); })(TXMetaDataPanel);

View File

@ -1,4 +1,5 @@
import { FetchCCRatesSucceeded, RatesAction, CCResponse } from 'actions/rates'; import { FetchCCRatesSucceeded, RatesAction } from 'actions/rates';
import { CCResponse } from 'api/rates';
import { TypeKeys } from 'actions/rates/constants'; import { TypeKeys } from 'actions/rates/constants';
// SYMBOL -> PRICE TO BUY 1 ETH // SYMBOL -> PRICE TO BUY 1 ETH

View File

@ -1,6 +1,7 @@
import configSaga from './config'; import configSaga from './config';
import deterministicWallets from './deterministicWallets'; import deterministicWallets from './deterministicWallets';
import notifications from './notifications'; import notifications from './notifications';
import rates from './rates';
import { import {
swapTimerSaga, swapTimerSaga,
pollBityOrderStatusSaga, pollBityOrderStatusSaga,
@ -31,5 +32,6 @@ export default {
wallet, wallet,
transaction, transaction,
deterministicWallets, deterministicWallets,
swapProviderSaga swapProviderSaga,
rates
}; };

19
common/sagas/rates.ts Normal file
View File

@ -0,0 +1,19 @@
import { fetchCCRatesSucceeded, fetchCCRatesFailed, FetchCCRatesRequested } from 'actions/rates';
import { SagaIterator } from 'redux-saga';
import { call, put, takeLatest } from 'redux-saga/effects';
import { fetchRates, CCResponse } from 'api/rates';
import { TypeKeys } from 'actions/rates/constants';
export function* fetchRatesSaga(action: FetchCCRatesRequested): SagaIterator {
try {
const rates: CCResponse = yield call(fetchRates, action.payload);
yield put(fetchCCRatesSucceeded(rates));
} catch (e) {
yield put(fetchCCRatesFailed());
return;
}
}
export default function* ratesSaga(): SagaIterator {
yield takeLatest(TypeKeys.RATES_FETCH_CC_REQUESTED, fetchRatesSaga);
}

View File

@ -12,7 +12,6 @@ import { createLogger } from 'redux-logger';
import createSagaMiddleware from 'redux-saga'; import createSagaMiddleware from 'redux-saga';
import { loadStatePropertyOrEmptyObject, saveState } from 'utils/localStorage'; import { loadStatePropertyOrEmptyObject, saveState } from 'utils/localStorage';
import RootReducer, { AppState } from './reducers'; import RootReducer, { AppState } from './reducers';
import promiseMiddleware from 'redux-promise-middleware';
import { getNodeConfigFromId } from 'utils/node'; import { getNodeConfigFromId } from 'utils/node';
import { getNetworkConfigFromId } from 'utils/network'; import { getNetworkConfigFromId } from 'utils/network';
import { dedupeCustomTokens } from 'utils/tokens'; import { dedupeCustomTokens } from 'utils/tokens';
@ -23,27 +22,15 @@ const configureStore = () => {
collapsed: true collapsed: true
}); });
const sagaMiddleware = createSagaMiddleware(); const sagaMiddleware = createSagaMiddleware();
const reduxPromiseMiddleWare = promiseMiddleware({
promiseTypeSuffixes: ['REQUESTED', 'SUCCEEDED', 'FAILED']
});
let middleware; let middleware;
let store; let store;
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
middleware = composeWithDevTools( middleware = composeWithDevTools(
applyMiddleware( applyMiddleware(sagaMiddleware, logger, routerMiddleware(history as any))
sagaMiddleware,
logger,
reduxPromiseMiddleWare,
routerMiddleware(history as any)
)
); );
} else { } else {
middleware = applyMiddleware( middleware = applyMiddleware(sagaMiddleware, routerMiddleware(history as any));
sagaMiddleware,
reduxPromiseMiddleWare,
routerMiddleware(history as any)
);
} }
const localSwapState = loadStatePropertyOrEmptyObject<SwapState>('swap'); const localSwapState = loadStatePropertyOrEmptyObject<SwapState>('swap');

View File

@ -45,7 +45,6 @@
"react-transition-group": "2.2.1", "react-transition-group": "2.2.1",
"redux": "3.7.2", "redux": "3.7.2",
"redux-logger": "3.0.6", "redux-logger": "3.0.6",
"redux-promise-middleware": "4.4.2",
"redux-saga": "0.16.0", "redux-saga": "0.16.0",
"scryptsy": "2.0.0", "scryptsy": "2.0.0",
"uuid": "3.2.1", "uuid": "3.2.1",
@ -68,7 +67,6 @@
"@types/react-router-redux": "5.0.11", "@types/react-router-redux": "5.0.11",
"@types/react-select": "1.2.0", "@types/react-select": "1.2.0",
"@types/redux-logger": "3.0.5", "@types/redux-logger": "3.0.5",
"@types/redux-promise-middleware": "0.0.9",
"@types/uuid": "3.4.3", "@types/uuid": "3.4.3",
"@types/webpack-env": "1.13.4", "@types/webpack-env": "1.13.4",
"@types/zxcvbn": "4.4.0", "@types/zxcvbn": "4.4.0",

View File

@ -1,9 +1,10 @@
import { rates, INITIAL_STATE } from 'reducers/rates'; import { rates, INITIAL_STATE } from 'reducers/rates';
import * as ratesActions from 'actions/rates'; import * as ratesActions from 'actions/rates';
import { CCResponse } from 'api/rates';
describe('rates reducer', () => { describe('rates reducer', () => {
it('should handle RATES_FETCH_CC_SUCCEEDED', () => { it('should handle RATES_FETCH_CC_SUCCEEDED', () => {
const fakeCCResp: ratesActions.CCResponse = { const fakeCCResp: CCResponse = {
ETH: { ETH: {
USD: 0, USD: 0,
BTC: 1, BTC: 1,

27
spec/sagas/rates.spec.ts Normal file
View File

@ -0,0 +1,27 @@
import { fetchRatesSaga } from 'sagas/rates';
import { call, put } from 'redux-saga/effects';
import { fetchCCRatesSucceeded, fetchCCRatesFailed, fetchCCRatesRequested } from 'actions/rates';
import { fetchRates } from 'api/rates';
describe('fetch rates saga success', () => {
const saga = fetchRatesSaga(fetchCCRatesRequested());
it('should fetch the rates', () => {
expect(saga.next().value).toEqual(call(fetchRates, []));
});
it('should dispatch a success action', () => {
expect(saga.next({}).value).toEqual(put(fetchCCRatesSucceeded({})));
});
it('should be done', () => {
expect(saga.next().done).toEqual(true);
});
});
describe('fetch rates saga failure', () => {
const saga = fetchRatesSaga(fetchCCRatesRequested());
it('it should throw and dispatch a failure action', () => {
saga.next();
expect(saga.throw!().value).toEqual(put(fetchCCRatesFailed()));
});
it('should be done', () => {
expect(saga.next().done).toEqual(true);
});
});

View File

@ -66,7 +66,6 @@ module.exports = {
'react-transition-group', 'react-transition-group',
'redux', 'redux',
'redux-logger', 'redux-logger',
'redux-promise-middleware',
'redux-saga', 'redux-saga',
'scryptsy', 'scryptsy',
'uuid', 'uuid',