selectors.spec.ts
1 import BN from 'bn.js'; 2 import cloneDeep from 'lodash/cloneDeep'; 3 4 import { Wei } from 'libs/units'; 5 import * as helpers from 'features/helpers'; 6 import * as testHelpers from 'features/testHelpers'; 7 import * as derivedSelectors from 'features/selectors'; 8 import { transactionBroadcastSelectors } from './broadcast'; 9 import { transactionFieldsSelectors } from './fields'; 10 import { transactionMetaSelectors } from './meta'; 11 import { transactionNetworkTypes, transactionNetworkSelectors } from './network'; 12 import { transactionSignSelectors } from './sign'; 13 import * as selectors from './selectors'; 14 15 const initialState = cloneDeep(testHelpers.getInitialState()); 16 17 describe('helpers selector', () => { 18 const state = testHelpers.getInitialState(); 19 state.transaction = { 20 ...state.transaction, 21 meta: { 22 ...state.transaction.meta, 23 unit: 'ETH' 24 }, 25 fields: { 26 to: { 27 raw: '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520', 28 value: new Buffer([0, 1, 2, 3]) 29 }, 30 data: { 31 raw: '', 32 value: null 33 }, 34 nonce: { 35 raw: '0', 36 value: new BN('0') 37 }, 38 value: { 39 raw: '1000000000', 40 value: Wei('1000000000') 41 }, 42 gasLimit: { 43 raw: '21000', 44 value: Wei('21000') 45 }, 46 gasPrice: { 47 raw: '1500', 48 value: Wei('1500') 49 } 50 } 51 }; 52 53 it('should reduce the fields state to its base values', () => { 54 const values = { 55 data: null, 56 gasLimit: Wei('21000'), 57 gasPrice: Wei('1500'), 58 nonce: new BN('0'), 59 to: new Buffer([0, 1, 2, 3]), 60 value: Wei('1000000000') 61 }; 62 expect(helpers.reduceToValues(state.transaction.fields)).toEqual(values); 63 }); 64 65 it('should check isFullTransaction with full transaction arguments', () => { 66 const currentTo = derivedSelectors.getCurrentTo(state); 67 const currentValue = derivedSelectors.getCurrentValue(state); 68 const transactionFields = transactionFieldsSelectors.getFields(state); 69 const unit = derivedSelectors.getUnit(state); 70 const dataExists = selectors.getDataExists(state); 71 const validGasCost = derivedSelectors.getValidGasCost(state); 72 const isFullTransaction = helpers.isFullTx( 73 state, 74 transactionFields, 75 currentTo, 76 currentValue, 77 dataExists, 78 validGasCost, 79 unit 80 ); 81 expect(isFullTransaction).toEqual(true); 82 }); 83 84 it('should check isFullTransaction without full transaction arguments', () => { 85 const currentTo = { raw: '', value: null }; 86 const currentValue = derivedSelectors.getCurrentValue(state); 87 const transactionFields = transactionFieldsSelectors.getFields(state); 88 const unit = derivedSelectors.getUnit(state); 89 const dataExists = selectors.getDataExists(state); 90 const validGasCost = derivedSelectors.getValidGasCost(state); 91 const isFullTransaction = helpers.isFullTx( 92 state, 93 transactionFields, 94 currentTo, 95 currentValue, 96 dataExists, 97 validGasCost, 98 unit 99 ); 100 expect(isFullTransaction).toEqual(false); 101 }); 102 }); 103 104 //#region Broadcast 105 describe('broadcast selector', () => { 106 const state = testHelpers.getInitialState(); 107 state.transaction = { 108 ...state.transaction, 109 broadcast: { 110 ...state.transaction.broadcast, 111 testIndexingHash1: { 112 broadcastedHash: 'testBroadcastedHash', 113 broadcastSuccessful: true, 114 isBroadcasting: false, 115 serializedTransaction: new Buffer([1, 2, 3]) 116 }, 117 testIndexingHash2: { 118 broadcastedHash: 'testBroadcastedHash', 119 broadcastSuccessful: true, 120 isBroadcasting: false, 121 serializedTransaction: new Buffer([1, 2, 3]) 122 } 123 }, 124 sign: { 125 ...state.transaction.sign, 126 indexingHash: 'testIndexingHash1', 127 pending: false 128 } 129 }; 130 it('should check getTransactionState with an indexing hash', () => { 131 expect(transactionBroadcastSelectors.getTransactionStatus(state, 'testIndexingHash1')).toEqual( 132 state.transaction.broadcast.testIndexingHash1 133 ); 134 }); 135 136 it('should check getCurrentTransactionStatus', () => { 137 expect(selectors.getCurrentTransactionStatus(state)).toEqual( 138 state.transaction.broadcast.testIndexingHash2 139 ); 140 }); 141 142 it('should check currentTransactionFailed', () => { 143 expect(selectors.currentTransactionFailed(state)).toEqual(false); 144 }); 145 146 it('should check currentTransactionBroadcasting', () => { 147 expect(selectors.currentTransactionBroadcasting(state)).toEqual(false); 148 }); 149 150 it('should check currentTransactionBroadcasted', () => { 151 expect(selectors.currentTransactionBroadcasted(state)).toEqual(true); 152 }); 153 154 it('should return false on getCurrentTransactionStatus if no index hash present', () => { 155 state.transaction.sign.indexingHash = null; 156 expect(selectors.getCurrentTransactionStatus(state)).toEqual(false); 157 }); 158 }); 159 //#endregion Broadcast 160 161 //#region Current 162 describe('current selector', () => { 163 const state = testHelpers.getInitialState(); 164 state.transaction = { 165 ...state.transaction, 166 fields: { 167 ...state.transaction.fields, 168 to: { 169 raw: '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520', 170 value: new Buffer([0, 1, 2, 3]) 171 }, 172 gasLimit: { 173 raw: '21000', 174 value: Wei('21000') 175 }, 176 gasPrice: { 177 raw: '1500', 178 value: Wei('1500') 179 } 180 }, 181 meta: { 182 ...state.transaction.meta, 183 unit: 'ETH', 184 previousUnit: 'ETH' 185 } 186 }; 187 188 it('should get stored receiver address on getCurrentTo', () => { 189 expect(derivedSelectors.getCurrentTo(state)).toEqual(state.transaction.fields.to); 190 }); 191 192 it('should get stored value on getCurrentValue', () => { 193 expect(derivedSelectors.getCurrentValue(state)).toEqual(state.transaction.fields.value); 194 }); 195 196 it('should get message to the receiver', () => { 197 expect(derivedSelectors.getCurrentToAddressMessage(state)).toEqual({ 198 msg: 'Thank you for donating to MyCrypto. TO THE MOON!' 199 }); 200 }); 201 202 it('should check isValidGasPrice', () => { 203 expect(selectors.isValidGasPrice(state)).toEqual(true); 204 }); 205 206 it('should check isEtherTransaction', () => { 207 expect(derivedSelectors.isEtherTransaction(state)).toEqual(true); 208 }); 209 210 it('should check isValidGasLimit', () => { 211 expect(selectors.isValidGasLimit(state)).toEqual(true); 212 }); 213 214 it('should check isValidCurrentTo', () => { 215 expect(derivedSelectors.isValidCurrentTo(state)).toEqual(true); 216 }); 217 218 it('should check isCurrentToLabelEntry', () => { 219 expect(derivedSelectors.isCurrentToLabelEntry(state)).toEqual(false); 220 221 const otherState = { ...state }; 222 otherState.transaction = { 223 ...state.transaction, 224 fields: { ...state.transaction.fields, to: { ...state.transaction.fields.to, raw: 'derp' } } 225 }; 226 227 expect(derivedSelectors.isCurrentToLabelEntry(otherState)).toEqual(true); 228 }); 229 }); 230 231 //#endregion Current 232 233 //#region Fields 234 describe('fields selector', () => { 235 const state = testHelpers.getInitialState(); 236 state.transaction.fields = { 237 to: { 238 raw: '0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520', 239 value: new Buffer([0, 1, 2, 3]) 240 }, 241 data: { 242 raw: '', 243 value: null 244 }, 245 nonce: { 246 raw: '0', 247 value: new BN('0') 248 }, 249 value: { 250 raw: '1000000000', 251 value: Wei('1000000000') 252 }, 253 gasLimit: { 254 raw: '21000', 255 value: Wei('21000') 256 }, 257 gasPrice: { 258 raw: '1500', 259 value: Wei('1500') 260 } 261 }; 262 263 it('should get fields from fields store', () => { 264 expect(transactionFieldsSelectors.getFields(state)).toEqual(state.transaction.fields); 265 }); 266 267 it('should get data from fields store', () => { 268 expect(transactionFieldsSelectors.getData(state)).toEqual(state.transaction.fields.data); 269 }); 270 271 it('should get gas limit from fields store', () => { 272 expect(transactionFieldsSelectors.getGasLimit(state)).toEqual( 273 state.transaction.fields.gasLimit 274 ); 275 }); 276 277 it('should get value from fields store', () => { 278 expect(transactionFieldsSelectors.getValue(state)).toEqual(state.transaction.fields.value); 279 }); 280 281 it('sould get receiver address from fields store', () => { 282 expect(transactionFieldsSelectors.getTo(state)).toEqual(state.transaction.fields.to); 283 }); 284 285 it('should get nonce from fields store', () => { 286 expect(transactionFieldsSelectors.getNonce(state)).toEqual(state.transaction.fields.nonce); 287 }); 288 289 it('should get gas price from fields store', () => { 290 expect(transactionFieldsSelectors.getGasPrice(state)).toEqual( 291 state.transaction.fields.gasPrice 292 ); 293 }); 294 295 it('should check getDataExists', () => { 296 expect(selectors.getDataExists(state)).toEqual(false); 297 }); 298 299 it('should check when gas cost is valid', () => { 300 expect(derivedSelectors.getValidGasCost(state)).toEqual(true); 301 }); 302 303 it('should check when gas cost is invalid', () => { 304 state.wallet.balance = { 305 wei: Wei('0'), 306 isPending: false 307 }; 308 expect(derivedSelectors.getValidGasCost(state)).toEqual(false); 309 }); 310 }); 311 312 //#endregion Fields 313 314 //#region Meta 315 describe('meta tests', () => { 316 const state = { ...initialState }; 317 (state.transaction.meta = { 318 unit: 'ETH', 319 previousUnit: 'ETH', 320 decimal: 18, 321 tokenValue: { 322 raw: '', 323 value: null 324 }, 325 tokenTo: { 326 raw: '', 327 value: null 328 }, 329 from: 'fromAddress', 330 isContractInteraction: false 331 }), 332 (state.customTokens = [ 333 { 334 address: '0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7', 335 symbol: 'UNI', 336 decimal: 0 337 } 338 ]); 339 340 it('should get the stored sender address', () => { 341 expect(derivedSelectors.getFrom(state)).toEqual(state.transaction.meta.from); 342 }); 343 344 it('should get the stored decimal', () => { 345 expect(transactionMetaSelectors.getDecimal(state)).toEqual(state.transaction.meta.decimal); 346 }); 347 348 it('should get the token value', () => { 349 expect(transactionMetaSelectors.getTokenValue(state)).toEqual( 350 state.transaction.meta.tokenValue 351 ); 352 }); 353 354 it('should get the token receiver address', () => { 355 expect(transactionMetaSelectors.getTokenTo(state)).toEqual(state.transaction.meta.tokenTo); 356 }); 357 358 it('should get the stored unit', () => { 359 expect(derivedSelectors.getUnit(state)).toEqual(state.transaction.meta.unit); 360 }); 361 362 it('should get the stored previous unit', () => { 363 expect(selectors.getPreviousUnit(state)).toEqual(state.transaction.meta.previousUnit); 364 }); 365 366 it('should get the decimal for ether', () => { 367 expect(derivedSelectors.getDecimalFromUnit(state, derivedSelectors.getUnit(state))).toEqual(18); 368 }); 369 370 it('should get the decimal for a token', () => { 371 expect(derivedSelectors.getDecimalFromUnit(state, 'UNI')).toEqual(0); 372 }); 373 374 it('should throw error if the token is not found', () => { 375 expect(() => derivedSelectors.getDecimalFromUnit(state, 'ABC')).toThrowError( 376 `Token ABC not found` 377 ); 378 }); 379 }); 380 381 //#endregion Meta 382 383 //#region Network 384 describe('network selector', () => { 385 const state = testHelpers.getInitialState(); 386 state.transaction.network = { 387 ...state.transaction.network, 388 gasEstimationStatus: transactionNetworkTypes.RequestStatus.REQUESTED, 389 getFromStatus: transactionNetworkTypes.RequestStatus.SUCCEEDED, 390 getNonceStatus: transactionNetworkTypes.RequestStatus.REQUESTED, 391 gasPriceStatus: transactionNetworkTypes.RequestStatus.SUCCEEDED 392 }; 393 394 it('should get network status', () => { 395 expect(transactionNetworkSelectors.getNetworkStatus(state)).toEqual(state.transaction.network); 396 }); 397 398 it('should check with the store if the nonce request is pending', () => { 399 expect(transactionNetworkSelectors.nonceRequestPending(state)).toEqual(true); 400 }); 401 402 it('should check with the store if the nonce request failed', () => { 403 state.transaction.network.getNonceStatus = transactionNetworkTypes.RequestStatus.FAILED; 404 expect(transactionNetworkSelectors.nonceRequestFailed(state)).toEqual(true); 405 }); 406 407 it('should check with the store if the gas estimation is pending', () => { 408 expect(transactionNetworkSelectors.getGasEstimationPending(state)).toEqual(true); 409 }); 410 411 it('should check with the store if gas limit estimation timed out', () => { 412 state.transaction.network.gasEstimationStatus = transactionNetworkTypes.RequestStatus.TIMEDOUT; 413 expect(transactionNetworkSelectors.getGasLimitEstimationTimedOut(state)).toEqual(true); 414 }); 415 416 it('should check with the store if network request is pending', () => { 417 state.transaction.network.gasEstimationStatus = transactionNetworkTypes.RequestStatus.REQUESTED; 418 expect(transactionNetworkSelectors.isNetworkRequestPending(state)).toEqual(true); 419 }); 420 }); 421 422 //#endregion Network 423 424 //#region Sign 425 describe('sign tests', () => { 426 const state = testHelpers.getInitialState(); 427 (state.transaction.sign = { 428 indexingHash: 'testIndexingHash', 429 pending: false, 430 local: { 431 signedTransaction: new Buffer([4, 5, 6, 7]) 432 }, 433 web3: { 434 transaction: null 435 } 436 }), 437 it('should return whether the current signature is pending', () => { 438 expect(derivedSelectors.signaturePending(state)).toEqual({ 439 isHardwareWallet: false, 440 isSignaturePending: false 441 }); 442 }); 443 444 it('should should get the stored sign state', () => { 445 expect(transactionSignSelectors.getSignState(state)).toEqual(state.transaction.sign); 446 }); 447 448 it('should get the signed local transaction state', () => { 449 expect(transactionSignSelectors.getSignedTx(state)).toEqual( 450 state.transaction.sign.local.signedTransaction 451 ); 452 }); 453 454 it('should get the signed web3 transaction state', () => { 455 expect(transactionSignSelectors.getWeb3Tx(state)).toEqual( 456 state.transaction.sign.web3.transaction 457 ); 458 }); 459 460 it('should get the serialized transaction state', () => { 461 expect(derivedSelectors.getSerializedTransaction(state)).toEqual(new Buffer([4, 5, 6, 7])); 462 }); 463 }); 464 465 //#endregion Sign