mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-01-11 03:26:14 +00:00
Add reducer tests for new redux state
This commit is contained in:
parent
8048157448
commit
dccd976043
@ -1,8 +1,8 @@
|
||||
import * as interfaces from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
|
||||
export type TToggleOfflineConfig = typeof toggleOfflineConfig;
|
||||
export function toggleOfflineConfig(): interfaces.ToggleOfflineAction {
|
||||
export type TToggleOffline = typeof toggleOffline;
|
||||
export function toggleOffline(): interfaces.ToggleOfflineAction {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_TOGGLE_OFFLINE
|
||||
};
|
||||
@ -96,7 +96,9 @@ export function setLatestBlock(payload: string): interfaces.SetLatestBlockAction
|
||||
};
|
||||
}
|
||||
|
||||
export function web3SetNode(payload: interfaces.Web3setNodeAction['payload']) {
|
||||
export function web3SetNode(
|
||||
payload: interfaces.Web3setNodeAction['payload']
|
||||
): interfaces.Web3setNodeAction {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_NODE_WEB3_SET,
|
||||
payload
|
||||
|
@ -24,7 +24,9 @@ export function sanitizeHex(hex: string) {
|
||||
return hex !== '' ? `0x${padLeftEven(hexStr)}` : '';
|
||||
}
|
||||
|
||||
export function networkIdToName(networkId: string | number): StaticNetworkIds {
|
||||
export function networkIdToName(
|
||||
networkId: 1 | 3 | 4 | 42 | '1' | '3' | '4' | '42'
|
||||
): StaticNetworkIds {
|
||||
switch (networkId.toString()) {
|
||||
case '1':
|
||||
return 'ETH';
|
||||
|
@ -2,7 +2,6 @@ import { ChangeLanguageAction, SetLatestBlockAction, MetaAction } from 'actions/
|
||||
import { TypeKeys } from 'actions/config/constants';
|
||||
|
||||
export interface State {
|
||||
// FIXME
|
||||
languageSelection: string;
|
||||
offline: boolean;
|
||||
autoGasLimit: boolean;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { NodeAction, TypeKeys, ChangeNodeAction } from 'actions/config';
|
||||
import { INITIAL_STATE as INITIAL_NODE_STATE } from '../nodes/selectedNode'; // could probably consolidate this in the index file of 'nodes' to make it easier to import
|
||||
import { INITIAL_STATE as INITIAL_NODE_STATE } from '../nodes/selectedNode';
|
||||
import { INITIAL_STATE as INITIAL_DEFAULT_NODE_STATE } from '../nodes/staticNodes';
|
||||
import { NonWeb3NodeConfigs } from 'types/node';
|
||||
import { StaticNetworkIds } from 'types/network';
|
||||
|
@ -17,7 +17,7 @@ export type State = { [key in StaticNetworkIds]: StaticNetworkConfig };
|
||||
// Must be a website that follows the ethplorer convention of /tx/[hash] and
|
||||
// address/[address] to generate the correct functions.
|
||||
// TODO: put this in utils / libs
|
||||
function makeExplorer(origin: string): BlockExplorerConfig {
|
||||
export function makeExplorer(origin: string): BlockExplorerConfig {
|
||||
return {
|
||||
origin,
|
||||
txUrl: hash => `${origin}/tx/${hash}`,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { EtherscanNode, InfuraNode, RPCNode } from 'libs/nodes';
|
||||
import { ConfigAction, TypeKeys } from 'actions/config';
|
||||
import { TypeKeys, NodeAction } from 'actions/config';
|
||||
import { NonWeb3NodeConfigs, Web3NodeConfigs } from 'types/node';
|
||||
|
||||
export type State = NonWeb3NodeConfigs & Web3NodeConfigs;
|
||||
@ -91,7 +91,7 @@ export const INITIAL_STATE: State = {
|
||||
}
|
||||
};
|
||||
|
||||
export const staticNodes = (state: State = INITIAL_STATE, action: ConfigAction) => {
|
||||
export const staticNodes = (state: State = INITIAL_STATE, action: NodeAction) => {
|
||||
switch (action.type) {
|
||||
case TypeKeys.CONFIG_NODE_WEB3_SET:
|
||||
return { ...state, [action.payload.id]: action.payload.config };
|
||||
|
@ -22,7 +22,7 @@ import {
|
||||
} from 'selectors/config';
|
||||
import { TypeKeys } from 'actions/config/constants';
|
||||
import {
|
||||
toggleOfflineConfig,
|
||||
toggleOffline,
|
||||
changeNode,
|
||||
changeNodeIntent,
|
||||
setLatestBlock,
|
||||
@ -55,7 +55,7 @@ export function* pollOfflineStatus(): SagaIterator {
|
||||
yield put(
|
||||
showNotification('success', 'Your connection to the network has been restored!', 3000)
|
||||
);
|
||||
yield put(toggleOfflineConfig());
|
||||
yield put(toggleOffline());
|
||||
} else if (!pingSucceeded && !isOffline) {
|
||||
// If we were unable to ping but redux says we're online, mark offline
|
||||
// If they had been online, show an error.
|
||||
@ -79,7 +79,7 @@ export function* pollOfflineStatus(): SagaIterator {
|
||||
)
|
||||
);
|
||||
}
|
||||
yield put(toggleOfflineConfig());
|
||||
yield put(toggleOffline());
|
||||
} else {
|
||||
// If neither case was true, try again in 5s
|
||||
yield call(delay, 5000);
|
||||
|
@ -1,19 +0,0 @@
|
||||
import { StaticNetworkConfig } from 'types/network';
|
||||
|
||||
describe('Networks', () => {
|
||||
Object.keys(NETWORKS).forEach(networkId => {
|
||||
it(`${networkId} contains non-null dPathFormats`, () => {
|
||||
const network: StaticNetworkConfig = NETWORKS[networkId];
|
||||
Object.values(network.dPathFormats).forEach(dPathFormat => {
|
||||
expect(dPathFormat).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`contain unique chainIds`, () => {
|
||||
const networkValues = Object.values(NETWORKS);
|
||||
const chainIds = networkValues.map(a => a.chainId);
|
||||
const chainIdsSet = new Set(chainIds);
|
||||
expect(Array.from(chainIdsSet).length).toEqual(chainIds.length);
|
||||
});
|
||||
});
|
@ -1,90 +0,0 @@
|
||||
import { config } from 'reducers/config';
|
||||
import * as configActions from 'actions/config';
|
||||
import { makeCustomNodeId, makeNodeConfigFromCustomConfig } from 'utils/node';
|
||||
|
||||
const custNode = {
|
||||
name: 'Test Config',
|
||||
url: 'http://somecustomconfig.org/',
|
||||
port: 443,
|
||||
network: 'ETH'
|
||||
};
|
||||
|
||||
describe('config reducer', () => {
|
||||
it('should handle CONFIG_LANGUAGE_CHANGE', () => {
|
||||
const language = 'en';
|
||||
expect(config(undefined, configActions.changeLanguage(language))).toEqual({
|
||||
...INITIAL_STATE,
|
||||
languageSelection: language
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle CONFIG_NODE_CHANGE', () => {
|
||||
const key = Object.keys(NODES)[0];
|
||||
const node = NODES[key];
|
||||
const network = NETWORKS[node.network];
|
||||
|
||||
expect(config(undefined, configActions.changeNode(key, node, network))).toEqual({
|
||||
...INITIAL_STATE,
|
||||
node: NODES[key],
|
||||
nodeSelection: key
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle CONFIG_TOGGLE_OFFLINE', () => {
|
||||
const offlineState = {
|
||||
...INITIAL_STATE,
|
||||
offline: true
|
||||
};
|
||||
|
||||
const onlineState = {
|
||||
...INITIAL_STATE,
|
||||
offline: false
|
||||
};
|
||||
|
||||
expect(config(offlineState, configActions.toggleOfflineConfig())).toEqual({
|
||||
...offlineState,
|
||||
offline: false
|
||||
});
|
||||
|
||||
expect(config(onlineState, configActions.toggleOfflineConfig())).toEqual({
|
||||
...onlineState,
|
||||
offline: true
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle CONFIG_ADD_CUSTOM_NODE', () => {
|
||||
expect(config(undefined, configActions.addCustomNode(custNode))).toEqual({
|
||||
...INITIAL_STATE,
|
||||
customNodes: [custNode]
|
||||
});
|
||||
});
|
||||
|
||||
describe('should handle CONFIG_REMOVE_CUSTOM_NODE', () => {
|
||||
const customNodeId = makeCustomNodeId(custNode);
|
||||
const addedState = config(undefined, configActions.addCustomNode(custNode));
|
||||
const addedAndActiveState = config(
|
||||
addedState,
|
||||
configActions.changeNode(
|
||||
customNodeId,
|
||||
makeNodeConfigFromCustomConfig(custNode),
|
||||
NETWORKS[custNode.network]
|
||||
)
|
||||
);
|
||||
const removedState = config(addedAndActiveState, configActions.removeCustomNode(custNode));
|
||||
|
||||
it('should remove the custom node from `customNodes`', () => {
|
||||
expect(removedState.customNodes.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should change the active node, if the custom one was active', () => {
|
||||
expect(removedState.nodeSelection === customNodeId).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle CONFIG_SET_LATEST_BLOCK', () => {
|
||||
expect(config(undefined, configActions.setLatestBlock('12345'))).toEqual({
|
||||
...INITIAL_STATE,
|
||||
latestBlock: '12345'
|
||||
});
|
||||
});
|
||||
});
|
74
spec/reducers/config/meta/meta.spec.ts
Normal file
74
spec/reducers/config/meta/meta.spec.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { meta } from 'reducers/config/meta';
|
||||
import { changeLanguage, toggleOffline, toggleAutoGasLimit, setLatestBlock } from 'actions/config';
|
||||
|
||||
const expectedInitialState = {
|
||||
languageSelection: 'en',
|
||||
offline: false,
|
||||
autoGasLimit: true,
|
||||
latestBlock: '???'
|
||||
};
|
||||
|
||||
const expectedState = {
|
||||
initialState: expectedInitialState,
|
||||
changingLanguage: {
|
||||
...expectedInitialState,
|
||||
languageSelection: 'langaugeToChange'
|
||||
},
|
||||
togglingToOffline: {
|
||||
...expectedInitialState,
|
||||
offline: true
|
||||
},
|
||||
togglingToOnline: {
|
||||
...expectedInitialState,
|
||||
offline: false
|
||||
},
|
||||
togglingToManualGasLimit: {
|
||||
...expectedInitialState,
|
||||
autoGasLimit: false
|
||||
},
|
||||
togglingToAutoGasLimit: {
|
||||
...expectedInitialState,
|
||||
autoGasLimit: true
|
||||
},
|
||||
settingLatestBlock: {
|
||||
...expectedInitialState,
|
||||
latestBlock: '12345'
|
||||
}
|
||||
};
|
||||
|
||||
const actions = {
|
||||
changeLangauge: changeLanguage('langaugeToChange'),
|
||||
toggleOffline: toggleOffline(),
|
||||
toggleAutoGasLimit: toggleAutoGasLimit(),
|
||||
setLatestBlock: setLatestBlock('12345')
|
||||
};
|
||||
|
||||
describe('meta reducer', () => {
|
||||
it('should return the inital state', () =>
|
||||
expect(meta(undefined, {} as any)).toEqual(expectedState.initialState));
|
||||
|
||||
it('should handle toggling to offline', () =>
|
||||
expect(meta(expectedState.initialState, actions.toggleOffline)).toEqual(
|
||||
expectedState.togglingToOffline
|
||||
));
|
||||
|
||||
it('should handle toggling back to online', () =>
|
||||
expect(meta(expectedState.togglingToOffline, actions.toggleOffline)).toEqual(
|
||||
expectedState.togglingToOnline
|
||||
));
|
||||
|
||||
it('should handle toggling to manual gas limit', () =>
|
||||
expect(meta(expectedState.initialState, actions.toggleAutoGasLimit)).toEqual(
|
||||
expectedState.togglingToManualGasLimit
|
||||
));
|
||||
|
||||
it('should handle toggling back to auto gas limit', () =>
|
||||
expect(meta(expectedState.togglingToManualGasLimit, actions.toggleAutoGasLimit)).toEqual(
|
||||
expectedState.togglingToAutoGasLimit
|
||||
));
|
||||
|
||||
it('should handle setting the latest block', () =>
|
||||
expect(meta(expectedState.initialState, actions.setLatestBlock)).toEqual(
|
||||
expectedState.settingLatestBlock
|
||||
));
|
||||
});
|
60
spec/reducers/config/networks/customNetworks.spec.ts
Normal file
60
spec/reducers/config/networks/customNetworks.spec.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { CustomNetworkConfig } from 'types/network';
|
||||
import { addCustomNetwork, removeCustomNetwork } from 'actions/config';
|
||||
import { customNetworks } from 'reducers/config/networks/customNetworks';
|
||||
|
||||
const firstCustomNetworkId = 'firstCustomNetwork';
|
||||
const firstCustomNetworkConfig: CustomNetworkConfig = {
|
||||
isCustom: true,
|
||||
chainId: 1,
|
||||
name: firstCustomNetworkId,
|
||||
unit: 'customNetworkUnit',
|
||||
dPathFormats: null
|
||||
};
|
||||
|
||||
const secondCustomNetworkId = 'secondCustomNetwork';
|
||||
const secondCustomNetworkConfig: CustomNetworkConfig = {
|
||||
...firstCustomNetworkConfig,
|
||||
name: secondCustomNetworkId
|
||||
};
|
||||
|
||||
const expectedState = {
|
||||
initialState: {},
|
||||
addFirstCustomNetwork: { [firstCustomNetworkId]: firstCustomNetworkConfig },
|
||||
addSecondCustomNetwork: {
|
||||
[firstCustomNetworkId]: firstCustomNetworkConfig,
|
||||
[secondCustomNetworkId]: secondCustomNetworkConfig
|
||||
},
|
||||
removeFirstCustomNetwork: { [secondCustomNetworkId]: secondCustomNetworkConfig }
|
||||
};
|
||||
|
||||
const actions = {
|
||||
addFirstCustomNetwork: addCustomNetwork({
|
||||
id: firstCustomNetworkId,
|
||||
config: firstCustomNetworkConfig
|
||||
}),
|
||||
addSecondCustomNetwork: addCustomNetwork({
|
||||
config: secondCustomNetworkConfig,
|
||||
id: secondCustomNetworkId
|
||||
}),
|
||||
removeFirstCustomNetwork: removeCustomNetwork({ id: firstCustomNetworkId })
|
||||
};
|
||||
|
||||
describe('custom networks reducer', () => {
|
||||
it('should return the intial state', () =>
|
||||
expect(customNetworks(undefined, {} as any)).toEqual(expectedState.initialState));
|
||||
|
||||
it('should handle adding the first custom network', () =>
|
||||
expect(customNetworks(expectedState.initialState, actions.addFirstCustomNetwork)).toEqual(
|
||||
expectedState.addFirstCustomNetwork
|
||||
));
|
||||
|
||||
it('should handle adding the second custom network', () =>
|
||||
expect(
|
||||
customNetworks(expectedState.addFirstCustomNetwork, actions.addSecondCustomNetwork)
|
||||
).toEqual(expectedState.addSecondCustomNetwork));
|
||||
|
||||
it('should handle removing the first custom network', () =>
|
||||
expect(
|
||||
customNetworks(expectedState.addSecondCustomNetwork, actions.removeFirstCustomNetwork)
|
||||
).toEqual(expectedState.removeFirstCustomNetwork));
|
||||
});
|
16
spec/reducers/config/networks/selectedNetwork.spec.ts
Normal file
16
spec/reducers/config/networks/selectedNetwork.spec.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { actions } from '../nodes/selectedNode.spec';
|
||||
import { selectedNetwork } from 'reducers/config/networks/selectedNetwork';
|
||||
|
||||
const expectedState = {
|
||||
initialState: 'ETH',
|
||||
nodeChange: 'networkToChangeTo'
|
||||
};
|
||||
|
||||
describe('selected network reducer', () => {
|
||||
it('should return the initial state', () =>
|
||||
expect(selectedNetwork(undefined, {} as any)).toEqual(expectedState.initialState));
|
||||
it('should handle changing nodes by changing to the right network', () =>
|
||||
expect(selectedNetwork(expectedState.initialState, actions.changeNode)).toEqual(
|
||||
expectedState.nodeChange
|
||||
));
|
||||
});
|
148
spec/reducers/config/networks/staticNetworks.spec.ts
Normal file
148
spec/reducers/config/networks/staticNetworks.spec.ts
Normal file
@ -0,0 +1,148 @@
|
||||
import { staticNetworks, makeExplorer } from 'reducers/config/networks/staticNetworks';
|
||||
import { ethPlorer, ETHTokenExplorer, SecureWalletName, InsecureWalletName } from 'config/data';
|
||||
import { StaticNetworkConfig } from 'types/network';
|
||||
import {
|
||||
ETH_DEFAULT,
|
||||
ETH_TREZOR,
|
||||
ETH_LEDGER,
|
||||
ETC_LEDGER,
|
||||
ETC_TREZOR,
|
||||
ETH_TESTNET,
|
||||
EXP_DEFAULT,
|
||||
UBQ_DEFAULT
|
||||
} from 'config/dpaths';
|
||||
|
||||
const expectedInitialState = {
|
||||
ETH: {
|
||||
name: 'ETH',
|
||||
unit: 'ETH',
|
||||
chainId: 1,
|
||||
isCustom: false,
|
||||
color: '#0e97c0',
|
||||
blockExplorer: makeExplorer('https://etherscan.io'),
|
||||
tokenExplorer: {
|
||||
name: ethPlorer,
|
||||
address: ETHTokenExplorer
|
||||
},
|
||||
tokens: require('config/tokens/eth.json'),
|
||||
contracts: require('config/contracts/eth.json'),
|
||||
dPathFormats: {
|
||||
[SecureWalletName.TREZOR]: ETH_TREZOR,
|
||||
[SecureWalletName.LEDGER_NANO_S]: ETH_LEDGER,
|
||||
[InsecureWalletName.MNEMONIC_PHRASE]: ETH_DEFAULT
|
||||
}
|
||||
},
|
||||
Ropsten: {
|
||||
name: 'Ropsten',
|
||||
unit: 'ETH',
|
||||
chainId: 3,
|
||||
isCustom: false,
|
||||
color: '#adc101',
|
||||
blockExplorer: makeExplorer('https://ropsten.etherscan.io'),
|
||||
tokens: require('config/tokens/ropsten.json'),
|
||||
contracts: require('config/contracts/ropsten.json'),
|
||||
isTestnet: true,
|
||||
dPathFormats: {
|
||||
[SecureWalletName.TREZOR]: ETH_TESTNET,
|
||||
[SecureWalletName.LEDGER_NANO_S]: ETH_TESTNET,
|
||||
[InsecureWalletName.MNEMONIC_PHRASE]: ETH_TESTNET
|
||||
}
|
||||
},
|
||||
Kovan: {
|
||||
name: 'Kovan',
|
||||
unit: 'ETH',
|
||||
chainId: 42,
|
||||
isCustom: false,
|
||||
color: '#adc101',
|
||||
blockExplorer: makeExplorer('https://kovan.etherscan.io'),
|
||||
tokens: require('config/tokens/ropsten.json'),
|
||||
contracts: require('config/contracts/ropsten.json'),
|
||||
isTestnet: true,
|
||||
dPathFormats: {
|
||||
[SecureWalletName.TREZOR]: ETH_TESTNET,
|
||||
[SecureWalletName.LEDGER_NANO_S]: ETH_TESTNET,
|
||||
[InsecureWalletName.MNEMONIC_PHRASE]: ETH_TESTNET
|
||||
}
|
||||
},
|
||||
Rinkeby: {
|
||||
name: 'Rinkeby',
|
||||
unit: 'ETH',
|
||||
chainId: 4,
|
||||
isCustom: false,
|
||||
color: '#adc101',
|
||||
blockExplorer: makeExplorer('https://rinkeby.etherscan.io'),
|
||||
tokens: require('config/tokens/rinkeby.json'),
|
||||
contracts: require('config/contracts/rinkeby.json'),
|
||||
isTestnet: true,
|
||||
dPathFormats: {
|
||||
[SecureWalletName.TREZOR]: ETH_TESTNET,
|
||||
[SecureWalletName.LEDGER_NANO_S]: ETH_TESTNET,
|
||||
[InsecureWalletName.MNEMONIC_PHRASE]: ETH_TESTNET
|
||||
}
|
||||
},
|
||||
ETC: {
|
||||
name: 'ETC',
|
||||
unit: 'ETC',
|
||||
chainId: 61,
|
||||
isCustom: false,
|
||||
color: '#669073',
|
||||
blockExplorer: makeExplorer('https://gastracker.io'),
|
||||
tokens: require('config/tokens/etc.json'),
|
||||
contracts: require('config/contracts/etc.json'),
|
||||
dPathFormats: {
|
||||
[SecureWalletName.TREZOR]: ETC_TREZOR,
|
||||
[SecureWalletName.LEDGER_NANO_S]: ETC_LEDGER,
|
||||
[InsecureWalletName.MNEMONIC_PHRASE]: ETC_TREZOR
|
||||
}
|
||||
},
|
||||
UBQ: {
|
||||
name: 'UBQ',
|
||||
unit: 'UBQ',
|
||||
chainId: 8,
|
||||
isCustom: false,
|
||||
color: '#b37aff',
|
||||
blockExplorer: makeExplorer('https://ubiqscan.io/en'),
|
||||
tokens: require('config/tokens/ubq.json'),
|
||||
contracts: require('config/contracts/ubq.json'),
|
||||
dPathFormats: {
|
||||
[SecureWalletName.TREZOR]: UBQ_DEFAULT,
|
||||
[SecureWalletName.LEDGER_NANO_S]: UBQ_DEFAULT,
|
||||
[InsecureWalletName.MNEMONIC_PHRASE]: UBQ_DEFAULT
|
||||
}
|
||||
},
|
||||
EXP: {
|
||||
name: 'EXP',
|
||||
unit: 'EXP',
|
||||
chainId: 2,
|
||||
isCustom: false,
|
||||
color: '#673ab7',
|
||||
blockExplorer: makeExplorer('http://www.gander.tech'),
|
||||
tokens: require('config/tokens/exp.json'),
|
||||
contracts: require('config/contracts/exp.json'),
|
||||
dPathFormats: {
|
||||
[SecureWalletName.TREZOR]: EXP_DEFAULT,
|
||||
[SecureWalletName.LEDGER_NANO_S]: EXP_DEFAULT,
|
||||
[InsecureWalletName.MNEMONIC_PHRASE]: EXP_DEFAULT
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const expectedState = {
|
||||
initialState: expectedInitialState
|
||||
};
|
||||
|
||||
describe('Testing contained data', () => {
|
||||
it(`contain unique chainIds`, () => {
|
||||
const networkValues = Object.values(expectedInitialState);
|
||||
const chainIds = networkValues.map(a => a.chainId);
|
||||
const chainIdsSet = new Set(chainIds);
|
||||
expect(Array.from(chainIdsSet).length).toEqual(chainIds.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('static networks reducer', () => {
|
||||
it('should return the initial state', () =>
|
||||
expect(JSON.stringify(staticNetworks(undefined, {} as any))).toEqual(
|
||||
JSON.stringify(expectedState.initialState)
|
||||
));
|
||||
});
|
55
spec/reducers/config/nodes/customNodes.spec.ts
Normal file
55
spec/reducers/config/nodes/customNodes.spec.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { addCustomNode, removeCustomNode } from 'actions/config';
|
||||
import { CustomNodeConfig } from 'types/node';
|
||||
import { customNodes } from 'reducers/config/nodes/customNodes';
|
||||
|
||||
const firstCustomNodeId = 'customNode1';
|
||||
const firstCustomNode: CustomNodeConfig = {
|
||||
isCustom: true,
|
||||
id: firstCustomNodeId,
|
||||
lib: jest.fn() as any,
|
||||
name: 'My cool custom node',
|
||||
network: 'CustomNetworkId',
|
||||
port: 8080,
|
||||
service: 'your custom node',
|
||||
url: '127.0.0.1'
|
||||
};
|
||||
|
||||
const secondCustomNodeId = 'customNode2';
|
||||
const secondCustomNode: CustomNodeConfig = {
|
||||
...firstCustomNode,
|
||||
id: secondCustomNodeId
|
||||
};
|
||||
|
||||
const expectedStates = {
|
||||
initialState: {},
|
||||
addFirstCustomNode: { [firstCustomNodeId]: firstCustomNode },
|
||||
addSecondCustomNode: {
|
||||
[firstCustomNodeId]: firstCustomNode,
|
||||
[secondCustomNodeId]: secondCustomNode
|
||||
},
|
||||
removeFirstCustomNode: { [secondCustomNodeId]: secondCustomNode }
|
||||
};
|
||||
|
||||
const actions = {
|
||||
addFirstCustomNode: addCustomNode({ id: firstCustomNodeId, config: firstCustomNode }),
|
||||
addSecondCustomNode: addCustomNode({ id: secondCustomNodeId, config: secondCustomNode }),
|
||||
removeFirstCustomNode: removeCustomNode({ id: firstCustomNodeId })
|
||||
};
|
||||
|
||||
describe('custom nodes reducer', () => {
|
||||
it('should return the initial state', () =>
|
||||
expect(customNodes(undefined, {} as any)).toEqual({}));
|
||||
|
||||
it('should handle adding the first custom node', () =>
|
||||
expect(customNodes(expectedStates.initialState, actions.addFirstCustomNode)).toEqual(
|
||||
expectedStates.addFirstCustomNode
|
||||
));
|
||||
it('should handle adding a second custom node', () =>
|
||||
expect(customNodes(expectedStates.addFirstCustomNode, actions.addSecondCustomNode)).toEqual(
|
||||
expectedStates.addSecondCustomNode
|
||||
));
|
||||
it('should handle removing the first custom node', () =>
|
||||
expect(customNodes(expectedStates.addSecondCustomNode, actions.removeFirstCustomNode)).toEqual(
|
||||
expectedStates.removeFirstCustomNode
|
||||
));
|
||||
});
|
26
spec/reducers/config/nodes/selectedNode.spec.ts
Normal file
26
spec/reducers/config/nodes/selectedNode.spec.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { changeNodeIntent, changeNode } from 'actions/config';
|
||||
import { State, selectedNode } from 'reducers/config/nodes/selectedNode';
|
||||
|
||||
export const expectedState: { [key: string]: State } = {
|
||||
initialState: { nodeId: 'eth_mew', pending: false },
|
||||
nodeChange: { nodeId: 'nodeToChangeTo', pending: false },
|
||||
nodeChangeIntent: { nodeId: 'eth_mew', pending: true }
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
changeNode: changeNode({ nodeId: 'nodeToChangeTo', networkId: 'networkToChangeTo' }),
|
||||
changeNodeIntent: changeNodeIntent('eth_mew')
|
||||
};
|
||||
|
||||
describe('selected node reducer', () => {
|
||||
it(' should return the initial state', () =>
|
||||
expect(selectedNode(undefined, {} as any)).toEqual(expectedState.initialState));
|
||||
|
||||
it('should handle a node change', () =>
|
||||
expect(selectedNode(undefined, actions.changeNode)).toEqual(expectedState.nodeChange));
|
||||
|
||||
it('should handle the intent to change a node', () =>
|
||||
expect(selectedNode(expectedState.initialState, actions.changeNodeIntent)).toEqual(
|
||||
expectedState.nodeChangeIntent
|
||||
));
|
||||
});
|
128
spec/reducers/config/nodes/staticNodes.spec.ts
Normal file
128
spec/reducers/config/nodes/staticNodes.spec.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import { web3SetNode, web3UnsetNode } from 'actions/config';
|
||||
import { staticNodes, INITIAL_STATE } from 'reducers/config/nodes/staticNodes';
|
||||
import { EtherscanNode, InfuraNode, RPCNode } from 'libs/nodes';
|
||||
import { Web3NodeConfig } from 'types/node';
|
||||
import { networkIdToName } from 'libs/values';
|
||||
import { Web3Service } from 'libs/nodes/web3';
|
||||
|
||||
const expectedInitialState = JSON.stringify({
|
||||
eth_mew: {
|
||||
network: 'ETH',
|
||||
isCustom: false,
|
||||
lib: new RPCNode('https://api.myetherapi.com/eth'),
|
||||
service: 'MyEtherWallet',
|
||||
estimateGas: true
|
||||
},
|
||||
eth_mycrypto: {
|
||||
network: 'ETH',
|
||||
isCustom: false,
|
||||
lib: new RPCNode('https://api.mycryptoapi.com/eth'),
|
||||
service: 'MyCrypto',
|
||||
estimateGas: true
|
||||
},
|
||||
eth_ethscan: {
|
||||
network: 'ETH',
|
||||
isCustom: false,
|
||||
service: 'Etherscan.io',
|
||||
lib: new EtherscanNode('https://api.etherscan.io/api'),
|
||||
estimateGas: false
|
||||
},
|
||||
eth_infura: {
|
||||
network: 'ETH',
|
||||
isCustom: false,
|
||||
service: 'infura.io',
|
||||
lib: new InfuraNode('https://mainnet.infura.io/mew'),
|
||||
estimateGas: false
|
||||
},
|
||||
rop_mew: {
|
||||
network: 'Ropsten',
|
||||
isCustom: false,
|
||||
service: 'MyEtherWallet',
|
||||
lib: new RPCNode('https://api.myetherapi.com/rop'),
|
||||
estimateGas: false
|
||||
},
|
||||
rop_infura: {
|
||||
network: 'Ropsten',
|
||||
isCustom: false,
|
||||
service: 'infura.io',
|
||||
lib: new InfuraNode('https://ropsten.infura.io/mew'),
|
||||
estimateGas: false
|
||||
},
|
||||
kov_ethscan: {
|
||||
network: 'Kovan',
|
||||
isCustom: false,
|
||||
service: 'Etherscan.io',
|
||||
lib: new EtherscanNode('https://kovan.etherscan.io/api'),
|
||||
estimateGas: false
|
||||
},
|
||||
rin_ethscan: {
|
||||
network: 'Rinkeby',
|
||||
isCustom: false,
|
||||
service: 'Etherscan.io',
|
||||
lib: new EtherscanNode('https://rinkeby.etherscan.io/api'),
|
||||
estimateGas: false
|
||||
},
|
||||
rin_infura: {
|
||||
network: 'Rinkeby',
|
||||
isCustom: false,
|
||||
service: 'infura.io',
|
||||
lib: new InfuraNode('https://rinkeby.infura.io/mew'),
|
||||
estimateGas: false
|
||||
},
|
||||
etc_epool: {
|
||||
network: 'ETC',
|
||||
isCustom: false,
|
||||
service: 'Epool.io',
|
||||
lib: new RPCNode('https://mewapi.epool.io'),
|
||||
estimateGas: false
|
||||
},
|
||||
ubq: {
|
||||
network: 'UBQ',
|
||||
isCustom: false,
|
||||
service: 'ubiqscan.io',
|
||||
lib: new RPCNode('https://pyrus2.ubiqscan.io'),
|
||||
estimateGas: true
|
||||
},
|
||||
exp_tech: {
|
||||
network: 'EXP',
|
||||
isCustom: false,
|
||||
service: 'Expanse.tech',
|
||||
lib: new RPCNode('https://node.expanse.tech/'),
|
||||
estimateGas: true
|
||||
}
|
||||
});
|
||||
|
||||
const web3Id = 'web3';
|
||||
const web3NetworkId = 1;
|
||||
const web3Node: Web3NodeConfig = {
|
||||
isCustom: false,
|
||||
network: networkIdToName(web3NetworkId),
|
||||
service: Web3Service,
|
||||
lib: jest.fn() as any,
|
||||
estimateGas: false,
|
||||
hidden: true
|
||||
};
|
||||
|
||||
const expectedStates = {
|
||||
initialState: expectedInitialState,
|
||||
setWeb3: { ...INITIAL_STATE, [web3Id]: web3Node },
|
||||
unsetWeb3: { ...INITIAL_STATE }
|
||||
};
|
||||
|
||||
const actions = {
|
||||
web3SetNode: web3SetNode({ id: web3Id, config: web3Node }),
|
||||
web3UnsetNode: web3UnsetNode()
|
||||
};
|
||||
|
||||
describe('static nodes reducer', () => {
|
||||
it('should return the inital state', () =>
|
||||
// turn the JSON into a string because we're storing function in the state
|
||||
expect(JSON.stringify(staticNodes(undefined, {} as any))).toEqual(expectedStates.initialState));
|
||||
it('should handle setting the web3 node', () =>
|
||||
expect(staticNodes(INITIAL_STATE, actions.web3SetNode)).toEqual(expectedStates.setWeb3));
|
||||
|
||||
it('should handle unsetting the web3 node', () =>
|
||||
expect(staticNodes(expectedStates.setWeb3, actions.web3UnsetNode)).toEqual(
|
||||
expectedStates.unsetWeb3
|
||||
));
|
||||
});
|
@ -2,7 +2,7 @@ import { configuredStore } from 'store';
|
||||
import { delay } from 'redux-saga';
|
||||
import { call, cancel, fork, put, take, select } from 'redux-saga/effects';
|
||||
import { cloneableGenerator, createMockTask } from 'redux-saga/utils';
|
||||
import { toggleOfflineConfig, changeNode, changeNodeIntent, setLatestBlock } from 'actions/config';
|
||||
import { toggleOffline, changeNode, changeNodeIntent, setLatestBlock } from 'actions/config';
|
||||
import {
|
||||
pollOfflineStatus,
|
||||
handlePollOfflineStatus,
|
||||
@ -102,14 +102,14 @@ describe('pollOfflineStatus*', () => {
|
||||
expect(data.gen.next(raceSuccess).value).toEqual(
|
||||
put(showNotification('success', 'Your connection to the network has been restored!', 3000))
|
||||
);
|
||||
expect(data.gen.next().value).toEqual(put(toggleOfflineConfig()));
|
||||
expect(data.gen.next().value).toEqual(put(toggleOffline()));
|
||||
});
|
||||
|
||||
it('should toggle offline and show notification if navigator agrees with isOffline and ping fails', () => {
|
||||
nav.onLine = isOffline;
|
||||
expect(data.isOfflineClone.next(!isOffline));
|
||||
expect(data.isOfflineClone.next(raceFailure).value).toMatchSnapshot();
|
||||
expect(data.isOfflineClone.next().value).toEqual(put(toggleOfflineConfig()));
|
||||
expect(data.isOfflineClone.next().value).toEqual(put(toggleOffline()));
|
||||
nav.onLine = !isOffline;
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user