mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-01-10 19:16:10 +00:00
Outstanding tasks to Productionize Tx (#1194)
* Verify and complete all branching saga logic tests for transaction stack. * Write reducer tests for refactored transaction stack. * Add selector tests. Some files still need to be debugged. * Add snapshot test for fields, additional seelector testing. * Remove fields snapshots. * Remove ABIs from the TestState json * Use redux state instead of raw json in selector testing. * Fix merge issues. * Remove log * Fix state values. * Change test value to wei. * Last touchup. * Fix buffer shape, change Wei typo, use reasonable wei values. * Last touch up.
This commit is contained in:
parent
94b3f3403b
commit
cf9887f21f
@ -56,12 +56,7 @@ const nonStandardTransaction = (state: AppState): boolean => {
|
|||||||
const getGasCost = (state: AppState) => {
|
const getGasCost = (state: AppState) => {
|
||||||
const gasPrice = getGasPrice(state);
|
const gasPrice = getGasPrice(state);
|
||||||
const gasLimit = getGasLimit(state);
|
const gasLimit = getGasLimit(state);
|
||||||
if (!gasLimit.value) {
|
return gasLimit.value ? gasPrice.value.mul(gasLimit.value) : Wei('0');
|
||||||
return Wei('0');
|
|
||||||
}
|
|
||||||
const cost = gasLimit.value.mul(gasPrice.value);
|
|
||||||
|
|
||||||
return cost;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const serializedAndTransactionFieldsMatch = (state: AppState, isLocallySigned: boolean) => {
|
const serializedAndTransactionFieldsMatch = (state: AppState, isLocallySigned: boolean) => {
|
||||||
|
24
package.json
24
package.json
@ -147,14 +147,10 @@
|
|||||||
"prebuild": "check-node-version --package",
|
"prebuild": "check-node-version --package",
|
||||||
"build:downloadable": "webpack --config webpack_config/webpack.html.js",
|
"build:downloadable": "webpack --config webpack_config/webpack.html.js",
|
||||||
"prebuild:downloadable": "check-node-version --package",
|
"prebuild:downloadable": "check-node-version --package",
|
||||||
"build:electron":
|
"build:electron": "webpack --config webpack_config/webpack.electron-prod.js && node webpack_config/buildElectron.js",
|
||||||
"webpack --config webpack_config/webpack.electron-prod.js && node webpack_config/buildElectron.js",
|
"build:electron:osx": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=osx node webpack_config/buildElectron.js",
|
||||||
"build:electron:osx":
|
"build:electron:windows": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js",
|
||||||
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=osx node webpack_config/buildElectron.js",
|
"build:electron:linux": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=linux node webpack_config/buildElectron.js",
|
||||||
"build:electron:windows":
|
|
||||||
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js",
|
|
||||||
"build:electron:linux":
|
|
||||||
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=linux node webpack_config/buildElectron.js",
|
|
||||||
"prebuild:electron": "check-node-version --package",
|
"prebuild:electron": "check-node-version --package",
|
||||||
"test:coverage": "jest --config=jest_config/jest.config.json --coverage",
|
"test:coverage": "jest --config=jest_config/jest.config.json --coverage",
|
||||||
"test": "jest --config=jest_config/jest.config.json",
|
"test": "jest --config=jest_config/jest.config.json",
|
||||||
@ -166,18 +162,14 @@
|
|||||||
"predev": "check-node-version --package",
|
"predev": "check-node-version --package",
|
||||||
"dev:https": "HTTPS=true node webpack_config/devServer.js",
|
"dev:https": "HTTPS=true node webpack_config/devServer.js",
|
||||||
"predev:https": "check-node-version --package",
|
"predev:https": "check-node-version --package",
|
||||||
"dev:electron":
|
"dev:electron": "concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true node webpack_config/devServer.js' 'webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'",
|
||||||
"concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true node webpack_config/devServer.js' 'webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'",
|
"dev:electron:https": "concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true HTTPS=true node webpack_config/devServer.js' 'HTTPS=true webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'",
|
||||||
"dev:electron:https":
|
|
||||||
"concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true HTTPS=true node webpack_config/devServer.js' 'HTTPS=true webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'",
|
|
||||||
"tslint": "tslint --project . --exclude common/vendor/**/*",
|
"tslint": "tslint --project . --exclude common/vendor/**/*",
|
||||||
"tscheck": "tsc --noEmit",
|
"tscheck": "tsc --noEmit",
|
||||||
"start": "npm run dev",
|
"start": "npm run dev",
|
||||||
"precommit": "lint-staged",
|
"precommit": "lint-staged",
|
||||||
"formatAll":
|
"formatAll": "find ./common/ -name '*.ts*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override",
|
||||||
"find ./common/ -name '*.ts*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override",
|
"prettier:diff": "prettier --write --config ./.prettierrc --list-different \"common/**/*.ts\" \"common/**/*.tsx\"",
|
||||||
"prettier:diff":
|
|
||||||
"prettier --write --config ./.prettierrc --list-different \"common/**/*.ts\" \"common/**/*.tsx\"",
|
|
||||||
"prepush": "npm run tslint && npm run tscheck"
|
"prepush": "npm run tslint && npm run tscheck"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
56
spec/reducers/transaction/broadcast/broadcast.spec.ts
Normal file
56
spec/reducers/transaction/broadcast/broadcast.spec.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { INITIAL_STATE } from 'reducers/transaction';
|
||||||
|
import { broadcast, ITransactionStatus } from 'reducers/transaction/broadcast';
|
||||||
|
import * as txActions from 'actions/transaction';
|
||||||
|
|
||||||
|
const indexingHash = 'testingHash';
|
||||||
|
|
||||||
|
describe('broadcast reducer', () => {
|
||||||
|
const serializedTransaction = new Buffer('testSerialized');
|
||||||
|
const nextTxStatus: ITransactionStatus = {
|
||||||
|
broadcastedHash: null,
|
||||||
|
broadcastSuccessful: false,
|
||||||
|
isBroadcasting: true,
|
||||||
|
serializedTransaction
|
||||||
|
};
|
||||||
|
const nextState: any = {
|
||||||
|
...INITIAL_STATE,
|
||||||
|
[indexingHash]: nextTxStatus
|
||||||
|
};
|
||||||
|
it('should handle BROADCAST_TRANSACTION_QUEUED', () => {
|
||||||
|
expect(
|
||||||
|
broadcast(
|
||||||
|
INITIAL_STATE as any,
|
||||||
|
txActions.broadcastTransactionQueued({ indexingHash, serializedTransaction })
|
||||||
|
)
|
||||||
|
).toEqual(nextState);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle BROADCAST_TRANSACTION_SUCCESS', () => {
|
||||||
|
const broadcastedHash = 'testBroadcastHash';
|
||||||
|
const broadcastedState = {
|
||||||
|
...nextState,
|
||||||
|
[indexingHash]: {
|
||||||
|
...nextTxStatus,
|
||||||
|
broadcastedHash,
|
||||||
|
isBroadcasting: false,
|
||||||
|
broadcastSuccessful: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(
|
||||||
|
broadcast(
|
||||||
|
nextState,
|
||||||
|
txActions.broadcastTransactionSucceeded({ indexingHash, broadcastedHash })
|
||||||
|
)
|
||||||
|
).toEqual(broadcastedState);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle BROADCAST_TRANSACTION_FAILURE', () => {
|
||||||
|
const failedBroadcastState = {
|
||||||
|
...nextState,
|
||||||
|
[indexingHash]: { ...nextTxStatus, isBroadcasting: false, broadcastSuccessful: false }
|
||||||
|
};
|
||||||
|
expect(broadcast(nextState, txActions.broadcastTransactionFailed({ indexingHash }))).toEqual(
|
||||||
|
failedBroadcastState
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
122
spec/reducers/transaction/fields/fields.spec.ts
Normal file
122
spec/reducers/transaction/fields/fields.spec.ts
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import { TypeKeys } from 'actions/transaction/constants';
|
||||||
|
import { gasPricetoBase } from 'libs/units';
|
||||||
|
import { fields, State } from 'reducers/transaction/fields';
|
||||||
|
import * as txActions from 'actions/transaction';
|
||||||
|
import BN from 'bn.js';
|
||||||
|
|
||||||
|
describe('fields reducer', () => {
|
||||||
|
const INITIAL_STATE: State = {
|
||||||
|
to: { raw: '', value: null },
|
||||||
|
data: { raw: '', value: null },
|
||||||
|
nonce: { raw: '', value: null },
|
||||||
|
value: { raw: '', value: null },
|
||||||
|
gasLimit: { raw: '21000', value: new BN(21000) },
|
||||||
|
gasPrice: { raw: '20', value: gasPricetoBase(20) }
|
||||||
|
};
|
||||||
|
const testPayload = { raw: 'test', value: null };
|
||||||
|
|
||||||
|
it('should handle TO_FIELD_SET', () => {
|
||||||
|
expect(fields(INITIAL_STATE, txActions.setToField(testPayload))).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
to: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle VALUE_FIELD_SET', () => {
|
||||||
|
expect(fields(INITIAL_STATE, txActions.setValueField(testPayload))).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
value: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle DATA_FIELD_SET', () => {
|
||||||
|
expect(fields(INITIAL_STATE, txActions.setDataField(testPayload))).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
data: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle GAS_LIMIT_FIELD_SET', () => {
|
||||||
|
expect(fields(INITIAL_STATE, txActions.setGasLimitField(testPayload))).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
gasLimit: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle NONCE_SET', () => {
|
||||||
|
expect(fields(INITIAL_STATE, txActions.setNonceField(testPayload))).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
nonce: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle GAS_PRICE_FIELD_SET', () => {
|
||||||
|
expect(fields(INITIAL_STATE, txActions.setGasPriceField(testPayload))).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
gasPrice: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle TOKEN_TO_ETHER_SWAP', () => {
|
||||||
|
const swapAction: txActions.SwapTokenToEtherAction = {
|
||||||
|
type: TypeKeys.TOKEN_TO_ETHER_SWAP,
|
||||||
|
payload: {
|
||||||
|
to: testPayload,
|
||||||
|
value: testPayload,
|
||||||
|
decimal: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(fields(INITIAL_STATE, swapAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
to: testPayload,
|
||||||
|
value: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle ETHER_TO_TOKEN_SWAP', () => {
|
||||||
|
const swapAction: txActions.SwapEtherToTokenAction = {
|
||||||
|
type: TypeKeys.ETHER_TO_TOKEN_SWAP,
|
||||||
|
payload: {
|
||||||
|
to: testPayload,
|
||||||
|
data: testPayload,
|
||||||
|
tokenTo: testPayload,
|
||||||
|
tokenValue: testPayload,
|
||||||
|
decimal: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(fields(INITIAL_STATE, swapAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
to: testPayload,
|
||||||
|
data: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle TOKEN_TO_TOKEN_SWAP', () => {
|
||||||
|
const swapAction: txActions.SwapTokenToTokenAction = {
|
||||||
|
type: TypeKeys.TOKEN_TO_TOKEN_SWAP,
|
||||||
|
payload: {
|
||||||
|
to: testPayload,
|
||||||
|
data: testPayload,
|
||||||
|
tokenValue: testPayload,
|
||||||
|
decimal: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(fields(INITIAL_STATE, swapAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
to: testPayload,
|
||||||
|
data: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reset', () => {
|
||||||
|
const resetAction: txActions.ResetAction = {
|
||||||
|
type: TypeKeys.RESET,
|
||||||
|
payload: { include: {}, exclude: {} }
|
||||||
|
};
|
||||||
|
const modifiedState: State = {
|
||||||
|
...INITIAL_STATE,
|
||||||
|
data: { raw: 'modified', value: null }
|
||||||
|
};
|
||||||
|
expect(fields(modifiedState, resetAction)).toEqual(INITIAL_STATE);
|
||||||
|
});
|
||||||
|
});
|
109
spec/reducers/transaction/meta/meta.spec.ts
Normal file
109
spec/reducers/transaction/meta/meta.spec.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { TypeKeys } from 'actions/transaction/constants';
|
||||||
|
import { getDecimalFromEtherUnit } from 'libs/units';
|
||||||
|
import { State, meta } from 'reducers/transaction/meta';
|
||||||
|
import * as txActions from 'actions/transaction';
|
||||||
|
|
||||||
|
describe('meta reducer', () => {
|
||||||
|
const INITIAL_STATE: State = {
|
||||||
|
unit: '',
|
||||||
|
previousUnit: '',
|
||||||
|
decimal: getDecimalFromEtherUnit('ether'),
|
||||||
|
tokenValue: { raw: '', value: null },
|
||||||
|
tokenTo: { raw: '', value: null },
|
||||||
|
from: null
|
||||||
|
};
|
||||||
|
|
||||||
|
const testPayload = { raw: 'test', value: null };
|
||||||
|
|
||||||
|
it('should handle UNIT_META_SET', () => {
|
||||||
|
const setUnitMetaAction: txActions.SetUnitMetaAction = {
|
||||||
|
type: TypeKeys.UNIT_META_SET,
|
||||||
|
payload: 'test'
|
||||||
|
};
|
||||||
|
expect(meta(INITIAL_STATE, setUnitMetaAction));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle TOKEN_VALUE_META_SET', () => {
|
||||||
|
expect(meta(INITIAL_STATE, txActions.setTokenValue(testPayload))).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
tokenValue: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle TOKEN_TO_META_SET', () => {
|
||||||
|
expect(meta(INITIAL_STATE, txActions.setTokenTo(testPayload))).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
tokenTo: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle GET_FROM_SUCCEEDED', () => {
|
||||||
|
expect(meta(INITIAL_STATE, txActions.getFromSucceeded('test'))).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
from: 'test'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle TOKEN_TO_ETHER_SWAP', () => {
|
||||||
|
const swapAction: txActions.SwapTokenToEtherAction = {
|
||||||
|
type: TypeKeys.TOKEN_TO_ETHER_SWAP,
|
||||||
|
payload: {
|
||||||
|
to: testPayload,
|
||||||
|
value: testPayload,
|
||||||
|
decimal: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(meta(INITIAL_STATE, swapAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
decimal: swapAction.payload.decimal
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle ETHER_TO_TOKEN_SWAP', () => {
|
||||||
|
const swapAction: txActions.SwapEtherToTokenAction = {
|
||||||
|
type: TypeKeys.ETHER_TO_TOKEN_SWAP,
|
||||||
|
payload: {
|
||||||
|
to: testPayload,
|
||||||
|
data: testPayload,
|
||||||
|
tokenTo: testPayload,
|
||||||
|
tokenValue: testPayload,
|
||||||
|
decimal: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(meta(INITIAL_STATE, swapAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
decimal: swapAction.payload.decimal,
|
||||||
|
tokenTo: testPayload,
|
||||||
|
tokenValue: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle TOKEN_TO_TOKEN_SWAP', () => {
|
||||||
|
const swapAction: txActions.SwapTokenToTokenAction = {
|
||||||
|
type: TypeKeys.TOKEN_TO_TOKEN_SWAP,
|
||||||
|
payload: {
|
||||||
|
to: testPayload,
|
||||||
|
data: testPayload,
|
||||||
|
tokenValue: testPayload,
|
||||||
|
decimal: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(meta(INITIAL_STATE, swapAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
decimal: swapAction.payload.decimal,
|
||||||
|
tokenValue: testPayload
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reset', () => {
|
||||||
|
const resetAction: txActions.ResetAction = {
|
||||||
|
type: TypeKeys.RESET,
|
||||||
|
payload: { include: {}, exclude: {} }
|
||||||
|
};
|
||||||
|
const modifiedState: State = {
|
||||||
|
...INITIAL_STATE,
|
||||||
|
unit: 'modified'
|
||||||
|
};
|
||||||
|
expect(meta(modifiedState, resetAction)).toEqual(INITIAL_STATE);
|
||||||
|
});
|
||||||
|
});
|
55
spec/reducers/transaction/network/network.spec.ts
Normal file
55
spec/reducers/transaction/network/network.spec.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { State, network } from 'reducers/transaction/network';
|
||||||
|
import * as txActions from 'actions/transaction';
|
||||||
|
import { TypeKeys } from 'actions/transaction/constants';
|
||||||
|
|
||||||
|
describe('network reducer', () => {
|
||||||
|
const INITIAL_STATE: State = {
|
||||||
|
gasEstimationStatus: null,
|
||||||
|
getFromStatus: null,
|
||||||
|
getNonceStatus: null,
|
||||||
|
gasPriceStatus: null
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should handle gas estimation status actions', () => {
|
||||||
|
const gasEstimationAction: txActions.NetworkAction = {
|
||||||
|
type: TypeKeys.ESTIMATE_GAS_SUCCEEDED
|
||||||
|
};
|
||||||
|
expect(network(INITIAL_STATE, gasEstimationAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
gasEstimationStatus: 'SUCCESS'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle get from status actions', () => {
|
||||||
|
const getFromAction: txActions.NetworkAction = {
|
||||||
|
type: TypeKeys.GET_FROM_SUCCEEDED,
|
||||||
|
payload: 'test'
|
||||||
|
};
|
||||||
|
expect(network(INITIAL_STATE, getFromAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
getFromStatus: 'SUCCESS'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle get nonce status actions', () => {
|
||||||
|
const getNonceAction: txActions.NetworkAction = {
|
||||||
|
type: TypeKeys.GET_NONCE_SUCCEEDED,
|
||||||
|
payload: 'test'
|
||||||
|
};
|
||||||
|
expect(network(INITIAL_STATE, getNonceAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
getNonceStatus: 'SUCCESS'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle gasPriceIntent', () => {
|
||||||
|
const gasPriceAction: txActions.InputGasPriceAction = {
|
||||||
|
type: TypeKeys.GAS_PRICE_INPUT,
|
||||||
|
payload: 'test'
|
||||||
|
};
|
||||||
|
expect(network(INITIAL_STATE, gasPriceAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
gasPriceStatus: 'SUCCESS'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
62
spec/reducers/transaction/signing/sign.spec.ts
Normal file
62
spec/reducers/transaction/signing/sign.spec.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import EthTx from 'ethereumjs-tx';
|
||||||
|
import * as txActions from 'actions/transaction';
|
||||||
|
import { TypeKeys } from 'actions/transaction/constants';
|
||||||
|
import { State, sign } from 'reducers/transaction/sign';
|
||||||
|
|
||||||
|
describe('sign reducer', () => {
|
||||||
|
const INITIAL_STATE: State = {
|
||||||
|
local: { signedTransaction: null },
|
||||||
|
web3: { transaction: null },
|
||||||
|
indexingHash: null,
|
||||||
|
pending: false
|
||||||
|
};
|
||||||
|
it('should handle SIGN_TRANSACTION_REQUESTED', () => {
|
||||||
|
const signTxRequestedAction: txActions.SignTransactionRequestedAction = {
|
||||||
|
type: TypeKeys.SIGN_TRANSACTION_REQUESTED,
|
||||||
|
payload: {} as EthTx
|
||||||
|
};
|
||||||
|
expect(sign(INITIAL_STATE, signTxRequestedAction)).toEqual({ ...INITIAL_STATE, pending: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle SIGN_LOCAL_TRANSACTION_SUCCEEDED', () => {
|
||||||
|
const signedTransaction = new Buffer('test');
|
||||||
|
const indexingHash = 'test';
|
||||||
|
const signLocalTxSucceededAction: txActions.SignLocalTransactionSucceededAction = {
|
||||||
|
type: TypeKeys.SIGN_LOCAL_TRANSACTION_SUCCEEDED,
|
||||||
|
payload: { signedTransaction, indexingHash }
|
||||||
|
};
|
||||||
|
expect(sign(INITIAL_STATE, signLocalTxSucceededAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
pending: false,
|
||||||
|
indexingHash,
|
||||||
|
local: { signedTransaction }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle SIGN_WEB3_TRANSACTION_SUCCEEDED', () => {
|
||||||
|
const transaction = new Buffer('test');
|
||||||
|
const indexingHash = 'test';
|
||||||
|
const signWeb3TxSucceededAction: txActions.SignWeb3TransactionSucceededAction = {
|
||||||
|
type: TypeKeys.SIGN_WEB3_TRANSACTION_SUCCEEDED,
|
||||||
|
payload: { transaction, indexingHash }
|
||||||
|
};
|
||||||
|
expect(sign(INITIAL_STATE, signWeb3TxSucceededAction)).toEqual({
|
||||||
|
...INITIAL_STATE,
|
||||||
|
pending: false,
|
||||||
|
indexingHash,
|
||||||
|
web3: { transaction }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reset', () => {
|
||||||
|
const resetAction: txActions.ResetAction = {
|
||||||
|
type: TypeKeys.RESET,
|
||||||
|
payload: { include: {}, exclude: {} }
|
||||||
|
};
|
||||||
|
const modifiedState: State = {
|
||||||
|
...INITIAL_STATE,
|
||||||
|
pending: true
|
||||||
|
};
|
||||||
|
expect(sign(modifiedState, resetAction)).toEqual(INITIAL_STATE);
|
||||||
|
});
|
||||||
|
});
|
@ -1,46 +1,97 @@
|
|||||||
import { configuredStore } from 'store';
|
import { getResolvedAddress } from 'selectors/ens';
|
||||||
import { Address } from 'libs/units';
|
import { Address } from 'libs/units';
|
||||||
import { call, select, put } from 'redux-saga/effects';
|
import { call, select, put, take } from 'redux-saga/effects';
|
||||||
import { isValidETHAddress, isValidENSAddress } from 'libs/validators';
|
import { isValidETHAddress, isValidENSAddress } from 'libs/validators';
|
||||||
import { setCurrentTo, setField } from 'sagas/transaction/current/currentTo';
|
import { setCurrentTo, setField } from 'sagas/transaction/current/currentTo';
|
||||||
import { isEtherTransaction } from 'selectors/transaction';
|
import { isEtherTransaction } from 'selectors/transaction';
|
||||||
import { cloneableGenerator } from 'redux-saga/utils';
|
import { cloneableGenerator } from 'redux-saga/utils';
|
||||||
import { setToField, setTokenTo } from 'actions/transaction';
|
import { setToField, setTokenTo } from 'actions/transaction';
|
||||||
configuredStore.getState();
|
import { resolveDomainRequested, TypeKeys as ENSTypekeys } from 'actions/ens';
|
||||||
const raw = '0xa';
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
raw,
|
|
||||||
value: Address(raw)
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('setCurrentTo*', () => {
|
describe('setCurrentTo*', () => {
|
||||||
const action: any = {
|
const data = {} as any;
|
||||||
payload: raw
|
|
||||||
};
|
|
||||||
const validAddress = true;
|
|
||||||
const validEns = false;
|
|
||||||
|
|
||||||
const gen = setCurrentTo(action);
|
describe('with valid Ethereum address', () => {
|
||||||
|
const raw = '0xa';
|
||||||
|
const ethAddrPayload = {
|
||||||
|
raw,
|
||||||
|
value: Address(raw)
|
||||||
|
};
|
||||||
|
const ethAddrAction: any = {
|
||||||
|
payload: raw
|
||||||
|
};
|
||||||
|
|
||||||
it('should call isValidETHAddress', () => {
|
data.validEthGen = setCurrentTo(ethAddrAction);
|
||||||
expect(gen.next().value).toEqual(call(isValidETHAddress, raw));
|
it('should call isValidETHAddress', () => {
|
||||||
|
expect(data.validEthGen.next().value).toEqual(call(isValidETHAddress, raw));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call isValidENSAddress', () => {
|
||||||
|
expect(data.validEthGen.next(raw).value).toEqual(call(isValidENSAddress, raw));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call setField', () => {
|
||||||
|
expect(data.validEthGen.next(raw).value).toEqual(call(setField, ethAddrPayload));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call isValidENSAddress', () => {
|
describe('with invalid Ethereum address, valid ENS address', () => {
|
||||||
expect(gen.next(validAddress).value).toEqual(call(isValidENSAddress, raw));
|
const raw = 'testing.eth';
|
||||||
});
|
const resolvedAddress = '0xa';
|
||||||
|
const [domain] = raw.split('.');
|
||||||
|
const ensAddrPayload = {
|
||||||
|
raw,
|
||||||
|
value: null
|
||||||
|
};
|
||||||
|
const ensAddrAction: any = {
|
||||||
|
payload: raw
|
||||||
|
};
|
||||||
|
data.validEnsGen = setCurrentTo(ensAddrAction);
|
||||||
|
|
||||||
it('should call setField', () => {
|
it('should call isValidETHAddress', () => {
|
||||||
expect(gen.next(validEns).value).toEqual(call(setField, payload));
|
expect(data.validEnsGen.next().value).toEqual(call(isValidETHAddress, raw));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be done', () => {
|
it('should call isValidENSAddress', () => {
|
||||||
expect(gen.next().done).toEqual(true);
|
expect(data.validEnsGen.next(false).value).toEqual(call(isValidENSAddress, raw));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call setField', () => {
|
||||||
|
expect(data.validEnsGen.next(true).value).toEqual(call(setField, ensAddrPayload));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should put resolveDomainRequested', () => {
|
||||||
|
expect(data.validEnsGen.next().value).toEqual(put(resolveDomainRequested(domain)));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should take ENS type keys', () => {
|
||||||
|
expect(data.validEnsGen.next().value).toEqual(
|
||||||
|
take([
|
||||||
|
ENSTypekeys.ENS_RESOLVE_DOMAIN_FAILED,
|
||||||
|
ENSTypekeys.ENS_RESOLVE_DOMAIN_SUCCEEDED,
|
||||||
|
ENSTypekeys.ENS_RESOLVE_DOMAIN_CACHED
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should select getResolvedAddress', () => {
|
||||||
|
expect(data.validEnsGen.next().value).toEqual(select(getResolvedAddress, true));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call setField', () => {
|
||||||
|
expect(data.validEnsGen.next(resolvedAddress).value).toEqual(
|
||||||
|
call(setField, { raw, value: Address(resolvedAddress) })
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('setField', () => {
|
describe('setField', () => {
|
||||||
|
const raw = '0xa';
|
||||||
|
const payload = {
|
||||||
|
raw,
|
||||||
|
value: Address(raw)
|
||||||
|
};
|
||||||
const etherTransaction = cloneableGenerator(setField)(payload);
|
const etherTransaction = cloneableGenerator(setField)(payload);
|
||||||
it('should select etherTransaction', () => {
|
it('should select etherTransaction', () => {
|
||||||
expect(etherTransaction.next().value).toEqual(select(isEtherTransaction));
|
expect(etherTransaction.next().value).toEqual(select(isEtherTransaction));
|
||||||
|
@ -46,7 +46,6 @@ describe('valueHandler', () => {
|
|||||||
});
|
});
|
||||||
it('should select getUnit', () => {
|
it('should select getUnit', () => {
|
||||||
gen.invalidDecimal = gen.pass.clone();
|
gen.invalidDecimal = gen.pass.clone();
|
||||||
|
|
||||||
expect(gen.pass.next(decimal).value).toEqual(select(getUnit));
|
expect(gen.pass.next(decimal).value).toEqual(select(getUnit));
|
||||||
expect(gen.invalidNumber.next(decimal).value).toEqual(select(getUnit));
|
expect(gen.invalidNumber.next(decimal).value).toEqual(select(getUnit));
|
||||||
expect(gen.invalidDecimal.next(failCases.invalidDecimal).value).toEqual(select(getUnit));
|
expect(gen.invalidDecimal.next(failCases.invalidDecimal).value).toEqual(select(getUnit));
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { configuredStore } from 'store';
|
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
|
import { SagaIterator, delay } from 'redux-saga';
|
||||||
import { call, put } from 'redux-saga/effects';
|
import { call, put } from 'redux-saga/effects';
|
||||||
import { setDataField, setGasLimitField, setNonceField } from 'actions/transaction/actionCreators';
|
import { setDataField, setGasLimitField, setNonceField } from 'actions/transaction/actionCreators';
|
||||||
import { isValidHex, isValidNonce, gasPriceValidator, gasLimitValidator } from 'libs/validators';
|
import { isValidHex, isValidNonce, gasPriceValidator, gasLimitValidator } from 'libs/validators';
|
||||||
@ -8,12 +8,11 @@ import {
|
|||||||
handleDataInput,
|
handleDataInput,
|
||||||
handleGasLimitInput,
|
handleGasLimitInput,
|
||||||
handleNonceInput,
|
handleNonceInput,
|
||||||
handleGasPriceInput
|
handleGasPriceInput,
|
||||||
|
handleGasPriceInputIntent
|
||||||
} from 'sagas/transaction/fields/fields';
|
} from 'sagas/transaction/fields/fields';
|
||||||
import { cloneableGenerator } from 'redux-saga/utils';
|
import { cloneableGenerator } from 'redux-saga/utils';
|
||||||
import { setGasPriceField } from 'actions/transaction';
|
import { setGasPriceField, inputGasPrice } from 'actions/transaction';
|
||||||
import { SagaIterator } from 'redux-saga';
|
|
||||||
configuredStore.getState();
|
|
||||||
|
|
||||||
const itShouldBeDone = (gen: SagaIterator) => {
|
const itShouldBeDone = (gen: SagaIterator) => {
|
||||||
it('should be done', () => {
|
it('should be done', () => {
|
||||||
@ -142,6 +141,19 @@ describe('handleGasPriceInput*', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('handleGasPriceInputIntent*', () => {
|
||||||
|
const payload = '100.111';
|
||||||
|
const action: any = { payload };
|
||||||
|
const gen = handleGasPriceInputIntent(action);
|
||||||
|
it('should call delay', () => {
|
||||||
|
expect(gen.next().value).toEqual(call(delay, 300));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should put inputGasPrice', () => {
|
||||||
|
expect(gen.next().value).toEqual(put(inputGasPrice(payload)));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('handleNonceInput*', () => {
|
describe('handleNonceInput*', () => {
|
||||||
const payload = '42';
|
const payload = '42';
|
||||||
const action: any = { payload };
|
const action: any = { payload };
|
||||||
|
79
spec/sagas/transaction/sign/signing.spec.ts
Normal file
79
spec/sagas/transaction/sign/signing.spec.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { put, apply, call } from 'redux-saga/effects';
|
||||||
|
import { signLocalTransactionSucceeded, signWeb3TransactionSucceeded } from 'actions/transaction';
|
||||||
|
import { computeIndexingHash } from 'libs/transaction';
|
||||||
|
import {
|
||||||
|
signLocalTransactionHandler,
|
||||||
|
signWeb3TransactionHandler
|
||||||
|
} from 'sagas/transaction/signing/signing';
|
||||||
|
|
||||||
|
describe('signLocalTransactionHandler*', () => {
|
||||||
|
const tx = 'tx';
|
||||||
|
const wallet = {
|
||||||
|
signRawTransaction: jest.fn()
|
||||||
|
};
|
||||||
|
const action: any = { tx, wallet };
|
||||||
|
const signedTransaction = new Buffer('signedTransaction');
|
||||||
|
const indexingHash = 'indexingHash';
|
||||||
|
|
||||||
|
const gen = signLocalTransactionHandler(action);
|
||||||
|
|
||||||
|
it('should apply wallet.signRawTransaction', () => {
|
||||||
|
expect(gen.next().value).toEqual(apply(wallet, wallet.signRawTransaction, [tx]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call computeIndexingHash', () => {
|
||||||
|
expect(gen.next(signedTransaction).value).toEqual(call(computeIndexingHash, signedTransaction));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should put signLocalTransactionSucceeded', () => {
|
||||||
|
expect(gen.next(indexingHash).value).toEqual(
|
||||||
|
put(
|
||||||
|
signLocalTransactionSucceeded({
|
||||||
|
signedTransaction,
|
||||||
|
indexingHash,
|
||||||
|
noVerify: false
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be done', () => {
|
||||||
|
expect(gen.next().done).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('signWeb3TransactionHandler*', () => {
|
||||||
|
const tx = {
|
||||||
|
serialize: jest.fn
|
||||||
|
};
|
||||||
|
const action: any = { tx };
|
||||||
|
const serializedTransaction = new Buffer('tx');
|
||||||
|
const indexingHash = 'indexingHash';
|
||||||
|
|
||||||
|
const gen = signWeb3TransactionHandler(action);
|
||||||
|
|
||||||
|
it('should apply tx.serialize', () => {
|
||||||
|
expect(gen.next().value).toEqual(apply(tx, tx.serialize));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call computeIndexingHash', () => {
|
||||||
|
expect(gen.next(serializedTransaction).value).toEqual(
|
||||||
|
call(computeIndexingHash, serializedTransaction)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should put signWeb3TransactionSucceeded', () => {
|
||||||
|
expect(gen.next(indexingHash).value).toEqual(
|
||||||
|
put(
|
||||||
|
signWeb3TransactionSucceeded({
|
||||||
|
transaction: serializedTransaction,
|
||||||
|
indexingHash
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be done', () => {
|
||||||
|
expect(gen.next().done).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
11
spec/selectors/helpers.ts
Normal file
11
spec/selectors/helpers.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { configuredStore } from '../../common/store';
|
||||||
|
|
||||||
|
export function getInitialState() {
|
||||||
|
return { ...configuredStore.getState() };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function testShallowlyEqual(oldValue: any, newValue: any) {
|
||||||
|
it('should be shallowly equal when called again with the same state', () => {
|
||||||
|
expect(oldValue === newValue).toBeTruthy();
|
||||||
|
});
|
||||||
|
}
|
63
spec/selectors/transaction/broadcast.spec.ts
Normal file
63
spec/selectors/transaction/broadcast.spec.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import {
|
||||||
|
getTransactionStatus,
|
||||||
|
currentTransactionFailed,
|
||||||
|
currentTransactionBroadcasting,
|
||||||
|
currentTransactionBroadcasted,
|
||||||
|
getCurrentTransactionStatus
|
||||||
|
} from 'selectors/transaction';
|
||||||
|
import { getInitialState } from '../helpers';
|
||||||
|
|
||||||
|
describe('broadcast selector', () => {
|
||||||
|
const state = getInitialState();
|
||||||
|
state.transaction = {
|
||||||
|
...state.transaction,
|
||||||
|
broadcast: {
|
||||||
|
...state.transaction.broadcast,
|
||||||
|
testIndexingHash1: {
|
||||||
|
broadcastedHash: 'testBroadcastedHash',
|
||||||
|
broadcastSuccessful: true,
|
||||||
|
isBroadcasting: false,
|
||||||
|
serializedTransaction: new Buffer([1, 2, 3])
|
||||||
|
},
|
||||||
|
testIndexingHash2: {
|
||||||
|
broadcastedHash: 'testBroadcastedHash',
|
||||||
|
broadcastSuccessful: true,
|
||||||
|
isBroadcasting: false,
|
||||||
|
serializedTransaction: new Buffer([1, 2, 3])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sign: {
|
||||||
|
...state.transaction.sign,
|
||||||
|
indexingHash: 'testIndexingHash1',
|
||||||
|
pending: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
it('should check getTransactionState with an indexing hash', () => {
|
||||||
|
expect(getTransactionStatus(state, 'testIndexingHash1')).toEqual(
|
||||||
|
state.transaction.broadcast.testIndexingHash1
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check getCurrentTransactionStatus', () => {
|
||||||
|
expect(getCurrentTransactionStatus(state)).toEqual(
|
||||||
|
state.transaction.broadcast.testIndexingHash2
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check currentTransactionFailed', () => {
|
||||||
|
expect(currentTransactionFailed(state)).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check currentTransactionBroadcasting', () => {
|
||||||
|
expect(currentTransactionBroadcasting(state)).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check currentTransactionBroadcasted', () => {
|
||||||
|
expect(currentTransactionBroadcasted(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false on getCurrentTransactionStatus if no index hash present', () => {
|
||||||
|
state.transaction.sign.indexingHash = null;
|
||||||
|
expect(getCurrentTransactionStatus(state)).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
68
spec/selectors/transaction/current.spec.ts
Normal file
68
spec/selectors/transaction/current.spec.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { Wei } from 'libs/units';
|
||||||
|
import {
|
||||||
|
getCurrentValue,
|
||||||
|
getCurrentTo,
|
||||||
|
isEtherTransaction,
|
||||||
|
isValidCurrentTo,
|
||||||
|
isValidGasPrice,
|
||||||
|
isValidGasLimit,
|
||||||
|
getCurrentToAddressMessage
|
||||||
|
} from 'selectors/transaction';
|
||||||
|
import { getInitialState } from '../helpers';
|
||||||
|
|
||||||
|
describe('current selector', () => {
|
||||||
|
const state = getInitialState();
|
||||||
|
state.transaction = {
|
||||||
|
...state.transaction,
|
||||||
|
fields: {
|
||||||
|
...state.transaction.fields,
|
||||||
|
to: {
|
||||||
|
raw: '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520',
|
||||||
|
value: new Buffer([0, 1, 2, 3])
|
||||||
|
},
|
||||||
|
gasLimit: {
|
||||||
|
raw: '21000',
|
||||||
|
value: Wei('21000')
|
||||||
|
},
|
||||||
|
gasPrice: {
|
||||||
|
raw: '1500',
|
||||||
|
value: Wei('1500')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
...state.transaction.meta,
|
||||||
|
unit: 'ETH',
|
||||||
|
previousUnit: 'ETH'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should get stored receiver address on getCurrentTo', () => {
|
||||||
|
expect(getCurrentTo(state)).toEqual(state.transaction.fields.to);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get stored value on getCurrentValue', () => {
|
||||||
|
expect(getCurrentValue(state)).toEqual(state.transaction.fields.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get message to the receiver', () => {
|
||||||
|
expect(getCurrentToAddressMessage(state)).toEqual({
|
||||||
|
msg: 'Thank you for donating to MyCrypto. TO THE MOON!'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check isValidGasPrice', () => {
|
||||||
|
expect(isValidGasPrice(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check isEtherTransaction', () => {
|
||||||
|
expect(isEtherTransaction(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check isValidGasLimit', () => {
|
||||||
|
expect(isValidGasLimit(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check isValidCurrentTo', () => {
|
||||||
|
expect(isValidCurrentTo(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
88
spec/selectors/transaction/fields.spec.ts
Normal file
88
spec/selectors/transaction/fields.spec.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import BN from 'bn.js';
|
||||||
|
import { Wei } from 'libs/units';
|
||||||
|
import {
|
||||||
|
getData,
|
||||||
|
getFields,
|
||||||
|
getGasLimit,
|
||||||
|
getValue,
|
||||||
|
getTo,
|
||||||
|
getNonce,
|
||||||
|
getGasPrice,
|
||||||
|
getDataExists,
|
||||||
|
getValidGasCost
|
||||||
|
} from 'selectors/transaction';
|
||||||
|
import { getInitialState } from '../helpers';
|
||||||
|
|
||||||
|
describe('fields selector', () => {
|
||||||
|
const state = getInitialState();
|
||||||
|
state.transaction.fields = {
|
||||||
|
to: {
|
||||||
|
raw: '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520',
|
||||||
|
value: new Buffer([0, 1, 2, 3])
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
raw: '',
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
nonce: {
|
||||||
|
raw: '0',
|
||||||
|
value: new BN('0')
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
raw: '1000000000',
|
||||||
|
value: Wei('1000000000')
|
||||||
|
},
|
||||||
|
gasLimit: {
|
||||||
|
raw: '21000',
|
||||||
|
value: Wei('21000')
|
||||||
|
},
|
||||||
|
gasPrice: {
|
||||||
|
raw: '1500',
|
||||||
|
value: Wei('1500')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should get fields from fields store', () => {
|
||||||
|
expect(getFields(state)).toEqual(state.transaction.fields);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get data from fields store', () => {
|
||||||
|
expect(getData(state)).toEqual(state.transaction.fields.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get gas limit from fields store', () => {
|
||||||
|
expect(getGasLimit(state)).toEqual(state.transaction.fields.gasLimit);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get value from fields store', () => {
|
||||||
|
expect(getValue(state)).toEqual(state.transaction.fields.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sould get receiver address from fields store', () => {
|
||||||
|
expect(getTo(state)).toEqual(state.transaction.fields.to);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get nonce from fields store', () => {
|
||||||
|
expect(getNonce(state)).toEqual(state.transaction.fields.nonce);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get gas price from fields store', () => {
|
||||||
|
expect(getGasPrice(state)).toEqual(state.transaction.fields.gasPrice);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check getDataExists', () => {
|
||||||
|
expect(getDataExists(state)).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check when gas cost is valid', () => {
|
||||||
|
expect(getValidGasCost(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check when gas cost is invalid', () => {
|
||||||
|
state.wallet.balance = {
|
||||||
|
wei: Wei('0'),
|
||||||
|
isPending: false
|
||||||
|
};
|
||||||
|
expect(getValidGasCost(state)).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
99
spec/selectors/transaction/helpers.spec.ts
Normal file
99
spec/selectors/transaction/helpers.spec.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import BN from 'bn.js';
|
||||||
|
import { Wei } from 'libs/units';
|
||||||
|
import { reduceToValues, isFullTx } from 'selectors/transaction/helpers';
|
||||||
|
import {
|
||||||
|
getCurrentTo,
|
||||||
|
getCurrentValue,
|
||||||
|
getFields,
|
||||||
|
getUnit,
|
||||||
|
getDataExists,
|
||||||
|
getValidGasCost
|
||||||
|
} from 'selectors/transaction';
|
||||||
|
import { getInitialState } from '../helpers';
|
||||||
|
|
||||||
|
describe('helpers selector', () => {
|
||||||
|
const state = getInitialState();
|
||||||
|
state.transaction = {
|
||||||
|
...state.transaction,
|
||||||
|
meta: {
|
||||||
|
...state.transaction.meta,
|
||||||
|
unit: 'ETH'
|
||||||
|
},
|
||||||
|
fields: {
|
||||||
|
to: {
|
||||||
|
raw: '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520',
|
||||||
|
value: new Buffer([0, 1, 2, 3])
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
raw: '',
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
nonce: {
|
||||||
|
raw: '0',
|
||||||
|
value: new BN('0')
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
raw: '1000000000',
|
||||||
|
value: Wei('1000000000')
|
||||||
|
},
|
||||||
|
gasLimit: {
|
||||||
|
raw: '21000',
|
||||||
|
value: Wei('21000')
|
||||||
|
},
|
||||||
|
gasPrice: {
|
||||||
|
raw: '1500',
|
||||||
|
value: Wei('1500')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should reduce the fields state to its base values', () => {
|
||||||
|
const values = {
|
||||||
|
data: null,
|
||||||
|
gasLimit: Wei('21000'),
|
||||||
|
gasPrice: Wei('1500'),
|
||||||
|
nonce: new BN('0'),
|
||||||
|
to: new Buffer([0, 1, 2, 3]),
|
||||||
|
value: Wei('1000000000')
|
||||||
|
};
|
||||||
|
expect(reduceToValues(state.transaction.fields)).toEqual(values);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check isFullTransaction with full transaction arguments', () => {
|
||||||
|
const currentTo = getCurrentTo(state);
|
||||||
|
const currentValue = getCurrentValue(state);
|
||||||
|
const transactionFields = getFields(state);
|
||||||
|
const unit = getUnit(state);
|
||||||
|
const dataExists = getDataExists(state);
|
||||||
|
const validGasCost = getValidGasCost(state);
|
||||||
|
const isFullTransaction = isFullTx(
|
||||||
|
state,
|
||||||
|
transactionFields,
|
||||||
|
currentTo,
|
||||||
|
currentValue,
|
||||||
|
dataExists,
|
||||||
|
validGasCost,
|
||||||
|
unit
|
||||||
|
);
|
||||||
|
expect(isFullTransaction).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check isFullTransaction without full transaction arguments', () => {
|
||||||
|
const currentTo = { raw: '', value: null };
|
||||||
|
const currentValue = getCurrentValue(state);
|
||||||
|
const transactionFields = getFields(state);
|
||||||
|
const unit = getUnit(state);
|
||||||
|
const dataExists = getDataExists(state);
|
||||||
|
const validGasCost = getValidGasCost(state);
|
||||||
|
const isFullTransaction = isFullTx(
|
||||||
|
state,
|
||||||
|
transactionFields,
|
||||||
|
currentTo,
|
||||||
|
currentValue,
|
||||||
|
dataExists,
|
||||||
|
validGasCost,
|
||||||
|
unit
|
||||||
|
);
|
||||||
|
expect(isFullTransaction).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
70
spec/selectors/transaction/meta.spec.ts
Normal file
70
spec/selectors/transaction/meta.spec.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import {
|
||||||
|
getFrom,
|
||||||
|
getDecimal,
|
||||||
|
getTokenValue,
|
||||||
|
getTokenTo,
|
||||||
|
getUnit,
|
||||||
|
getPreviousUnit,
|
||||||
|
getDecimalFromUnit
|
||||||
|
} from 'selectors/transaction/meta';
|
||||||
|
import { getInitialState } from '../helpers';
|
||||||
|
|
||||||
|
describe('meta tests', () => {
|
||||||
|
const state = getInitialState();
|
||||||
|
(state.transaction.meta = {
|
||||||
|
unit: 'ETH',
|
||||||
|
previousUnit: 'ETH',
|
||||||
|
decimal: 18,
|
||||||
|
tokenValue: {
|
||||||
|
raw: '',
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
tokenTo: {
|
||||||
|
raw: '',
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
from: 'fromAddress'
|
||||||
|
}),
|
||||||
|
(state.customTokens = [
|
||||||
|
{
|
||||||
|
address: '0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7',
|
||||||
|
symbol: 'UNI',
|
||||||
|
decimal: 0
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
it('should get the stored sender address', () => {
|
||||||
|
expect(getFrom(state)).toEqual(state.transaction.meta.from);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the stored decimal', () => {
|
||||||
|
expect(getDecimal(state)).toEqual(state.transaction.meta.decimal);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the token value', () => {
|
||||||
|
expect(getTokenValue(state)).toEqual(state.transaction.meta.tokenValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the token receiver address', () => {
|
||||||
|
expect(getTokenTo(state)).toEqual(state.transaction.meta.tokenTo);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the stored unit', () => {
|
||||||
|
expect(getUnit(state)).toEqual(state.transaction.meta.unit);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the stored previous unit', () => {
|
||||||
|
expect(getPreviousUnit(state)).toEqual(state.transaction.meta.previousUnit);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the decimal for ether', () => {
|
||||||
|
expect(getDecimalFromUnit(state, getUnit(state))).toEqual(18);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the decimal for a token', () => {
|
||||||
|
expect(getDecimalFromUnit(state, 'UNI')).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw error if the token is not found', () => {
|
||||||
|
expect(() => getDecimalFromUnit(state, 'ABC')).toThrowError(`Token ABC not found`);
|
||||||
|
});
|
||||||
|
});
|
48
spec/selectors/transaction/network.spec.ts
Normal file
48
spec/selectors/transaction/network.spec.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { RequestStatus } from 'reducers/transaction/network';
|
||||||
|
import {
|
||||||
|
getNetworkStatus,
|
||||||
|
nonceRequestPending,
|
||||||
|
nonceRequestFailed,
|
||||||
|
isNetworkRequestPending,
|
||||||
|
getGasEstimationPending,
|
||||||
|
getGasLimitEstimationTimedOut
|
||||||
|
} from 'selectors/transaction';
|
||||||
|
import { getInitialState } from '../helpers';
|
||||||
|
|
||||||
|
describe('current selector', () => {
|
||||||
|
const state = getInitialState();
|
||||||
|
state.transaction.network = {
|
||||||
|
...state.transaction.network,
|
||||||
|
gasEstimationStatus: RequestStatus.REQUESTED,
|
||||||
|
getFromStatus: RequestStatus.SUCCEEDED,
|
||||||
|
getNonceStatus: RequestStatus.REQUESTED,
|
||||||
|
gasPriceStatus: RequestStatus.SUCCEEDED
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should get network status', () => {
|
||||||
|
expect(getNetworkStatus(state)).toEqual(state.transaction.network);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check with the store if the nonce request is pending', () => {
|
||||||
|
expect(nonceRequestPending(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check with the store if the nonce request failed', () => {
|
||||||
|
state.transaction.network.getNonceStatus = RequestStatus.FAILED;
|
||||||
|
expect(nonceRequestFailed(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check with the store if the gas estimation is pending', () => {
|
||||||
|
expect(getGasEstimationPending(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check with the store if gas limit estimation timed out', () => {
|
||||||
|
state.transaction.network.gasEstimationStatus = RequestStatus.TIMEDOUT;
|
||||||
|
expect(getGasLimitEstimationTimedOut(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check with the store if network request is pending', () => {
|
||||||
|
state.transaction.network.gasEstimationStatus = RequestStatus.REQUESTED;
|
||||||
|
expect(isNetworkRequestPending(state)).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
44
spec/selectors/transaction/sign.spec.ts
Normal file
44
spec/selectors/transaction/sign.spec.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import {
|
||||||
|
signaturePending,
|
||||||
|
getSignedTx,
|
||||||
|
getWeb3Tx,
|
||||||
|
getSignState,
|
||||||
|
getSerializedTransaction
|
||||||
|
} from 'selectors/transaction/sign';
|
||||||
|
import { getInitialState } from '../helpers';
|
||||||
|
|
||||||
|
describe('sign tests', () => {
|
||||||
|
const state = getInitialState();
|
||||||
|
(state.transaction.sign = {
|
||||||
|
indexingHash: 'testIndexingHash',
|
||||||
|
pending: false,
|
||||||
|
local: {
|
||||||
|
signedTransaction: new Buffer([4, 5, 6, 7])
|
||||||
|
},
|
||||||
|
web3: {
|
||||||
|
transaction: null
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
it('should return whether the current signature is pending', () => {
|
||||||
|
expect(signaturePending(state)).toEqual({
|
||||||
|
isHardwareWallet: false,
|
||||||
|
isSignaturePending: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should should get the stored sign state', () => {
|
||||||
|
expect(getSignState(state)).toEqual(state.transaction.sign);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the signed local transaction state', () => {
|
||||||
|
expect(getSignedTx(state)).toEqual(state.transaction.sign.local.signedTransaction);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the signed web3 transaction state', () => {
|
||||||
|
expect(getWeb3Tx(state)).toEqual(state.transaction.sign.web3.transaction);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the serialized transaction state', () => {
|
||||||
|
expect(getSerializedTransaction(state)).toEqual(new Buffer([4, 5, 6, 7]));
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user