aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/base.conf.js2
-rw-r--r--test/e2e/beta/contract-test/contract.js134
-rw-r--r--test/e2e/beta/contract-test/index.html33
-rw-r--r--test/e2e/beta/from-import-beta-ui.spec.js236
-rw-r--r--test/e2e/beta/helpers.js71
-rw-r--r--test/e2e/beta/metamask-beta-ui.spec.js782
-rwxr-xr-xtest/e2e/beta/run-all.sh4
-rw-r--r--test/e2e/metamask.spec.js30
-rw-r--r--test/flat.conf.js2
-rw-r--r--test/integration/lib/add-token.js2
-rw-r--r--test/integration/lib/confirm-sig-requests.js21
-rw-r--r--test/integration/lib/currency-localization.js3
-rw-r--r--test/integration/lib/first-time.js5
-rw-r--r--test/integration/lib/mascara-first-time.js2
-rw-r--r--test/integration/lib/send-new-ui.js33
-rw-r--r--test/integration/lib/tx-list-items.js7
-rw-r--r--test/lib/migrations/002.json2
-rw-r--r--test/lib/mock-encryptor.js2
-rw-r--r--test/lib/mock-tx-gen.js6
-rw-r--r--test/lib/react-trigger-change.js112
-rw-r--r--test/lib/util.js6
-rw-r--r--test/mascara.conf.js4
-rw-r--r--test/screens/new-ui.js30
-rw-r--r--test/unit/actions/tx_test.js102
-rw-r--r--test/unit/app/account-import-strategies.spec.js3
-rw-r--r--test/unit/app/controllers/address-book-controller.js2
-rw-r--r--test/unit/app/controllers/detect-tokens-test.js141
-rw-r--r--test/unit/app/controllers/metamask-controller-test.js156
-rw-r--r--test/unit/app/controllers/network-contoller-test.js3
-rw-r--r--test/unit/app/controllers/preferences-controller-test.js25
-rw-r--r--test/unit/app/controllers/transactions/nonce-tracker-test.js14
-rw-r--r--test/unit/app/controllers/transactions/pending-tx-test.js57
-rw-r--r--test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js6
-rw-r--r--test/unit/app/controllers/transactions/tx-controller-test.js21
-rw-r--r--test/unit/app/controllers/transactions/tx-gas-util-test.js1
-rw-r--r--test/unit/app/controllers/transactions/tx-state-history-helper-test.js41
-rw-r--r--test/unit/app/controllers/transactions/tx-state-manager-test.js72
-rw-r--r--test/unit/app/controllers/transactions/tx-utils-test.js4
-rw-r--r--test/unit/app/edge-encryptor-test.js10
-rw-r--r--test/unit/app/nodeify-test.js8
-rw-r--r--test/unit/app/pending-balance-test.js7
-rw-r--r--test/unit/app/seed-phrase-verifier-test.js93
-rw-r--r--test/unit/app/util-test.js2
-rw-r--r--test/unit/components/balance-component-test.js2
-rw-r--r--test/unit/components/bn-as-decimal-input-test.js4
-rw-r--r--test/unit/components/pending-tx-test.js67
-rw-r--r--test/unit/migrations/022-test.js16
-rw-r--r--test/unit/migrations/023-test.js12
-rw-r--r--test/unit/migrations/024-test.js11
-rw-r--r--test/unit/migrations/025-test.js10
-rw-r--r--test/unit/migrations/027-test.js50
-rw-r--r--test/unit/migrations/template-test.js1
-rw-r--r--test/unit/responsive/components/dropdown-test.js58
53 files changed, 1760 insertions, 768 deletions
diff --git a/test/base.conf.js b/test/base.conf.js
index 956dce011..ccb91cc65 100644
--- a/test/base.conf.js
+++ b/test/base.conf.js
@@ -1,7 +1,7 @@
// Karma configuration
// Generated on Mon Sep 11 2017 18:45:48 GMT-0700 (PDT)
-module.exports = function(config) {
+module.exports = function (config) {
return {
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: process.cwd(),
diff --git a/test/e2e/beta/contract-test/contract.js b/test/e2e/beta/contract-test/contract.js
new file mode 100644
index 000000000..8af008dce
--- /dev/null
+++ b/test/e2e/beta/contract-test/contract.js
@@ -0,0 +1,134 @@
+/*
+The `piggybankContract` is compiled from:
+
+ pragma solidity ^0.4.0;
+ contract PiggyBank {
+
+ uint private balance;
+ address public owner;
+
+ function PiggyBank() public {
+ owner = msg.sender;
+ balance = 0;
+ }
+
+ function deposit() public payable returns (uint) {
+ balance += msg.value;
+ return balance;
+ }
+
+ function withdraw(uint withdrawAmount) public returns (uint remainingBal) {
+ require(msg.sender == owner);
+ balance -= withdrawAmount;
+
+ msg.sender.transfer(withdrawAmount);
+
+ return balance;
+ }
+ }
+*/
+
+var piggybankContract = web3.eth.contract([{'constant': false, 'inputs': [{'name': 'withdrawAmount', 'type': 'uint256'}], 'name': 'withdraw', 'outputs': [{'name': 'remainingBal', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'owner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [], 'name': 'deposit', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}])
+const deployButton = document.getElementById('deployButton')
+const depositButton = document.getElementById('depositButton')
+const withdrawButton = document.getElementById('withdrawButton')
+const sendButton = document.getElementById('sendButton')
+const createToken = document.getElementById('createToken')
+const transferTokens = document.getElementById('transferTokens')
+const approveTokens = document.getElementById('approveTokens')
+
+deployButton.addEventListener('click', async function (event) {
+ var piggybank = await piggybankContract.new(
+ {
+ from: web3.eth.accounts[0],
+ data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029',
+ gas: '4700000',
+ }, function (e, contract) {
+ console.log(e, contract)
+ if (typeof contract.address !== 'undefined') {
+ console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash)
+
+ console.log(`contract`, contract)
+
+ depositButton.addEventListener('click', function (event) {
+ contract.deposit({ from: web3.eth.accounts[0], value: '0x3782dace9d900000' }, function (result) {
+ console.log(result)
+ })
+ })
+
+ withdrawButton.addEventListener('click', function (event) {
+ contract.withdraw('0xde0b6b3a7640000', { from: web3.eth.accounts[0] }, function (result) {
+ console.log(result)
+ })
+ })
+ }
+ })
+
+ console.log(piggybank)
+})
+
+sendButton.addEventListener('click', function (event) {
+ web3.eth.sendTransaction({
+ from: web3.eth.accounts[0],
+ to: '0x2f318C334780961FB129D2a6c30D0763d9a5C970',
+ value: '0x29a2241af62c0000',
+ gas: 21000,
+ gasPrice: 20000000000,
+ }, (result) => {
+ console.log(result)
+ })
+})
+
+
+createToken.addEventListener('click', async function (event) {
+ var _initialAmount = 100
+ var _tokenName = 'TST'
+ var _decimalUnits = 0
+ var _tokenSymbol = 'TST'
+ var humanstandardtokenContract = web3.eth.contract([{'constant': true, 'inputs': [], 'name': 'name', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'approve', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'totalSupply', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_from', 'type': 'address'}, {'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transferFrom', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'decimals', 'outputs': [{'name': '', 'type': 'uint8'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}], 'name': 'balanceOf', 'outputs': [{'name': 'balance', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'symbol', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transfer', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}, {'name': '_extraData', 'type': 'bytes'}], 'name': 'approveAndCall', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}, {'name': '_spender', 'type': 'address'}], 'name': 'allowance', 'outputs': [{'name': 'remaining', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'name': '_initialAmount', 'type': 'uint256'}, {'name': '_tokenName', 'type': 'string'}, {'name': '_decimalUnits', 'type': 'uint8'}, {'name': '_tokenSymbol', 'type': 'string'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': false, 'stateMutability': 'nonpayable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_from', 'type': 'address'}, {'indexed': true, 'name': '_to', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Transfer', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_owner', 'type': 'address'}, {'indexed': true, 'name': '_spender', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Approval', 'type': 'event'}])
+ return humanstandardtokenContract.new(
+ _initialAmount,
+ _tokenName,
+ _decimalUnits,
+ _tokenSymbol,
+ {
+ from: web3.eth.accounts[0],
+ data: '0x60806040526040805190810160405280600481526020017f48302e3100000000000000000000000000000000000000000000000000000000815250600690805190602001906200005192919062000143565b503480156200005f57600080fd5b50604051620011f3380380620011f383398101806040528101908080519060200190929190805182019291906020018051906020019092919080518201929190505050836000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360028190555082600390805190602001906200010492919062000143565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906200013892919062000143565b5050505050620001f2565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200018657805160ff1916838001178555620001b7565b82800160010185558215620001b7579182015b82811115620001b657825182559160200191906001019062000199565b5b509050620001c69190620001ca565b5090565b620001ef91905b80821115620001eb576000816000905550600101620001d1565b5090565b90565b610ff180620002026000396000f3006080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100c1578063095ea7b31461015157806318160ddd146101b657806323b872dd146101e1578063313ce5671461026657806354fd4d501461029757806370a082311461032757806395d89b411461037e578063a9059cbb1461040e578063cae9ca5114610473578063dd62ed3e1461051e575b3480156100bb57600080fd5b50600080fd5b3480156100cd57600080fd5b506100d6610595565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101165780820151818401526020810190506100fb565b50505050905090810190601f1680156101435780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015d57600080fd5b5061019c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610633565b604051808215151515815260200191505060405180910390f35b3480156101c257600080fd5b506101cb610725565b6040518082815260200191505060405180910390f35b3480156101ed57600080fd5b5061024c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061072b565b604051808215151515815260200191505060405180910390f35b34801561027257600080fd5b5061027b6109a4565b604051808260ff1660ff16815260200191505060405180910390f35b3480156102a357600080fd5b506102ac6109b7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102ec5780820151818401526020810190506102d1565b50505050905090810190601f1680156103195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561033357600080fd5b50610368600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610a55565b6040518082815260200191505060405180910390f35b34801561038a57600080fd5b50610393610a9d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103d35780820151818401526020810190506103b8565b50505050905090810190601f1680156104005780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041a57600080fd5b50610459600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b3b565b604051808215151515815260200191505060405180910390f35b34801561047f57600080fd5b50610504600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610ca1565b604051808215151515815260200191505060405180910390f35b34801561052a57600080fd5b5061057f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f3e565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561062b5780601f106106005761010080835404028352916020019161062b565b820191906000526020600020905b81548152906001019060200180831161060e57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60025481565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101580156107f7575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b80156108035750600082115b1561099857816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905061099d565b600090505b9392505050565b600460009054906101000a900460ff1681565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a4d5780601f10610a2257610100808354040283529160200191610a4d565b820191906000526020600020905b815481529060010190602001808311610a3057829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b335780601f10610b0857610100808354040283529160200191610b33565b820191906000526020600020905b815481529060010190602001808311610b1657829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610b8b5750600082115b15610c9657816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610c9b565b600090505b92915050565b600082600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a38373ffffffffffffffffffffffffffffffffffffffff1660405180807f72656365697665417070726f76616c28616464726573732c75696e743235362c81526020017f616464726573732c627974657329000000000000000000000000000000000000815250602e01905060405180910390207c01000000000000000000000000000000000000000000000000000000009004338530866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828051906020019080838360005b83811015610ee2578082015181840152602081019050610ec7565b50505050905090810190601f168015610f0f5780820380516001836020036101000a031916815260200191505b509450505050506000604051808303816000875af1925050501515610f3357600080fd5b600190509392505050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a723058200052919e0bc22b5adcd3d320be977df3a1dcc35d1a0160287383ba371900a1c50029',
+ gas: '4700000',
+ gasPrice: '20000000000',
+ }, function (e, contract) {
+ console.log(e, contract)
+ if (typeof contract.address !== 'undefined') {
+ console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash)
+
+ document.getElementById('tokenAddress').innerHTML = contract.address
+
+ transferTokens.addEventListener('click', function (event) {
+ console.log(`event`, event)
+ contract.transfer('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', {
+ from: web3.eth.accounts[0],
+ to: contract.address,
+ data: '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a',
+ gas: 60000,
+ gasPrice: '20000000000',
+ }, function (result) {
+ console.log('result', result)
+ })
+ })
+
+ approveTokens.addEventListener('click', function (event) {
+ contract.approve('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', {
+ from: web3.eth.accounts[0],
+ to: contract.address,
+ data: '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005',
+ gas: 60000,
+ gasPrice: '20000000000',
+ }, function (result) {
+ console.log(result)
+ })
+ })
+ }
+ })
+
+})
+
diff --git a/test/e2e/beta/contract-test/index.html b/test/e2e/beta/contract-test/index.html
new file mode 100644
index 000000000..0d63fd940
--- /dev/null
+++ b/test/e2e/beta/contract-test/index.html
@@ -0,0 +1,33 @@
+<html>
+<head>
+ <title>E2E Test Dapp</title>
+</head>
+<body>
+ <div style="display: flex; flex-flow: column;">
+ <div style="display: flex; font-size: 1.25rem;">Contract</div>
+ <div style="display: flex;">
+ <button id="deployButton">Deploy Contract</button>
+ <button id="depositButton">Deposit</button>
+ <button id="withdrawButton">Withdraw</button>
+ </div>
+ </div>
+ <div style="display: flex; flex-flow: column;">
+ <div style="display: flex; font-size: 1.25rem;">Send eth</div>
+ <div style="display: flex;">
+ <button id="sendButton">Send</button>
+ </div>
+ </div>
+ <div style="display: flex; flex-flow: column;">
+ <div style="display: flex; font-size: 1.25rem;">Send tokens</div>
+ <div id="tokenAddress"></div>
+ <div style="display: flex;">
+ <button id="createToken">Create Token</button>
+ <button id="transferTokens">Transfer Tokens</button>
+ <button id="approveTokens">Approve Tokens</button>
+ </div>
+ </div>
+
+<script src="contract.js"></script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js
index 823c72a3a..06e669e5b 100644
--- a/test/e2e/beta/from-import-beta-ui.spec.js
+++ b/test/e2e/beta/from-import-beta-ui.spec.js
@@ -12,23 +12,24 @@ const {
} = require('../func')
const {
checkBrowserForConsoleErrors,
- loadExtension,
+ closeAllWindowHandlesExcept,
verboseReportOnFailure,
findElement,
findElements,
+ loadExtension,
} = require('./helpers')
describe('Using MetaMask with an existing account', function () {
let extensionId
let driver
- let tokenAddress
const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'
const testAddress = '0xE18035BF8712672935FDB4e5e431b1a0183d2DFC'
+ const testPrivateKey2 = '14abe6f4aab7f9f626fe981c864d0adeb5685f289ac9270c27b8fd790b4235d6'
+ const tinyDelayMs = 500
const regularDelayMs = 1000
const largeDelayMs = regularDelayMs * 2
- const waitingNewPageDelayMs = regularDelayMs * 10
this.timeout(0)
this.bail(true)
@@ -76,36 +77,51 @@ describe('Using MetaMask with an existing account', function () {
describe('New UI setup', async function () {
it('switches to first tab', async function () {
+ await delay(tinyDelayMs)
const [firstTab] = await driver.getAllWindowHandles()
await driver.switchTo().window(firstTab)
await delay(regularDelayMs)
})
- it('use the local network', async function () {
- const networkSelector = await findElement(driver, By.css('#network_component'))
- await networkSelector.click()
- await delay(regularDelayMs)
-
- const [localhost] = await findElements(driver, By.xpath(`//li[contains(text(), 'Localhost')]`))
- await localhost.click()
- await delay(regularDelayMs)
- })
-
it('selects the new UI option', async () => {
- const button = await findElement(driver, By.xpath("//p[contains(text(), 'Try Beta Version')]"))
+ try {
+ const overlay = await findElement(driver, By.css('.full-flex-height'))
+ await driver.wait(until.stalenessOf(overlay))
+ } catch (e) {}
+
+ const button = await findElement(driver, By.xpath("//button[contains(text(), 'Try it now')]"))
await button.click()
await delay(regularDelayMs)
// Close all other tabs
- let [oldUi, infoPage, newUi] = await driver.getAllWindowHandles()
- newUi = newUi || infoPage
- await driver.switchTo().window(oldUi)
- await driver.close()
- if (infoPage !== newUi) {
- await driver.switchTo().window(infoPage)
- await driver.close()
+ const [tab0, tab1, tab2] = await driver.getAllWindowHandles()
+ await driver.switchTo().window(tab0)
+ await delay(tinyDelayMs)
+
+ let selectedUrl = await driver.getCurrentUrl()
+ await delay(tinyDelayMs)
+ if (tab0 && selectedUrl.match(/popup.html/)) {
+ await closeAllWindowHandlesExcept(driver, tab0)
+ } else if (tab1) {
+ await driver.switchTo().window(tab1)
+ selectedUrl = await driver.getCurrentUrl()
+ await delay(tinyDelayMs)
+ if (selectedUrl.match(/popup.html/)) {
+ await closeAllWindowHandlesExcept(driver, tab1)
+ } else if (tab2) {
+ await driver.switchTo().window(tab2)
+ selectedUrl = await driver.getCurrentUrl()
+ selectedUrl.match(/popup.html/) && await closeAllWindowHandlesExcept(driver, tab2)
+ }
+ } else {
+ throw new Error('popup.html not found')
}
- await driver.switchTo().window(newUi)
+ await delay(regularDelayMs)
+ const [appTab] = await driver.getAllWindowHandles()
+ await driver.switchTo().window(appTab)
+ await delay(tinyDelayMs)
+
+ await loadExtension(driver, extensionId)
await delay(regularDelayMs)
const continueBtn = await findElement(driver, By.css('.welcome-screen__button'))
@@ -166,8 +182,7 @@ describe('Using MetaMask with an existing account', function () {
describe('Show account information', () => {
it('shows the correct account address', async () => {
- const detailsButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Details')]`))
- detailsButton.click()
+ await driver.findElement(By.css('.wallet-view__details-button')).click()
await driver.findElement(By.css('.qr-wrapper')).isDisplayed()
await delay(regularDelayMs)
@@ -210,6 +225,16 @@ describe('Using MetaMask with an existing account', function () {
})
describe('Add an account', () => {
+ it('switches to localhost', async () => {
+ const networkDropdown = await findElement(driver, By.css('.network-name'))
+ await networkDropdown.click()
+ await delay(regularDelayMs)
+
+ const [localhost] = await findElements(driver, By.xpath(`//span[contains(text(), 'Localhost')]`))
+ await localhost.click()
+ await delay(largeDelayMs * 2)
+ })
+
it('choose Create Account from the account menu', async () => {
await driver.findElement(By.css('.account-menu__icon')).click()
await delay(regularDelayMs)
@@ -263,8 +288,10 @@ describe('Using MetaMask with an existing account', function () {
await configureGas.click()
await delay(regularDelayMs)
+ const gasModal = await driver.findElement(By.css('span .modal'))
const save = await findElement(driver, By.xpath(`//button[contains(text(), 'Save')]`))
await save.click()
+ await driver.wait(until.stalenessOf(gasModal))
await delay(regularDelayMs)
// Continue to next screen
@@ -289,142 +316,83 @@ describe('Using MetaMask with an existing account', function () {
})
})
- describe('Send ETH from Faucet', () => {
- it('starts a send transaction inside Faucet', async () => {
- await driver.executeScript('window.open("https://faucet.metamask.io")')
- await delay(waitingNewPageDelayMs)
-
- const [extension, faucet] = await driver.getAllWindowHandles()
- await driver.switchTo().window(faucet)
- await delay(regularDelayMs)
-
- const send1eth = await findElement(driver, By.xpath(`//button[contains(text(), '10 ether')]`), 14000)
- await send1eth.click()
- await delay(regularDelayMs)
-
- await driver.switchTo().window(extension)
- await loadExtension(driver, extensionId)
- await delay(regularDelayMs)
-
- const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`), 14000)
- await confirmButton.click()
- await delay(regularDelayMs)
-
- await driver.switchTo().window(faucet)
- await delay(regularDelayMs)
- await driver.close()
- await delay(regularDelayMs)
- await driver.switchTo().window(extension)
- await delay(regularDelayMs)
- await loadExtension(driver, extensionId)
+ describe('Imports an account with private key', () => {
+ it('choose Create Account from the account menu', async () => {
+ await driver.findElement(By.css('.account-menu__icon')).click()
await delay(regularDelayMs)
- })
- })
- describe('Add existing token using search', () => {
- it('clicks on the Add Token button', async () => {
- const addToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Token')]`))
- await addToken.click()
+ const [importAccount] = await findElements(driver, By.xpath(`//div[contains(text(), 'Import Account')]`))
+ await importAccount.click()
await delay(regularDelayMs)
})
- it('picks an existing token', async () => {
- const tokenSearch = await findElement(driver, By.css('#search-tokens'))
- await tokenSearch.sendKeys('BAT')
+ it('enter private key', async () => {
+ const privateKeyInput = await findElement(driver, By.css('#private-key-box'))
+ await privateKeyInput.sendKeys(testPrivateKey2)
await delay(regularDelayMs)
-
- const token = await findElement(driver, By.xpath("//span[contains(text(), 'BAT')]"))
- await token.click()
+ const importButtons = await findElements(driver, By.xpath(`//button[contains(text(), 'Import')]`))
+ await importButtons[0].click()
await delay(regularDelayMs)
+ })
- const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
- await nextScreen.click()
+ it('should show the correct account name', async () => {
+ const [accountName] = await findElements(driver, By.css('.account-name'))
+ assert.equal(await accountName.getText(), 'Account 3')
await delay(regularDelayMs)
-
- const addTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Tokens')]`))
- await addTokens.click()
- await delay(largeDelayMs)
})
- it('renders the balance for the new token', async () => {
- const balance = await findElement(driver, By.css('.tx-view .balance-display .token-amount'))
- const tokenAmount = await balance.getText()
- assert.equal(tokenAmount, '0BAT')
+ it('should show the imported label', async () => {
+ const [importedLabel] = await findElements(driver, By.css('.wallet-view__keyring-label'))
+ assert.equal(await importedLabel.getText(), 'IMPORTED')
await delay(regularDelayMs)
})
})
- describe('Add a custom token from TokenFactory', () => {
- it('creates a new token', async () => {
- await driver.executeScript('window.open("https://tokenfactory.surge.sh/#/factory")')
- await delay(waitingNewPageDelayMs)
-
- const [extension, tokenFactory] = await driver.getAllWindowHandles()
- await driver.switchTo().window(tokenFactory)
- const [
- totalSupply,
- tokenName,
- tokenDecimal,
- tokenSymbol,
- ] = await findElements(driver, By.css('.form-control'))
-
- await totalSupply.sendKeys('100')
- await tokenName.sendKeys('Test')
- await tokenDecimal.sendKeys('0')
- await tokenSymbol.sendKeys('TST')
-
- const createToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Create Token')]`))
- await createToken.click()
- await delay(regularDelayMs)
-
- await driver.switchTo().window(extension)
- await loadExtension(driver, extensionId)
- await delay(regularDelayMs)
-
- const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
- await confirmButton.click()
+ describe('Connects to a Hardware wallet', () => {
+ it('choose Connect Hardware Wallet from the account menu', async () => {
+ await driver.findElement(By.css('.account-menu__icon')).click()
await delay(regularDelayMs)
- await driver.switchTo().window(tokenFactory)
- await delay(regularDelayMs)
- const tokenContactAddress = await driver.findElement(By.css('div > div > div:nth-child(2) > span:nth-child(3)'))
- tokenAddress = await tokenContactAddress.getText()
- await driver.close()
- await driver.switchTo().window(extension)
- await loadExtension(driver, extensionId)
+ const [connectAccount] = await findElements(driver, By.xpath(`//div[contains(text(), 'Connect Hardware Wallet')]`))
+ await connectAccount.click()
await delay(regularDelayMs)
})
- it('clicks on the Add Token button', async () => {
- const addToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Token')]`))
- await addToken.click()
- await delay(regularDelayMs)
+ it('should open the TREZOR Connect popup', async () => {
+ const connectButtons = await findElements(driver, By.xpath(`//button[contains(text(), 'Connect to Trezor')]`))
+ await connectButtons[0].click()
+ await delay(regularDelayMs)
+ const allWindows = await driver.getAllWindowHandles()
+ switch (process.env.SELENIUM_BROWSER) {
+ case 'chrome':
+ assert.equal(allWindows.length, 2)
+ break
+ default:
+ assert.equal(allWindows.length, 1)
+ }
})
- it('picks the new Test token', async () => {
- const addCustomToken = await findElement(driver, By.xpath("//div[contains(text(), 'Custom Token')]"))
- await addCustomToken.click()
- await delay(regularDelayMs)
+ it('should show the "Browser not supported" screen for non Chrome browsers', async () => {
+ if (process.env.SELENIUM_BROWSER !== 'chrome') {
+ const title = await findElements(driver, By.xpath(`//h3[contains(text(), 'Your Browser is not supported...')]`))
+ assert.equal(title.length, 1)
- const newTokenAddress = await findElement(driver, By.css('#custom-address'))
- await newTokenAddress.sendKeys(tokenAddress)
- await delay(regularDelayMs)
+ const downloadChromeButtons = await findElements(driver, By.xpath(`//button[contains(text(), 'Download Google Chrome')]`))
+ assert.equal(downloadChromeButtons.length, 1)
- const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
- await nextScreen.click()
- await delay(regularDelayMs)
+ await downloadChromeButtons[0].click()
+ await delay(regularDelayMs)
- const addTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Tokens')]`))
- await addTokens.click()
- await delay(regularDelayMs)
- })
+ const [newUITab, downloadChromeTab] = await driver.getAllWindowHandles()
- it('renders the balance for the new token', async () => {
- const balance = await findElement(driver, By.css('.tx-view .balance-display .token-amount'))
- await driver.wait(until.elementTextIs(balance, '100TST'))
- const tokenAmount = await balance.getText()
- assert.equal(tokenAmount, '100TST')
- await delay(regularDelayMs)
+ await driver.switchTo().window(downloadChromeTab)
+ await delay(regularDelayMs)
+ const tabUrl = await driver.getCurrentUrl()
+ assert.equal(tabUrl, 'https://www.google.com/chrome/')
+ await driver.close()
+ await delay(regularDelayMs)
+ await driver.switchTo().window(newUITab)
+ }
})
})
})
diff --git a/test/e2e/beta/helpers.js b/test/e2e/beta/helpers.js
index 31c41d8b7..828f87db7 100644
--- a/test/e2e/beta/helpers.js
+++ b/test/e2e/beta/helpers.js
@@ -1,14 +1,21 @@
const fs = require('fs')
const mkdirp = require('mkdirp')
const pify = require('pify')
+const assert = require('assert')
const {until} = require('selenium-webdriver')
+const { delay } = require('../func')
module.exports = {
+ assertElementNotPresent,
checkBrowserForConsoleErrors,
- loadExtension,
- verboseReportOnFailure,
+ closeAllWindowHandlesExcept,
findElement,
findElements,
+ loadExtension,
+ openNewPage,
+ switchToWindowWithTitle,
+ verboseReportOnFailure,
+ waitUntilXWindowHandles,
}
async function loadExtension (driver, extensionId) {
@@ -64,3 +71,63 @@ async function findElement (driver, by, timeout = 10000) {
async function findElements (driver, by, timeout = 10000) {
return driver.wait(until.elementsLocated(by), timeout)
}
+
+async function openNewPage (driver, url) {
+ await driver.executeScript('window.open()')
+ await delay(1000)
+
+ const handles = await driver.getAllWindowHandles()
+ const lastHandle = handles[handles.length - 1]
+ await driver.switchTo().window(lastHandle)
+
+ await driver.get(url)
+ await delay(1000)
+}
+
+async function waitUntilXWindowHandles (driver, x) {
+ const windowHandles = await driver.getAllWindowHandles()
+ if (windowHandles.length === x) return
+ await delay(1000)
+ return await waitUntilXWindowHandles(driver, x)
+}
+
+async function switchToWindowWithTitle (driver, title, windowHandles) {
+ if (!windowHandles) {
+ windowHandles = await driver.getAllWindowHandles()
+ } else if (windowHandles.length === 0) {
+ throw new Error('No window with title: ' + title)
+ }
+ const firstHandle = windowHandles[0]
+ await driver.switchTo().window(firstHandle)
+ const handleTitle = await driver.getTitle()
+
+ if (handleTitle === title) {
+ return firstHandle
+ } else {
+ return await switchToWindowWithTitle(driver, title, windowHandles.slice(1))
+ }
+}
+
+async function closeAllWindowHandlesExcept (driver, exceptions, windowHandles) {
+ exceptions = typeof exceptions === 'string' ? [ exceptions ] : exceptions
+ windowHandles = windowHandles || await driver.getAllWindowHandles()
+ const lastWindowHandle = windowHandles.pop()
+ if (!exceptions.includes(lastWindowHandle)) {
+ await driver.switchTo().window(lastWindowHandle)
+ await delay(1000)
+ await driver.close()
+ await delay(1000)
+ }
+ return windowHandles.length && await closeAllWindowHandlesExcept(driver, exceptions, windowHandles)
+}
+
+async function assertElementNotPresent (webdriver, driver, by) {
+ try {
+ const dataTab = await findElement(driver, by, 4000)
+ if (dataTab) {
+ assert(false, 'Data tab should not be present')
+ }
+ } catch (err) {
+ assert(err instanceof webdriver.error.NoSuchElementError)
+ }
+}
diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js
index d911b91ed..98132e68c 100644
--- a/test/e2e/beta/metamask-beta-ui.spec.js
+++ b/test/e2e/beta/metamask-beta-ui.spec.js
@@ -11,11 +11,16 @@ const {
getExtensionIdFirefox,
} = require('../func')
const {
+ assertElementNotPresent,
+ checkBrowserForConsoleErrors,
+ closeAllWindowHandlesExcept,
findElement,
findElements,
- checkBrowserForConsoleErrors,
loadExtension,
+ openNewPage,
+ switchToWindowWithTitle,
verboseReportOnFailure,
+ waitUntilXWindowHandles,
} = require('./helpers')
describe('MetaMask', function () {
@@ -24,10 +29,9 @@ describe('MetaMask', function () {
let tokenAddress
const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'
- const tinyDelayMs = 1000
+ const tinyDelayMs = 200
const regularDelayMs = tinyDelayMs * 2
const largeDelayMs = regularDelayMs * 2
- const waitingNewPageDelayMs = regularDelayMs * 30
this.timeout(0)
this.bail(true)
@@ -62,7 +66,7 @@ describe('MetaMask', function () {
}
}
if (this.currentTest.state === 'failed') {
- await verboseReportOnFailure(this.currentTest)
+ await verboseReportOnFailure(driver, this.currentTest)
}
})
@@ -72,36 +76,51 @@ describe('MetaMask', function () {
describe('New UI setup', async function () {
it('switches to first tab', async function () {
+ await delay(tinyDelayMs)
const [firstTab] = await driver.getAllWindowHandles()
await driver.switchTo().window(firstTab)
await delay(regularDelayMs)
})
- it('use the local network', async function () {
- const networkSelector = await findElement(driver, By.css('#network_component'))
- await networkSelector.click()
- await delay(regularDelayMs)
-
- const localhost = await findElement(driver, By.xpath(`//li[contains(text(), 'Localhost')]`))
- await localhost.click()
- await delay(regularDelayMs)
- })
-
it('selects the new UI option', async () => {
- const button = await findElement(driver, By.xpath("//p[contains(text(), 'Try Beta Version')]"))
+ try {
+ const overlay = await findElement(driver, By.css('.full-flex-height'))
+ await driver.wait(until.stalenessOf(overlay))
+ } catch (e) {}
+
+ const button = await findElement(driver, By.xpath("//button[contains(text(), 'Try it now')]"))
await button.click()
await delay(regularDelayMs)
// Close all other tabs
- let [oldUi, infoPage, newUi] = await driver.getAllWindowHandles()
- newUi = newUi || infoPage
- await driver.switchTo().window(oldUi)
- await driver.close()
- if (infoPage !== newUi) {
- await driver.switchTo().window(infoPage)
- await driver.close()
+ const [tab0, tab1, tab2] = await driver.getAllWindowHandles()
+ await driver.switchTo().window(tab0)
+ await delay(tinyDelayMs)
+
+ let selectedUrl = await driver.getCurrentUrl()
+ await delay(tinyDelayMs)
+ if (tab0 && selectedUrl.match(/popup.html/)) {
+ await closeAllWindowHandlesExcept(driver, tab0)
+ } else if (tab1) {
+ await driver.switchTo().window(tab1)
+ selectedUrl = await driver.getCurrentUrl()
+ await delay(tinyDelayMs)
+ if (selectedUrl.match(/popup.html/)) {
+ await closeAllWindowHandlesExcept(driver, tab1)
+ } else if (tab2) {
+ await driver.switchTo().window(tab2)
+ selectedUrl = await driver.getCurrentUrl()
+ selectedUrl.match(/popup.html/) && await closeAllWindowHandlesExcept(driver, tab2)
+ }
+ } else {
+ throw new Error('popup.html not found')
}
- await driver.switchTo().window(newUi)
+ await delay(regularDelayMs)
+ const [appTab] = await driver.getAllWindowHandles()
+ await driver.switchTo().window(appTab)
+ await delay(tinyDelayMs)
+
+ await loadExtension(driver, extensionId)
await delay(regularDelayMs)
const continueBtn = await findElement(driver, By.css('.welcome-screen__button'))
@@ -136,6 +155,7 @@ describe('MetaMask', function () {
await driver.executeScript('arguments[0].scrollIntoView(true)', bottomOfTos)
await delay(regularDelayMs)
const acceptTos = await findElement(driver, By.css('.tou button'))
+ driver.wait(until.elementIsEnabled(acceptTos))
await acceptTos.click()
await delay(regularDelayMs)
})
@@ -160,8 +180,10 @@ describe('MetaMask', function () {
let seedPhrase
it('reveals the seed phrase', async () => {
- const revealSeedPhrase = await findElement(driver, By.css('.backup-phrase__secret-blocker'))
- await revealSeedPhrase.click()
+ const byRevealButton = By.css('.backup-phrase__secret-blocker .backup-phrase__reveal-button')
+ await driver.wait(until.elementLocated(byRevealButton, 10000))
+ const revealSeedPhraseButton = await findElement(driver, byRevealButton, 10000)
+ await revealSeedPhraseButton.click()
await delay(regularDelayMs)
seedPhrase = await driver.findElement(By.css('.backup-phrase__secret-words')).getText()
@@ -173,56 +195,88 @@ describe('MetaMask', function () {
await delay(regularDelayMs)
})
- it('can retype the seed phrase', async () => {
- const words = seedPhrase.split(' ')
+ async function retypeSeedPhrase (words, wasReloaded) {
+ try {
+ if (wasReloaded) {
+ const byRevealButton = By.css('.backup-phrase__secret-blocker .backup-phrase__reveal-button')
+ await driver.wait(until.elementLocated(byRevealButton, 10000))
+ const revealSeedPhraseButton = await findElement(driver, byRevealButton, 10000)
+ await revealSeedPhraseButton.click()
+ await delay(regularDelayMs)
- const word0 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[0]}')]`))
- await word0.click()
- await delay(tinyDelayMs)
+ const nextScreen = await findElement(driver, By.css('.backup-phrase button'))
+ await nextScreen.click()
+ await delay(regularDelayMs)
+ }
- const word1 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[1]}')]`))
- await word1.click()
- await delay(tinyDelayMs)
+ const word0 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[0]}')]`), 10000)
- const word2 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[2]}')]`))
- await word2.click()
- await delay(tinyDelayMs)
+ await word0.click()
+ await delay(tinyDelayMs)
- const word3 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[3]}')]`))
- await word3.click()
- await delay(tinyDelayMs)
+ const word1 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[1]}')]`), 10000)
- const word4 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[4]}')]`))
- await word4.click()
- await delay(tinyDelayMs)
+ await word1.click()
+ await delay(tinyDelayMs)
- const word5 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[5]}')]`))
- await word5.click()
- await delay(tinyDelayMs)
+ const word2 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[2]}')]`), 10000)
- const word6 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[6]}')]`))
- await word6.click()
- await delay(tinyDelayMs)
+ await word2.click()
+ await delay(tinyDelayMs)
- const word7 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[7]}')]`))
- await word7.click()
- await delay(tinyDelayMs)
+ const word3 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[3]}')]`), 10000)
- const word8 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[8]}')]`))
- await word8.click()
- await delay(tinyDelayMs)
+ await word3.click()
+ await delay(tinyDelayMs)
- const word9 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[9]}')]`))
- await word9.click()
- await delay(tinyDelayMs)
+ const word4 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[4]}')]`), 10000)
- const word10 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[10]}')]`))
- await word10.click()
- await delay(tinyDelayMs)
+ await word4.click()
+ await delay(tinyDelayMs)
- const word11 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[11]}')]`))
- await word11.click()
- await delay(tinyDelayMs)
+ const word5 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[5]}')]`), 10000)
+
+ await word5.click()
+ await delay(tinyDelayMs)
+
+ const word6 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[6]}')]`), 10000)
+
+ await word6.click()
+ await delay(tinyDelayMs)
+
+ const word7 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[7]}')]`), 10000)
+
+ await word7.click()
+ await delay(tinyDelayMs)
+
+ const word8 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[8]}')]`), 10000)
+
+ await word8.click()
+ await delay(tinyDelayMs)
+
+ const word9 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[9]}')]`), 10000)
+
+ await word9.click()
+ await delay(tinyDelayMs)
+
+ const word10 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[10]}')]`), 10000)
+
+ await word10.click()
+ await delay(tinyDelayMs)
+
+ const word11 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[11]}')]`), 10000)
+ await word11.click()
+ await delay(tinyDelayMs)
+ } catch (e) {
+ await loadExtension(driver, extensionId)
+ await retypeSeedPhrase(words, true)
+ }
+ }
+
+ it('can retype the seed phrase', async () => {
+ const words = seedPhrase.split(' ')
+
+ await retypeSeedPhrase(words)
const confirm = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
await confirm.click()
@@ -230,7 +284,8 @@ describe('MetaMask', function () {
})
it('clicks through the deposit modal', async () => {
- const buyModal = await driver.findElement(By.css('span .modal'))
+ const byBuyModal = By.css('span .modal')
+ const buyModal = await driver.wait(until.elementLocated(byBuyModal))
const closeModal = await findElement(driver, By.css('.page-container__header-close'))
await closeModal.click()
await driver.wait(until.stalenessOf(buyModal))
@@ -244,8 +299,12 @@ describe('MetaMask', function () {
await driver.findElement(By.css('.qr-wrapper')).isDisplayed()
await delay(regularDelayMs)
+ const accountModal = await driver.findElement(By.css('span .modal'))
+
await driver.executeScript("document.querySelector('.account-modal-close').click()")
- await delay(regularDelayMs * 4)
+
+ await driver.wait(until.stalenessOf(accountModal))
+ await delay(regularDelayMs)
})
})
@@ -263,7 +322,7 @@ describe('MetaMask', function () {
it('accepts the account password after lock', async () => {
await driver.findElement(By.id('password')).sendKeys('correct horse battery staple')
await driver.findElement(By.id('password')).sendKeys(Key.ENTER)
- await delay(regularDelayMs * 4)
+ await delay(largeDelayMs * 4)
})
})
@@ -284,10 +343,10 @@ describe('MetaMask', function () {
const create = await findElement(driver, By.xpath(`//button[contains(text(), 'Create')]`))
await create.click()
- await delay(regularDelayMs)
+ await delay(largeDelayMs)
})
- it('should correct account name', async () => {
+ it('should display correct account name', async () => {
const accountName = await findElement(driver, By.css('.account-name'))
assert.equal(await accountName.getText(), '2nd account')
await delay(regularDelayMs)
@@ -315,16 +374,28 @@ describe('MetaMask', function () {
await seedTextArea.sendKeys(testSeedPhrase)
await delay(regularDelayMs)
- await driver.findElement(By.id('password-box')).sendKeys('correct horse battery staple')
- await driver.findElement(By.id('password-box-confirm')).sendKeys('correct horse battery staple')
- await driver.findElement(By.css('button:nth-child(2)')).click()
+ const passwordInputs = await driver.findElements(By.css('input'))
+ await delay(regularDelayMs)
+
+ passwordInputs[0].sendKeys('correct horse battery staple')
+ passwordInputs[1].sendKeys('correct horse battery staple')
+ await driver.findElement(By.css('.first-time-flow__button')).click()
await delay(regularDelayMs)
})
+ it('switches to localhost', async () => {
+ const networkDropdown = await findElement(driver, By.css('.network-name'))
+ await networkDropdown.click()
+ await delay(regularDelayMs)
+
+ const [localhost] = await findElements(driver, By.xpath(`//span[contains(text(), 'Localhost')]`))
+ await localhost.click()
+ await delay(largeDelayMs * 2)
+ })
+
it('balance renders', async () => {
const balance = await findElement(driver, By.css('.balance-display .token-amount'))
- const tokenAmount = await balance.getText()
- assert.equal(tokenAmount, '100.000 ETH')
+ await driver.wait(until.elementTextMatches(balance, /100.+ETH/))
await delay(regularDelayMs)
})
})
@@ -340,13 +411,19 @@ describe('MetaMask', function () {
await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970')
await inputAmount.sendKeys('1')
+ const inputValue = await inputAmount.getAttribute('value')
+ assert.equal(inputValue, '1')
+
// Set the gas limit
const configureGas = await findElement(driver, By.css('.send-v2__gas-fee-display button'))
await configureGas.click()
await delay(regularDelayMs)
+ const gasModal = await driver.findElement(By.css('span .modal'))
+
const save = await findElement(driver, By.xpath(`//button[contains(text(), 'Save')]`))
await save.click()
+ await driver.wait(until.stalenessOf(gasModal))
await delay(regularDelayMs)
// Continue to next screen
@@ -358,103 +435,216 @@ describe('MetaMask', function () {
it('confirms the transaction', async function () {
const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
await confirmButton.click()
- await delay(regularDelayMs)
+ await delay(largeDelayMs)
})
it('finds the transaction in the transactions list', async function () {
const transactions = await findElements(driver, By.css('.tx-list-item'))
assert.equal(transactions.length, 1)
- const txValues = await findElements(driver, By.css('.tx-list-value'))
- assert.equal(txValues.length, 1)
- assert.equal(await txValues[0].getText(), '1 ETH')
+ if (process.env.SELENIUM_BROWSER !== 'firefox') {
+ const txValues = await findElement(driver, By.css('.tx-list-value'))
+ await driver.wait(until.elementTextMatches(txValues, /1\sETH/), 10000)
+ }
})
})
- describe('Send ETH from Faucet', () => {
- it('starts a send transaction inside Faucet', async () => {
- await driver.executeScript('window.open("https://faucet.metamask.io")')
- await delay(waitingNewPageDelayMs)
+ describe('Send ETH from dapp', () => {
+ it('starts a send transaction inside the dapp', async () => {
+ await openNewPage(driver, 'http://127.0.0.1:8080/')
+ await delay(regularDelayMs)
+
+ await waitUntilXWindowHandles(driver, 2)
+ let windowHandles = await driver.getAllWindowHandles()
+ const extension = windowHandles[0]
+ const dapp = windowHandles[1]
- const [extension, faucet] = await driver.getAllWindowHandles()
- await driver.switchTo().window(faucet)
+ await driver.switchTo().window(dapp)
await delay(regularDelayMs)
- const send1eth = await findElement(driver, By.xpath(`//button[contains(text(), '10 ether')]`), 14000)
- await send1eth.click()
+ const send3eth = await findElement(driver, By.xpath(`//button[contains(text(), 'Send')]`), 10000)
+ await send3eth.click()
await delay(regularDelayMs)
- await driver.switchTo().window(extension)
- await loadExtension(driver, extensionId)
+ windowHandles = await driver.getAllWindowHandles()
+ await driver.switchTo().window(windowHandles[2])
await delay(regularDelayMs)
- const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`), 14000)
+ assertElementNotPresent(webdriver, driver, By.xpath(`//li[contains(text(), 'Data')]`))
+
+ const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`), 10000)
await confirmButton.click()
await delay(regularDelayMs)
- await driver.switchTo().window(faucet)
+ await waitUntilXWindowHandles(driver, 2)
+ await driver.switchTo().window(extension)
await delay(regularDelayMs)
- await driver.close()
+ })
+
+ it('finds the transaction in the transactions list', async function () {
+ const transactions = await findElements(driver, By.css('.tx-list-item'))
+ assert.equal(transactions.length, 2)
+
+ const txValues = await findElement(driver, By.css('.tx-list-value'))
+ await driver.wait(until.elementTextMatches(txValues, /3\sETH/), 10000)
+ })
+ })
+
+ describe('Deploy contract and call contract methods', () => {
+ let extension
+ let dapp
+ it('creates a deploy contract transaction', async () => {
+ const windowHandles = await driver.getAllWindowHandles()
+ extension = windowHandles[0]
+ dapp = windowHandles[1]
+ await delay(tinyDelayMs)
+
+ await driver.switchTo().window(dapp)
await delay(regularDelayMs)
+
+ const deployContractButton = await findElement(driver, By.css('#deployButton'))
+ await deployContractButton.click()
+ await delay(regularDelayMs)
+
await driver.switchTo().window(extension)
await delay(regularDelayMs)
- await loadExtension(driver, extensionId)
+
+ const txListItem = await findElement(driver, By.xpath(`//span[contains(text(), 'Contract Deployment')]`))
+ await txListItem.click()
await delay(regularDelayMs)
})
- })
- describe('Add existing token using search', () => {
- it('clicks on the Add Token button', async () => {
- const addToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Token')]`))
- await addToken.click()
+ it('displays the contract creation data', async () => {
+ const dataTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Data')]`))
+ dataTab.click()
+ await delay(regularDelayMs)
+
+ await findElement(driver, By.xpath(`//div[contains(text(), '127.0.0.1')]`))
+
+ const confirmDataDiv = await findElement(driver, By.css('.confirm-page-container-content__data-box'))
+ const confirmDataText = await confirmDataDiv.getText()
+ assert.equal(confirmDataText.match(/0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff/))
+
+ const detailsTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Details')]`))
+ detailsTab.click()
await delay(regularDelayMs)
})
- it('can pick a token from the existing options', async () => {
- const tokenSearch = await findElement(driver, By.css('#search-tokens'))
- await tokenSearch.sendKeys('BAT')
+ it('confirms a deploy contract transaction', async () => {
+ const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
+ await confirmButton.click()
await delay(regularDelayMs)
- const token = await findElement(driver, By.xpath("//span[contains(text(), 'BAT')]"))
- await token.click()
+ const txStatuses = await findElements(driver, By.css('.tx-list-status'))
+ await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/))
+
+ const txAccounts = await findElements(driver, By.css('.tx-list-account'))
+ assert.equal(await txAccounts[0].getText(), 'Contract Deployment')
await delay(regularDelayMs)
+ })
- const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
- await nextScreen.click()
+ it('calls and confirms a contract method where ETH is sent', async () => {
+ await driver.switchTo().window(dapp)
await delay(regularDelayMs)
- const addTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Tokens')]`))
- await addTokens.click()
+ const depositButton = await findElement(driver, By.css('#depositButton'))
+ await depositButton.click()
+ await delay(regularDelayMs)
+
+ await driver.switchTo().window(extension)
await delay(largeDelayMs)
+
+ await findElements(driver, By.css('.tx-list-pending-item-container'))
+ const [txListValue] = await findElements(driver, By.css('.tx-list-value'))
+ await driver.wait(until.elementTextMatches(txListValue, /4\sETH/), 10000)
+ await txListValue.click()
+ await delay(regularDelayMs)
+
+ // Set the gas limit
+ const configureGas = await findElement(driver, By.css('.confirm-detail-row__header-text--edit'))
+ await configureGas.click()
+ await delay(regularDelayMs)
+
+ const gasModal = await driver.findElement(By.css('span .modal'))
+ await driver.wait(until.elementLocated(By.css('.customize-gas__title')))
+
+ const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.customize-gas-input'))
+ await gasPriceInput.clear()
+ await gasPriceInput.sendKeys('10')
+ await gasLimitInput.clear()
+ await gasLimitInput.sendKeys('60001')
+
+ const save = await findElement(driver, By.xpath(`//button[contains(text(), 'Save')]`))
+ await save.click()
+ await delay(regularDelayMs)
+
+ await driver.wait(until.stalenessOf(gasModal))
+
+ const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
+ await confirmButton.click()
+ await delay(regularDelayMs)
+
+ const txStatuses = await findElements(driver, By.css('.tx-list-status'))
+ await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/))
+
+ const txValues = await findElement(driver, By.css('.tx-list-value'))
+ await driver.wait(until.elementTextMatches(txValues, /4\sETH/), 10000)
+
+ const txAccounts = await findElements(driver, By.css('.tx-list-account'))
+ const firstTxAddress = await txAccounts[0].getText()
+ assert(firstTxAddress.match(/^0x\w{8}\.{3}\w{4}$/))
})
- it('renders the balance for the chosen token', async () => {
+ it('calls and confirms a contract method where ETH is received', async () => {
+ await driver.switchTo().window(dapp)
+ await delay(regularDelayMs)
+
+ const withdrawButton = await findElement(driver, By.css('#withdrawButton'))
+ await withdrawButton.click()
+ await delay(regularDelayMs)
+
+ await driver.switchTo().window(extension)
+ await delay(regularDelayMs)
+
+ const txListItem = await findElement(driver, By.css('.tx-list-item'))
+ await txListItem.click()
+ await delay(regularDelayMs)
+
+ const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
+ await confirmButton.click()
+ await delay(regularDelayMs)
+
+ const txStatuses = await findElements(driver, By.css('.tx-list-status'))
+ await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/))
+
+ const txValues = await findElement(driver, By.css('.tx-list-value'))
+ await driver.wait(until.elementTextMatches(txValues, /0\sETH/), 10000)
+
+ await closeAllWindowHandlesExcept(driver, [extension, dapp])
+ await driver.switchTo().window(extension)
+ })
+
+ it('renders the correct ETH balance', async () => {
const balance = await findElement(driver, By.css('.tx-view .balance-display .token-amount'))
- await driver.wait(until.elementTextIs(balance, '0BAT'))
- const tokenAmount = await balance.getText()
- assert.equal(tokenAmount, '0BAT')
await delay(regularDelayMs)
+ if (process.env.SELENIUM_BROWSER !== 'firefox') {
+ await driver.wait(until.elementTextMatches(balance, /^92.*ETH.*$/), 10000)
+ const tokenAmount = await balance.getText()
+ assert.ok(/^92.*ETH.*$/.test(tokenAmount))
+ await delay(regularDelayMs)
+ }
})
})
- describe('Add a custom token from TokenFactory', () => {
+ describe('Add a custom token from a dapp', () => {
it('creates a new token', async () => {
- await driver.executeScript('window.open("https://tokenfactory.surge.sh/#/factory")')
- await delay(waitingNewPageDelayMs)
-
- const [extension, tokenFactory] = await driver.getAllWindowHandles()
- await driver.switchTo().window(tokenFactory)
- const [
- totalSupply,
- tokenName,
- tokenDecimal,
- tokenSymbol,
- ] = await findElements(driver, By.css('.form-control'))
-
- await totalSupply.sendKeys('100')
- await tokenName.sendKeys('Test')
- await tokenDecimal.sendKeys('0')
- await tokenSymbol.sendKeys('TST')
+ const windowHandles = await driver.getAllWindowHandles()
+ const extension = windowHandles[0]
+ const dapp = windowHandles[1]
+ await delay(regularDelayMs * 2)
+
+ await driver.switchTo().window(dapp)
+ await delay(regularDelayMs)
const createToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Create Token')]`))
await createToken.click()
@@ -468,14 +658,19 @@ describe('MetaMask', function () {
await confirmButton.click()
await delay(regularDelayMs)
- await driver.switchTo().window(tokenFactory)
+ await driver.switchTo().window(dapp)
+ await delay(tinyDelayMs)
+
+ const tokenContractAddress = await driver.findElement(By.css('#tokenAddress'))
+ await driver.wait(until.elementTextMatches(tokenContractAddress, /0x/))
+ tokenAddress = await tokenContractAddress.getText()
+
+ await delay(regularDelayMs)
+ await closeAllWindowHandlesExcept(driver, [extension, dapp])
await delay(regularDelayMs)
- const tokenContactAddress = await driver.findElement(By.css('div > div > div:nth-child(2) > span:nth-child(3)'))
- tokenAddress = await tokenContactAddress.getText()
- await driver.close()
await driver.switchTo().window(extension)
- await loadExtension(driver, extensionId)
await delay(regularDelayMs)
+
})
it('clicks on the Add Token button', async () => {
@@ -504,9 +699,330 @@ describe('MetaMask', function () {
it('renders the balance for the new token', async () => {
const balance = await findElement(driver, By.css('.tx-view .balance-display .token-amount'))
- await driver.wait(until.elementTextIs(balance, '100TST'))
+ await driver.wait(until.elementTextMatches(balance, /^100\s*TST\s*$/))
const tokenAmount = await balance.getText()
- assert.equal(tokenAmount, '100TST')
+ assert.ok(/^100\s*TST\s*$/.test(tokenAmount))
+ await delay(regularDelayMs)
+ })
+ })
+
+ describe('Send token from inside MetaMask', () => {
+ let gasModal
+ it('starts to send a transaction', async function () {
+ const sendButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Send')]`))
+ await sendButton.click()
+ await delay(regularDelayMs)
+
+ const inputAddress = await findElement(driver, By.css('input[placeholder="Recipient Address"]'))
+ const inputAmount = await findElement(driver, By.css('.currency-display__input'))
+ await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970')
+ await inputAmount.sendKeys('50')
+
+ // Set the gas limit
+ const configureGas = await findElement(driver, By.css('.send-v2__gas-fee-display button'))
+ await configureGas.click()
+ await delay(regularDelayMs)
+
+ gasModal = await driver.findElement(By.css('span .modal'))
+ })
+
+ it('opens customizes gas modal', async () => {
+ await driver.wait(until.elementLocated(By.css('.send-v2__customize-gas__title')))
+ const save = await findElement(driver, By.xpath(`//button[contains(text(), 'Save')]`))
+ await save.click()
+ await delay(regularDelayMs)
+ })
+
+ it('transitions to the confirm screen', async () => {
+ await driver.wait(until.stalenessOf(gasModal))
+
+ // Continue to next screen
+ const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
+ await nextScreen.click()
+ await delay(regularDelayMs)
+ })
+
+ it('displays the token transfer data', async () => {
+ const dataTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Data')]`))
+ dataTab.click()
+ await delay(regularDelayMs)
+
+ const functionType = await findElement(driver, By.css('.confirm-page-container-content__function-type'))
+ const functionTypeText = await functionType.getText()
+ assert.equal(functionTypeText, 'Transfer')
+
+ const confirmDataDiv = await findElement(driver, By.css('.confirm-page-container-content__data-box'))
+ const confirmDataText = await confirmDataDiv.getText()
+ assert.equal(confirmDataText.match(/0xa9059cbb0000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c97/))
+
+ const detailsTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Details')]`))
+ detailsTab.click()
+ await delay(regularDelayMs)
+ })
+
+ it('submits the transaction', async function () {
+ const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
+ await confirmButton.click()
+ await delay(regularDelayMs)
+ })
+
+ it('finds the transaction in the transactions list', async function () {
+ const transactions = await findElements(driver, By.css('.tx-list-item'))
+ assert.equal(transactions.length, 1)
+
+ const txValues = await findElements(driver, By.css('.tx-list-value'))
+ assert.equal(txValues.length, 1)
+
+ // test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved,
+ // or possibly until we use latest version of firefox in the tests
+ if (process.env.SELENIUM_BROWSER !== 'firefox') {
+ await driver.wait(until.elementTextMatches(txValues[0], /50\sTST/), 10000)
+ }
+
+ const txStatuses = await findElements(driver, By.css('.tx-list-status'))
+ const tx = await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed|Failed/), 10000)
+ assert.equal(await tx.getText(), 'Confirmed')
+ })
+ })
+
+ describe('Send a custom token from dapp', () => {
+ let gasModal
+ it('sends an already created token', async () => {
+ const windowHandles = await driver.getAllWindowHandles()
+ const extension = windowHandles[0]
+ const dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles)
+ await closeAllWindowHandlesExcept(driver, [extension, dapp])
+ await delay(regularDelayMs)
+
+ await driver.switchTo().window(dapp)
+ await delay(tinyDelayMs)
+
+ const transferTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Transfer Tokens')]`))
+ await transferTokens.click()
+
+ await closeAllWindowHandlesExcept(driver, [extension, dapp])
+ await driver.switchTo().window(extension)
+ await delay(largeDelayMs)
+
+ await findElements(driver, By.css('.tx-list-pending-item-container'))
+ const [txListValue] = await findElements(driver, By.css('.tx-list-value'))
+ await driver.wait(until.elementTextMatches(txListValue, /7\sTST/), 10000)
+ await txListValue.click()
+ await delay(regularDelayMs)
+
+ // Set the gas limit
+ const configureGas = await driver.wait(until.elementLocated(By.css('.confirm-detail-row__header-text--edit')), 10000)
+ await configureGas.click()
+ await delay(regularDelayMs)
+
+ gasModal = await driver.findElement(By.css('span .modal'))
+ })
+
+ it('customizes gas', async () => {
+ await driver.wait(until.elementLocated(By.css('.customize-gas__title')))
+
+ const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.customize-gas-input'))
+ await gasPriceInput.clear()
+ await delay(tinyDelayMs)
+ await gasPriceInput.sendKeys('10')
+ await delay(tinyDelayMs)
+ await gasLimitInput.clear()
+ await delay(tinyDelayMs)
+ await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'a'))
+ await gasLimitInput.sendKeys('60000')
+ await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'e'))
+
+ // Needed for different behaviour of input in different versions of firefox
+ const gasLimitInputValue = await gasLimitInput.getAttribute('value')
+ if (gasLimitInputValue === '600001') {
+ await gasLimitInput.sendKeys(Key.BACK_SPACE)
+ }
+
+ const save = await findElement(driver, By.css('.customize-gas__save'))
+ await save.click()
+ await driver.wait(until.stalenessOf(gasModal))
+
+ const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__eth'))
+ assert.equal(await gasFeeInputs[0].getText(), '♦ 0.0006')
+ })
+
+ it('submits the transaction', async function () {
+ const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
+ await confirmButton.click()
+ await delay(regularDelayMs)
+ })
+
+ it('finds the transaction in the transactions list', async function () {
+ const transactions = await findElements(driver, By.css('.tx-list-item'))
+ assert.equal(transactions.length, 2)
+
+ const txValues = await findElements(driver, By.css('.tx-list-value'))
+ await driver.wait(until.elementTextMatches(txValues[0], /7\sTST/))
+ const txStatuses = await findElements(driver, By.css('.tx-list-status'))
+ await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/))
+
+ const walletBalance = await findElement(driver, By.css('.wallet-balance'))
+ await walletBalance.click()
+
+ const tokenListItems = await findElements(driver, By.css('.token-list-item'))
+ await tokenListItems[0].click()
+
+ // test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved,
+ // or possibly until we use latest version of firefox in the tests
+ if (process.env.SELENIUM_BROWSER !== 'firefox') {
+ const tokenBalanceAmount = await findElement(driver, By.css('.token-balance__amount'))
+ assert.equal(await tokenBalanceAmount.getText(), '43')
+ }
+ })
+ })
+
+ describe('Approves a custom token from dapp', () => {
+ let gasModal
+ it('approves an already created token', async () => {
+ const windowHandles = await driver.getAllWindowHandles()
+ const extension = windowHandles[0]
+ const dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles)
+ await closeAllWindowHandlesExcept(driver, [extension, dapp])
+ await delay(regularDelayMs)
+
+ await driver.switchTo().window(dapp)
+ await delay(tinyDelayMs)
+
+ const transferTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Approve Tokens')]`))
+ await transferTokens.click()
+
+ await closeAllWindowHandlesExcept(driver, extension)
+ await driver.switchTo().window(extension)
+ await delay(regularDelayMs)
+
+ const [txListItem] = await findElements(driver, By.css('.tx-list-item'))
+ const [txListValue] = await findElements(driver, By.css('.tx-list-value'))
+ await driver.wait(until.elementTextMatches(txListValue, /0\sETH/))
+ await txListItem.click()
+ await delay(regularDelayMs)
+ })
+
+ it('displays the token approval data', async () => {
+ const dataTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Data')]`))
+ dataTab.click()
+ await delay(regularDelayMs)
+
+ const functionType = await findElement(driver, By.css('.confirm-page-container-content__function-type'))
+ const functionTypeText = await functionType.getText()
+ assert.equal(functionTypeText, 'Approve')
+
+ const confirmDataDiv = await findElement(driver, By.css('.confirm-page-container-content__data-box'))
+ const confirmDataText = await confirmDataDiv.getText()
+ assert.equal(confirmDataText.match(/0x095ea7b30000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c97/))
+
+ const detailsTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Details')]`))
+ detailsTab.click()
+ await delay(regularDelayMs)
+
+ const approvalWarning = await findElement(driver, By.css('.confirm-page-container-warning__warning'))
+ const approvalWarningText = await approvalWarning.getText()
+ assert(approvalWarningText.match(/By approving this/))
+ await delay(regularDelayMs)
+ })
+
+ it('opens the gas edit modal', async () => {
+ const configureGas = await driver.wait(until.elementLocated(By.css('.confirm-detail-row__header-text--edit')))
+ await configureGas.click()
+ await delay(regularDelayMs)
+
+ gasModal = await driver.findElement(By.css('span .modal'))
+ })
+
+ it('customizes gas', async () => {
+ await driver.wait(until.elementLocated(By.css('.customize-gas__title')))
+
+ const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.customize-gas-input'))
+ await gasPriceInput.clear()
+ await delay(tinyDelayMs)
+ await gasPriceInput.sendKeys('10')
+ await delay(tinyDelayMs)
+ await gasLimitInput.clear()
+ await delay(tinyDelayMs)
+ await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'a'))
+ await gasLimitInput.sendKeys('60000')
+ await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'e'))
+
+ // Needed for different behaviour of input in different versions of firefox
+ const gasLimitInputValue = await gasLimitInput.getAttribute('value')
+ if (gasLimitInputValue === '600001') {
+ await gasLimitInput.sendKeys(Key.BACK_SPACE)
+ }
+
+ const save = await findElement(driver, By.css('.customize-gas__save'))
+ await save.click()
+ await driver.wait(until.stalenessOf(gasModal))
+
+ const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__eth'))
+ assert.equal(await gasFeeInputs[0].getText(), '♦ 0.0006')
+ })
+
+ it('submits the transaction', async function () {
+ const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
+ await confirmButton.click()
+ await delay(regularDelayMs)
+ })
+
+ it('finds the transaction in the transactions list', async function () {
+ const txValues = await findElements(driver, By.css('.tx-list-value'))
+ await driver.wait(until.elementTextMatches(txValues[0], /0\sETH/))
+ const txStatuses = await findElements(driver, By.css('.tx-list-status'))
+ await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/))
+ })
+ })
+
+ describe('Hide token', () => {
+ it('hides the token when clicked', async () => {
+ const [hideTokenEllipsis] = await findElements(driver, By.css('.token-list-item__ellipsis'))
+ await hideTokenEllipsis.click()
+
+ const byTokenMenuDropdownOption = By.css('.menu__item--clickable')
+ const tokenMenuDropdownOption = await driver.wait(until.elementLocated(byTokenMenuDropdownOption))
+
+ await tokenMenuDropdownOption.click()
+
+ const confirmHideModal = await findElement(driver, By.css('span .modal'))
+
+ const byHideTokenConfirmationButton = By.css('.hide-token-confirmation__button')
+ const hideTokenConfirmationButton = await driver.wait(until.elementLocated(byHideTokenConfirmationButton))
+ await hideTokenConfirmationButton.click()
+
+ await driver.wait(until.stalenessOf(confirmHideModal))
+ })
+ })
+
+ describe('Add existing token using search', () => {
+ it('clicks on the Add Token button', async () => {
+ const addToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Token')]`))
+ await addToken.click()
+ await delay(regularDelayMs)
+ })
+
+ it('can pick a token from the existing options', async () => {
+ const tokenSearch = await findElement(driver, By.css('#search-tokens'))
+ await tokenSearch.sendKeys('BAT')
+ await delay(regularDelayMs)
+
+ const token = await findElement(driver, By.xpath("//span[contains(text(), 'BAT')]"))
+ await token.click()
+ await delay(regularDelayMs)
+
+ const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
+ await nextScreen.click()
+ await delay(regularDelayMs)
+
+ const addTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Tokens')]`))
+ await addTokens.click()
+ await delay(largeDelayMs)
+ })
+
+ it('renders the balance for the chosen token', async () => {
+ const balance = await findElement(driver, By.css('.tx-view .balance-display .token-amount'))
+ await driver.wait(until.elementTextMatches(balance, /0\sBAT/))
await delay(regularDelayMs)
})
})
diff --git a/test/e2e/beta/run-all.sh b/test/e2e/beta/run-all.sh
index 5916d5614..493e1360a 100755
--- a/test/e2e/beta/run-all.sh
+++ b/test/e2e/beta/run-all.sh
@@ -6,5 +6,5 @@ set -o pipefail
export PATH="$PATH:./node_modules/.bin"
-shell-parallel -s 'npm run ganache:start' -x 'sleep 5 && mocha test/e2e/beta/metamask-beta-ui.spec'
-shell-parallel -s 'npm run ganache:start' -x 'sleep 5 && mocha test/e2e/beta/from-import-beta-ui.spec'
+shell-parallel -s 'npm run ganache:start' -x 'sleep 5 && superstatic test/e2e/beta/contract-test/ --port 8080 --host 127.0.0.1' -x 'sleep 5 && mocha test/e2e/beta/metamask-beta-ui.spec'
+shell-parallel -s 'npm run ganache:start -- -d' -x 'sleep 5 && superstatic test/e2e/beta/contract-test/ --port 8080 --host 127.0.0.1' -x 'sleep 5 && mocha test/e2e/beta/from-import-beta-ui.spec'
diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js
index b0a8fe411..ac7600f09 100644
--- a/test/e2e/metamask.spec.js
+++ b/test/e2e/metamask.spec.js
@@ -4,7 +4,7 @@ const path = require('path')
const assert = require('assert')
const pify = require('pify')
const webdriver = require('selenium-webdriver')
-const { By, Key } = webdriver
+const { By, Key, until } = webdriver
const { delay, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, getExtensionIdChrome, getExtensionIdFirefox } = require('./func')
describe('Metamask popup page', function () {
@@ -59,6 +59,13 @@ describe('Metamask popup page', function () {
await driver.switchTo().window(windowHandles[0])
})
+ it('does not select the new UI option', async () => {
+ await delay(300)
+ const button = await driver.findElement(By.xpath("//button[contains(text(), 'No thanks, maybe later')]"))
+ await button.click()
+ await delay(1000)
+ })
+
it('sets provider type to localhost', async function () {
await delay(300)
await setProviderType('localhost')
@@ -133,9 +140,9 @@ describe('Metamask popup page', function () {
})
it('adds a second account', async function () {
- await driver.findElement(By.css('#app-content > div > div.full-width > div > div:nth-child(2) > span > div')).click()
+ await driver.findElement(By.css('div.full-width > div > div:nth-child(2) > span > div')).click()
await delay(300)
- await driver.findElement(By.css('#app-content > div > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(3) > span')).click()
+ await driver.findElement(By.css('div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(3) > span')).click()
})
it('shows account address', async function () {
@@ -146,7 +153,7 @@ describe('Metamask popup page', function () {
it('logs out of the vault', async () => {
await driver.findElement(By.css('.sandwich-expando')).click()
await delay(500)
- const logoutButton = await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)'))
+ const logoutButton = await driver.findElement(By.css('.menu-droppo > li:nth-child(3)'))
assert.equal(await logoutButton.getText(), 'Log Out')
await logoutButton.click()
})
@@ -178,7 +185,7 @@ describe('Metamask popup page', function () {
it('logs out', async function () {
await driver.findElement(By.css('.sandwich-expando')).click()
await delay(200)
- const logOut = await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)'))
+ const logOut = await driver.findElement(By.css('.menu-droppo > li:nth-child(3)'))
assert.equal(await logOut.getText(), 'Log Out')
await logOut.click()
await delay(300)
@@ -229,8 +236,12 @@ describe('Metamask popup page', function () {
it('confirms transaction', async function () {
await delay(300)
- await driver.findElement(By.css('#pending-tx-form > div.flex-row.flex-space-around.conf-buttons > input')).click()
- await delay(500)
+ const bySubmitButton = By.css('#pending-tx-form > div.flex-row.flex-space-around.conf-buttons > input')
+ const submitButton = await driver.wait(until.elementLocated(bySubmitButton))
+
+ submitButton.click()
+
+ await delay(1500)
})
it('finds the transaction in the transactions list', async function () {
@@ -269,7 +280,8 @@ describe('Metamask popup page', function () {
it('confirms transaction in MetaMask popup', async function () {
const windowHandles = await driver.getAllWindowHandles()
await driver.switchTo().window(windowHandles[windowHandles.length - 1])
- const metamaskSubmit = await driver.findElement(By.css('#pending-tx-form > div.flex-row.flex-space-around.conf-buttons > input'))
+ const byMetamaskSubmit = By.css('#pending-tx-form > div.flex-row.flex-space-around.conf-buttons > input')
+ const metamaskSubmit = await driver.wait(until.elementLocated(byMetamaskSubmit))
await metamaskSubmit.click()
await delay(1000)
})
@@ -330,7 +342,7 @@ describe('Metamask popup page', function () {
await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
}
- async function checkBrowserForConsoleErrors() {
+ async function checkBrowserForConsoleErrors () {
const ignoredLogTypes = ['WARNING']
const ignoredErrorMessages = [
// React throws error warnings on "dataset", but still sets the data-* properties correctly
diff --git a/test/flat.conf.js b/test/flat.conf.js
index cd2dbdcdc..1c9ec3dcd 100644
--- a/test/flat.conf.js
+++ b/test/flat.conf.js
@@ -1,6 +1,6 @@
const getBaseConfig = require('./base.conf.js')
-module.exports = function(config) {
+module.exports = function (config) {
const settings = getBaseConfig(config)
settings.files.push('development/bundle.js')
settings.files.push('test/integration/bundle.js')
diff --git a/test/integration/lib/add-token.js b/test/integration/lib/add-token.js
index 5a08c90cd..6de7574c4 100644
--- a/test/integration/lib/add-token.js
+++ b/test/integration/lib/add-token.js
@@ -75,7 +75,7 @@ async function runAddTokenFlowTest (assert, done) {
tokenWrapper[0].click()
// Click Next button
- let nextButton = await queryAsync($, 'button.btn-primary.btn--large')
+ const nextButton = await queryAsync($, 'button.btn-primary.btn--large')
assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
nextButton[0].click()
diff --git a/test/integration/lib/confirm-sig-requests.js b/test/integration/lib/confirm-sig-requests.js
index d5ed7c77c..dcc25c493 100644
--- a/test/integration/lib/confirm-sig-requests.js
+++ b/test/integration/lib/confirm-sig-requests.js
@@ -2,9 +2,7 @@ const reactTriggerChange = require('react-trigger-change')
const {
timeout,
queryAsync,
- findAsync,
} = require('../../lib/util')
-const PASSWORD = 'password123'
QUnit.module('confirm sig requests')
@@ -16,23 +14,23 @@ QUnit.test('successful confirmation of sig requests', (assert) => {
})
})
-async function runConfirmSigRequestsTest(assert, done) {
- let selectState = await queryAsync($, 'select')
+async function runConfirmSigRequestsTest (assert, done) {
+ const selectState = await queryAsync($, 'select')
selectState.val('confirm sig requests')
reactTriggerChange(selectState[0])
- // await timeout(1000000)
-
const pendingRequestItem = $.find('.tx-list-item.tx-list-pending-item-container.tx-list-clickable')
if (pendingRequestItem[0]) {
pendingRequestItem[0].click()
}
+ await timeout(1000)
+
let confirmSigHeadline = await queryAsync($, '.request-signature__headline')
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
- let confirmSigMessage = await queryAsync($, '.request-signature__notice')
+ const confirmSigMessage = await queryAsync($, '.request-signature__notice')
assert.ok(confirmSigMessage[0].textContent.match(/^Signing\sthis\smessage/))
let confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
@@ -40,16 +38,16 @@ async function runConfirmSigRequestsTest(assert, done) {
let confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large')
confirmSigSignButton[0].click()
-
+ await timeout(1000)
confirmSigHeadline = await queryAsync($, '.request-signature__headline')
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
- assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/))
+ assert.ok(confirmSigRowValue[0].textContent.match(/^#\sTerms\sof\sUse/))
confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large')
confirmSigSignButton[0].click()
-
+ await timeout(1000)
confirmSigHeadline = await queryAsync($, '.request-signature__headline')
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
@@ -60,6 +58,5 @@ async function runConfirmSigRequestsTest(assert, done) {
confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large')
confirmSigSignButton[0].click()
- const txView = await queryAsync($, '.tx-view')
- assert.ok(txView[0], 'Should return to the account details screen after confirming')
+ await timeout(2000)
}
diff --git a/test/integration/lib/currency-localization.js b/test/integration/lib/currency-localization.js
index 7705c9720..d42b7495d 100644
--- a/test/integration/lib/currency-localization.js
+++ b/test/integration/lib/currency-localization.js
@@ -15,10 +15,11 @@ QUnit.test('renders localized currency', (assert) => {
})
})
-async function runCurrencyLocalizationTest(assert, done) {
+async function runCurrencyLocalizationTest (assert, done) {
console.log('*** start runCurrencyLocalizationTest')
const selectState = await queryAsync($, 'select')
selectState.val('currency localization')
+ await timeout(1000)
reactTriggerChange(selectState[0])
await timeout(1000)
const txView = await queryAsync($, '.tx-view')
diff --git a/test/integration/lib/first-time.js b/test/integration/lib/first-time.js
index 052d89518..8cacd7f14 100644
--- a/test/integration/lib/first-time.js
+++ b/test/integration/lib/first-time.js
@@ -27,6 +27,11 @@ async function runFirstTimeUsageTest(assert, done) {
const app = $('#app-content')
+ // Selects new ui
+ const tryNewUIButton = (await findAsync(app, 'button.negative'))[0]
+ tryNewUIButton.click()
+ await timeout()
+
// recurse notices
while (true) {
const button = await findAsync(app, 'button')
diff --git a/test/integration/lib/mascara-first-time.js b/test/integration/lib/mascara-first-time.js
index f43a30c74..8bbdb4410 100644
--- a/test/integration/lib/mascara-first-time.js
+++ b/test/integration/lib/mascara-first-time.js
@@ -42,7 +42,7 @@ async function runFirstTimeUsageTest (assert, done) {
assert.equal(created.textContent, 'Your unique account image', 'unique image screen')
// Agree button
- let button = (await findAsync(app, 'button'))[0]
+ const button = (await findAsync(app, 'button'))[0]
assert.ok(button, 'button present')
button.click()
diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js
index 72e4a8cb1..406863ca6 100644
--- a/test/integration/lib/send-new-ui.js
+++ b/test/integration/lib/send-new-ui.js
@@ -5,8 +5,6 @@ const {
findAsync,
} = require('../../lib/util')
-const PASSWORD = 'password123'
-
QUnit.module('new ui send flow')
QUnit.test('successful send flow', (assert) => {
@@ -54,7 +52,7 @@ async function customizeGas (assert, price, limit, ethFee, usdFee) {
)
}
-async function runSendFlowTest(assert, done) {
+async function runSendFlowTest (assert, done) {
console.log('*** start runSendFlowTest')
const selectState = await queryAsync($, 'select')
selectState.val('send new ui')
@@ -87,7 +85,7 @@ async function runSendFlowTest(assert, done) {
sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 2', 'send from field dropdown changes account name')
- let sendToFieldInput = await queryAsync($, '.send-v2__to-autocomplete__input')
+ const sendToFieldInput = await queryAsync($, '.send-v2__to-autocomplete__input')
sendToFieldInput[0].focus()
const sendToDropdownList = await queryAsync($, '.send-v2__from-dropdown__list')
@@ -114,19 +112,8 @@ async function runSendFlowTest(assert, done) {
errorMessage = $('.send-v2__error')
assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected')
- const sendGasField = await queryAsync($, '.send-v2__gas-fee-display')
- assert.equal(
- sendGasField.find('.currency-display__input-wrapper > input').val(),
- '0.000021',
- 'send gas field should show estimated gas total'
- )
- assert.equal(
- sendGasField.find('.currency-display__converted-value')[0].textContent,
- '$0.03 USD',
- 'send gas field should show estimated gas total converted to USD'
- )
-
await customizeGas(assert, 0, 21000, '0', '$0.00 USD')
+ await customizeGas(assert, 1, 21000, '0.000021', '$0.03 USD')
await customizeGas(assert, 500, 60000, '0.03', '$36.03 USD')
const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button')
@@ -138,18 +125,18 @@ async function runSendFlowTest(assert, done) {
reactTriggerChange(selectState[0])
const confirmFromName = (await queryAsync($, '.sender-to-recipient__sender-name')).first()
- assert.equal(confirmFromName[0].textContent, 'Send Account 2', 'confirm screen should show correct from name')
+ assert.equal(confirmFromName[0].textContent, 'Send Account 4', 'confirm screen should show correct from name')
const confirmToName = (await queryAsync($, '.sender-to-recipient__recipient-name')).last()
assert.equal(confirmToName[0].textContent, 'Send Account 3', 'confirm screen should show correct to name')
- const confirmScreenRows = await queryAsync($, '.confirm-screen-rows')
- const confirmScreenGas = confirmScreenRows.find('.currency-display__converted-value')[0]
- assert.equal(confirmScreenGas.textContent, '$3.60 USD', 'confirm screen should show correct gas')
- const confirmScreenTotal = confirmScreenRows.find('.confirm-screen-row-info')[2]
- assert.equal(confirmScreenTotal.textContent, '$2,405.36 USD', 'confirm screen should show correct total')
+ const confirmScreenRowFiats = await queryAsync($, '.confirm-detail-row__fiat')
+ const confirmScreenGas = confirmScreenRowFiats[0]
+ assert.equal(confirmScreenGas.textContent, '$3.60', 'confirm screen should show correct gas')
+ const confirmScreenTotal = confirmScreenRowFiats[1]
+ assert.equal(confirmScreenTotal.textContent, '$2,405.36', 'confirm screen should show correct total')
- const confirmScreenBackButton = await queryAsync($, '.page-container__back-button')
+ const confirmScreenBackButton = await queryAsync($, '.confirm-page-container-header__back-button')
confirmScreenBackButton[0].click()
const sendFromFieldItemInEdit = await queryAsync($, '.account-list-item')
diff --git a/test/integration/lib/tx-list-items.js b/test/integration/lib/tx-list-items.js
index 4856b3852..b7aca44d5 100644
--- a/test/integration/lib/tx-list-items.js
+++ b/test/integration/lib/tx-list-items.js
@@ -1,6 +1,5 @@
const reactTriggerChange = require('../../lib/react-trigger-change')
const {
- timeout,
queryAsync,
findAsync,
} = require('../../lib/util')
@@ -15,7 +14,7 @@ QUnit.test('renders list items successfully', (assert) => {
})
})
-async function runTxListItemsTest(assert, done) {
+async function runTxListItemsTest (assert, done) {
console.log('*** start runTxListItemsTest')
const selectState = await queryAsync($, 'select')
selectState.val('tx list items')
@@ -32,8 +31,8 @@ async function runTxListItemsTest(assert, done) {
assert.equal($(unapprovedTx).hasClass('tx-list-pending-item-container'), true, 'unapprovedTx has the correct class')
const retryTx = txListItems[1]
- const retryTxLink = await findAsync($(retryTx), '.tx-list-item-retry-link')
- assert.equal(retryTxLink[0].textContent, 'Increase the gas price on your transaction', 'retryTx has expected link')
+ const retryTxLink = await findAsync($(retryTx), '.tx-list-item-retry-container span')
+ assert.equal(retryTxLink[0].textContent, 'Taking too long? Increase the gas price on your transaction', 'retryTx has expected link')
const approvedTx = txListItems[2]
const approvedTxRenderedStatus = await findAsync($(approvedTx), '.tx-list-status')
diff --git a/test/lib/migrations/002.json b/test/lib/migrations/002.json
index 9ad3d4cfe..15820ded5 100644
--- a/test/lib/migrations/002.json
+++ b/test/lib/migrations/002.json
@@ -1 +1 @@
-{"meta":{"version":20},"data":{"config":{},"NetworkController":{"provider":{"type":"mainnet","rpcTarget":"https://mainnet.infura.io/metamask"},"network":"1"},"firstTimeInfo":{"version":"3.12.1","date":1517351427287},"NoticeController":{"noticesList":[{"read":false,"date":"Thu Feb 09 2017","title":"Terms of Use","body":"# Terms of Use #\n\n**THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.**\n\n_Our Terms of Use have been updated as of September 5, 2016_\n\n## 1. Acceptance of Terms ##\n\nMetaMask provides a platform for managing Ethereum (or \"ETH\") accounts, and allowing ordinary websites to interact with the Ethereum blockchain, while keeping the user in control over what transactions they approve, through our website located at[ ](http://metamask.io)[https://metamask.io/](https://metamask.io/) and browser plugin (the \"Site\") — which includes text, images, audio, code and other materials (collectively, the “Content”) and all of the features, and services provided. The Site, and any other features, tools, materials, or other services offered from time to time by MetaMask are referred to here as the “Service.” Please read these Terms of Use (the “Terms” or “Terms of Use”) carefully before using the Service. By using or otherwise accessing the Services, or clicking to accept or agree to these Terms where that option is made available, you (1) accept and agree to these Terms (2) consent to the collection, use, disclosure and other handling of information as described in our Privacy Policy and (3) any additional terms, rules and conditions of participation issued by MetaMask from time to time. If you do not agree to the Terms, then you may not access or use the Content or Services.\n\n## 2. Modification of Terms of Use ##\n\nExcept for Section 13, providing for binding arbitration and waiver of class action rights, MetaMask reserves the right, at its sole discretion, to modify or replace the Terms of Use at any time. The most current version of these Terms will be posted on our Site. You shall be responsible for reviewing and becoming familiar with any such modifications. Use of the Services by you after any modification to the Terms constitutes your acceptance of the Terms of Use as modified.\n\n\n\n## 3. Eligibility ##\n\nYou hereby represent and warrant that you are fully able and competent to enter into the terms, conditions, obligations, affirmations, representations and warranties set forth in these Terms and to abide by and comply with these Terms.\n\nMetaMask is a global platform and by accessing the Content or Services, you are representing and warranting that, you are of the legal age of majority in your jurisdiction as is required to access such Services and Content and enter into arrangements as provided by the Service. You further represent that you are otherwise legally permitted to use the service in your jurisdiction including owning cryptographic tokens of value, and interacting with the Services or Content in any way. You further represent you are responsible for ensuring compliance with the laws of your jurisdiction and acknowledge that MetaMask is not liable for your compliance with such laws.\n\n## 4 Account Password and Security ##\n\nWhen setting up an account within MetaMask, you will be responsible for keeping your own account secrets, which may be a twelve-word seed phrase, an account file, or other locally stored secret information. MetaMask encrypts this information locally with a password you provide, that we never send to our servers. You agree to (a) never use the same password for MetaMask that you have ever used outside of this service; (b) keep your secret information and password confidential and do not share them with anyone else; (c) immediately notify MetaMask of any unauthorized use of your account or breach of security. MetaMask cannot and will not be liable for any loss or damage arising from your failure to comply with this section.\n\n## 5. Representations, Warranties, and Risks ##\n\n### 5.1. Warranty Disclaimer ###\n\nYou expressly understand and agree that your use of the Service is at your sole risk. The Service (including the Service and the Content) are provided on an \"AS IS\" and \"as available\" basis, without warranties of any kind, either express or implied, including, without limitation, implied warranties of merchantability, fitness for a particular purpose or non-infringement. You acknowledge that MetaMask has no control over, and no duty to take any action regarding: which users gain access to or use the Service; what effects the Content may have on you; how you may interpret or use the Content; or what actions you may take as a result of having been exposed to the Content. You release MetaMask from all liability for you having acquired or not acquired Content through the Service. MetaMask makes no representations concerning any Content contained in or accessed through the Service, and MetaMask will not be responsible or liable for the accuracy, copyright compliance, legality or decency of material contained in or accessed through the Service.\n\n### 5.2 Sophistication and Risk of Cryptographic Systems ###\n\nBy utilizing the Service or interacting with the Content or platform in any way, you represent that you understand the inherent risks associated with cryptographic systems; and warrant that you have an understanding of the usage and intricacies of native cryptographic tokens, like Ether (ETH) and Bitcoin (BTC), smart contract based tokens such as those that follow the Ethereum Token Standard (https://github.com/ethereum/EIPs/issues/20), and blockchain-based software systems.\n\n### 5.3 Risk of Regulatory Actions in One or More Jurisdictions ###\n\nMetaMask and ETH could be impacted by one or more regulatory inquiries or regulatory action, which could impede or limit the ability of MetaMask to continue to develop, or which could impede or limit your ability to access or use the Service or Ethereum blockchain.\n\n### 5.4 Risk of Weaknesses or Exploits in the Field of Cryptography ###\n\nYou acknowledge and understand that Cryptography is a progressing field. Advances in code cracking or technical advances such as the development of quantum computers may present risks to cryptocurrencies and Services of Content, which could result in the theft or loss of your cryptographic tokens or property. To the extent possible, MetaMask intends to update the protocol underlying Services to account for any advances in cryptography and to incorporate additional security measures, but does not guarantee or otherwise represent full security of the system. By using the Service or accessing Content, you acknowledge these inherent risks.\n\n### 5.5 Volatility of Crypto Currencies ###\n\nYou understand that Ethereum and other blockchain technologies and associated currencies or tokens are highly volatile due to many factors including but not limited to adoption, speculation, technology and security risks. You also acknowledge that the cost of transacting on such technologies is variable and may increase at any time causing impact to any activities taking place on the Ethereum blockchain. You acknowledge these risks and represent that MetaMask cannot be held liable for such fluctuations or increased costs.\n\n### 5.6 Application Security ###\n\nYou acknowledge that Ethereum applications are code subject to flaws and acknowledge that you are solely responsible for evaluating any code provided by the Services or Content and the trustworthiness of any third-party websites, products, smart-contracts, or Content you access or use through the Service. You further expressly acknowledge and represent that Ethereum applications can be written maliciously or negligently, that MetaMask cannot be held liable for your interaction with such applications and that such applications may cause the loss of property or even identity. This warning and others later provided by MetaMask in no way evidence or represent an on-going duty to alert you to all of the potential risks of utilizing the Service or Content.\n\n## 6. Indemnity ##\n\nYou agree to release and to indemnify, defend and hold harmless MetaMask and its parents, subsidiaries, affiliates and agencies, as well as the officers, directors, employees, shareholders and representatives of any of the foregoing entities, from and against any and all losses, liabilities, expenses, damages, costs (including attorneys’ fees and court costs) claims or actions of any kind whatsoever arising or resulting from your use of the Service, your violation of these Terms of Use, and any of your acts or omissions that implicate publicity rights, defamation or invasion of privacy. MetaMask reserves the right, at its own expense, to assume exclusive defense and control of any matter otherwise subject to indemnification by you and, in such case, you agree to cooperate with MetaMask in the defense of such matter.\n\n## 7. Limitation on liability ##\n\nYOU ACKNOWLEDGE AND AGREE THAT YOU ASSUME FULL RESPONSIBILITY FOR YOUR USE OF THE SITE AND SERVICE. YOU ACKNOWLEDGE AND AGREE THAT ANY INFORMATION YOU SEND OR RECEIVE DURING YOUR USE OF THE SITE AND SERVICE MAY NOT BE SECURE AND MAY BE INTERCEPTED OR LATER ACQUIRED BY UNAUTHORIZED PARTIES. YOU ACKNOWLEDGE AND AGREE THAT YOUR USE OF THE SITE AND SERVICE IS AT YOUR OWN RISK. RECOGNIZING SUCH, YOU UNDERSTAND AND AGREE THAT, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, NEITHER METAMASK NOR ITS SUPPLIERS OR LICENSORS WILL BE LIABLE TO YOU FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY OR OTHER DAMAGES OF ANY KIND, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER TANGIBLE OR INTANGIBLE LOSSES OR ANY OTHER DAMAGES BASED ON CONTRACT, TORT, STRICT LIABILITY OR ANY OTHER THEORY (EVEN IF METAMASK HAD BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES), RESULTING FROM THE SITE OR SERVICE; THE USE OR THE INABILITY TO USE THE SITE OR SERVICE; UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; STATEMENTS OR CONDUCT OF ANY THIRD PARTY ON THE SITE OR SERVICE; ANY ACTIONS WE TAKE OR FAIL TO TAKE AS A RESULT OF COMMUNICATIONS YOU SEND TO US; HUMAN ERRORS; TECHNICAL MALFUNCTIONS; FAILURES, INCLUDING PUBLIC UTILITY OR TELEPHONE OUTAGES; OMISSIONS, INTERRUPTIONS, LATENCY, DELETIONS OR DEFECTS OF ANY DEVICE OR NETWORK, PROVIDERS, OR SOFTWARE (INCLUDING, BUT NOT LIMITED TO, THOSE THAT DO NOT PERMIT PARTICIPATION IN THE SERVICE); ANY INJURY OR DAMAGE TO COMPUTER EQUIPMENT; INABILITY TO FULLY ACCESS THE SITE OR SERVICE OR ANY OTHER WEBSITE; THEFT, TAMPERING, DESTRUCTION, OR UNAUTHORIZED ACCESS TO, IMAGES OR OTHER CONTENT OF ANY KIND; DATA THAT IS PROCESSED LATE OR INCORRECTLY OR IS INCOMPLETE OR LOST; TYPOGRAPHICAL, PRINTING OR OTHER ERRORS, OR ANY COMBINATION THEREOF; OR ANY OTHER MATTER RELATING TO THE SITE OR SERVICE.\n\nSOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES. ACCORDINGLY, SOME OF THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU.\n\n## 8. Our Proprietary Rights ##\n\nAll title, ownership and intellectual property rights in and to the Service are owned by MetaMask or its licensors. You acknowledge and agree that the Service contains proprietary and confidential information that is protected by applicable intellectual property and other laws. Except as expressly authorized by MetaMask, you agree not to copy, modify, rent, lease, loan, sell, distribute, perform, display or create derivative works based on the Service, in whole or in part. MetaMask issues a license for MetaMask, found [here](https://github.com/MetaMask/metamask-plugin/blob/master/LICENSE). For information on other licenses utilized in the development of MetaMask, please see our attribution page at: [https://metamask.io/attributions.html](https://metamask.io/attributions.html)\n\n## 9. Links ##\n\nThe Service provides, or third parties may provide, links to other World Wide Web or accessible sites, applications or resources. Because MetaMask has no control over such sites, applications and resources, you acknowledge and agree that MetaMask is not responsible for the availability of such external sites, applications or resources, and does not endorse and is not responsible or liable for any content, advertising, products or other materials on or available from such sites or resources. You further acknowledge and agree that MetaMask shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such site or resource.\n\n## 10. Termination and Suspension ##\n\nMetaMask may terminate or suspend all or part of the Service and your MetaMask access immediately, without prior notice or liability, if you breach any of the terms or conditions of the Terms. Upon termination of your access, your right to use the Service will immediately cease.\n\nThe following provisions of the Terms survive any termination of these Terms: INDEMNITY; WARRANTY DISCLAIMERS; LIMITATION ON LIABILITY; OUR PROPRIETARY RIGHTS; LINKS; TERMINATION; NO THIRD PARTY BENEFICIARIES; BINDING ARBITRATION AND CLASS ACTION WAIVER; GENERAL INFORMATION.\n\n## 11. No Third Party Beneficiaries ##\n\nYou agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.\n\n## 12. Notice and Procedure For Making Claims of Copyright Infringement ##\n\nIf you believe that your copyright or the copyright of a person on whose behalf you are authorized to act has been infringed, please provide MetaMask’s Copyright Agent a written Notice containing the following information:\n\n· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;\n\n· a description of the copyrighted work or other intellectual property that you claim has been infringed;\n\n· a description of where the material that you claim is infringing is located on the Service;\n\n· your address, telephone number, and email address;\n\n· a statement by you that you have a good faith belief that the disputed use is not authorized by the copyright owner, its agent, or the law;\n\n· a statement by you, made under penalty of perjury, that the above information in your Notice is accurate and that you are the copyright or intellectual property owner or authorized to act on the copyright or intellectual property owner's behalf.\n\nMetaMask’s Copyright Agent can be reached at:\n\nEmail: copyright [at] metamask [dot] io\n\nMail:\n\nAttention:\n\nMetaMask Copyright ℅ ConsenSys\n\n49 Bogart Street\n\nBrooklyn, NY 11206\n\n## 13. Binding Arbitration and Class Action Waiver ##\n\nPLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT\n\n### 13.1 Initial Dispute Resolution ###\n\nThe parties shall use their best efforts to engage directly to settle any dispute, claim, question, or disagreement and engage in good faith negotiations which shall be a condition to either party initiating a lawsuit or arbitration.\n\n### 13.2 Binding Arbitration ###\n\nIf the parties do not reach an agreed upon solution within a period of 30 days from the time informal dispute resolution under the Initial Dispute Resolution provision begins, then either party may initiate binding arbitration as the sole means to resolve claims, subject to the terms set forth below. Specifically, all claims arising out of or relating to these Terms (including their formation, performance and breach), the parties’ relationship with each other and/or your use of the Service shall be finally settled by binding arbitration administered by the American Arbitration Association in accordance with the provisions of its Commercial Arbitration Rules and the supplementary procedures for consumer related disputes of the American Arbitration Association (the \"AAA\"), excluding any rules or procedures governing or permitting class actions.\n\nThe arbitrator, and not any federal, state or local court or agency, shall have exclusive authority to resolve all disputes arising out of or relating to the interpretation, applicability, enforceability or formation of these Terms, including, but not limited to any claim that all or any part of these Terms are void or voidable, or whether a claim is subject to arbitration. The arbitrator shall be empowered to grant whatever relief would be available in a court under law or in equity. The arbitrator’s award shall be written, and binding on the parties and may be entered as a judgment in any court of competent jurisdiction.\n\nThe parties understand that, absent this mandatory provision, they would have the right to sue in court and have a jury trial. They further understand that, in some instances, the costs of arbitration could exceed the costs of litigation and the right to discovery may be more limited in arbitration than in court.\n\n### 13.3 Location ###\n\nBinding arbitration shall take place in New York. You agree to submit to the personal jurisdiction of any federal or state court in New York County, New York, in order to compel arbitration, to stay proceedings pending arbitration, or to confirm, modify, vacate or enter judgment on the award entered by the arbitrator.\n\n### 13.4 Class Action Waiver ###\n\nThe parties further agree that any arbitration shall be conducted in their individual capacities only and not as a class action or other representative action, and the parties expressly waive their right to file a class action or seek relief on a class basis. YOU AND METAMASK AGREE THAT EACH MAY BRING CLAIMS AGAINST THE OTHER ONLY IN YOUR OR ITS INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING. If any court or arbitrator determines that the class action waiver set forth in this paragraph is void or unenforceable for any reason or that an arbitration can proceed on a class basis, then the arbitration provision set forth above shall be deemed null and void in its entirety and the parties shall be deemed to have not agreed to arbitrate disputes.\n\n### 13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims ###\n\nNotwithstanding the parties' decision to resolve all disputes through arbitration, either party may bring an action in state or federal court to protect its intellectual property rights (\"intellectual property rights\" means patents, copyrights, moral rights, trademarks, and trade secrets, but not privacy or publicity rights). Either party may also seek relief in a small claims court for disputes or claims within the scope of that court’s jurisdiction.\n\n### 13.6 30-Day Right to Opt Out ###\n\nYou have the right to opt-out and not be bound by the arbitration and class action waiver provisions set forth above by sending written notice of your decision to opt-out to the following address: MetaMask ℅ ConsenSys, 49 Bogart Street, Brooklyn NY 11206 and via email at legal-opt@metamask.io. The notice must be sent within 30 days of September 6, 2016 or your first use of the Service, whichever is later, otherwise you shall be bound to arbitrate disputes in accordance with the terms of those paragraphs. If you opt-out of these arbitration provisions, MetaMask also will not be bound by them.\n\n### 13.7 Changes to This Section ###\n\nMetaMask will provide 60-days’ notice of any changes to this section. Changes will become effective on the 60th day, and will apply prospectively only to any claims arising after the 60th day.\n\nFor any dispute not subject to arbitration you and MetaMask agree to submit to the personal and exclusive jurisdiction of and venue in the federal and state courts located in New York, New York. You further agree to accept service of process by mail, and hereby waive any and all jurisdictional and venue defenses otherwise available.\n\nThe Terms and the relationship between you and MetaMask shall be governed by the laws of the State of New York without regard to conflict of law provisions.\n\n## 14. General Information ##\n\n### 14.1 Entire Agreement ###\n\nThese Terms (and any additional terms, rules and conditions of participation that MetaMask may post on the Service) constitute the entire agreement between you and MetaMask with respect to the Service and supersedes any prior agreements, oral or written, between you and MetaMask. In the event of a conflict between these Terms and the additional terms, rules and conditions of participation, the latter will prevail over the Terms to the extent of the conflict.\n\n### 14.2 Waiver and Severability of Terms ###\n\nThe failure of MetaMask to exercise or enforce any right or provision of the Terms shall not constitute a waiver of such right or provision. If any provision of the Terms is found by an arbitrator or court of competent jurisdiction to be invalid, the parties nevertheless agree that the arbitrator or court should endeavor to give effect to the parties' intentions as reflected in the provision, and the other provisions of the Terms remain in full force and effect.\n\n### 14.3 Statute of Limitations ###\n\nYou agree that regardless of any statute or law to the contrary, any claim or cause of action arising out of or related to the use of the Service or the Terms must be filed within one (1) year after such claim or cause of action arose or be forever barred.\n\n### 14.4 Section Titles ###\n\nThe section titles in the Terms are for convenience only and have no legal or contractual effect.\n\n### 14.5 Communications ###\n\nUsers with questions, complaints or claims with respect to the Service may contact us using the relevant contact information set forth above and at communications@metamask.io.\n\n## 15 Related Links ##\n\n**[Terms of Use](https://metamask.io/terms.html)**\n\n**[Privacy](https://metamask.io/privacy.html)**\n\n**[Attributions](https://metamask.io/attributions.html)**\n\n","id":0},{"read":false,"date":"Mon May 08 2017","title":"Privacy Notice","body":"MetaMask is beta software. \n\nWhen you log in to MetaMask, your current account is visible to every new site you visit.\n\nFor your privacy, for now, please sign out of MetaMask when you're done using a site.\n\nAlso, by default, you will be signed in to a test network. To use real Ether, you must connect to the main network manually in the top left network menu.\n\n","id":2}]},"BlacklistController":{"phishing":{"version":2,"tolerance":2,"fuzzylist":["metamask.io","myetherwallet.com","cryptokitties.co"],"whitelist":["metahash.io","metahash.net","metahash.org","cryptotitties.com","cryptocities.net","cryptoshitties.co","cryptotitties.fun","cryptokitties.forsale","cryptokitties.care","metamate.cc","metamesh.tech","ico.nexus.social","metamesh.org","metatask.io","metmask.com","metarasa.com","metapack.com","metacase.com","metafas.nl","metamako.com","metamast.com","metamax.ru","metadesk.io","metadisk.com","metallsk.ru","metamag.fr","metamaks.ru","metamap.ru","metamaps.cc","metamats.com","metamax.by","metamax.com","metamax.io","metamuse.net","metarank.com","metaxas.com","megamas2.ru","metamask.io","myetherwallet.com","myethlerwallet.com","ethereum.org","myetheroll.com","myetherapi.com","ledgerwallet.com","databrokerdao.com","etherscan.io","etherid.org","ether.cards","etheroll.com","ethnews.com","ethex.market","ethereumdev.io","ethereumdev.kr","dether.io","ethermine.org","slaask.com","etherbtc.io","ethereal.capital","etherisc.com","m.famalk.net","etherecho.com","ethereum.os.tc","theethereum.wiki","metajack.im","etherhub.io","ethereum.network","ethereum.link","ethereum.com","prethereum.org","ethereumj.io","etheraus.com","ethereum.dev","1ethereum.ru","ethereum.nz","nethereum.com","metabank.com","metamas.com","aventus.io","metabase.com","etherdelta.com","metabase.one","cryptokitties.co"],"blacklist":["myetherwallet.uk.com","kodakone.cc","nyeihitervvallet.com","xn--myeterwalet-cm8eoi.com","nucleus.foundation","beetoken-ico.com","data-token.com","tron-labs.com","ocoin.tech","aionfoundation.com","ico-telegram.org","nyeihitervvallat.com","telegramcoin.us","daddi.cloud","daditoken.com","blockarray.org","dadi-cloud.net","wanchainfunding.org","ico-telegram.io","iconfoundation.site","iost.co","beetoken-ico.eu","cindicator.network","wanchainetwork.org","wamchain.org","wanchainltd.org","wanchainalliance.org","nucleus-vision.net","ledgerwallet.by","nucleuss.vision","myenhterswailct.com","cobin-hood.com","wanchainfoundation.org","xn--polniex-ex4c.com","xn--polniex-s1a.com","xn--polonex-ieb.com","xn--polonex-sza.com","xn--polonex-zw4c.com","xn--polonix-ws4c.com","xn--polonix-y8a.com","xn--pooniex-ojb.com","gramico.info","dimnsions.network","www-gemini.com","login-kucoin.net","venchain.foundation","grampreico.com","tgram.cc","ton-gramico.com","wwwpaywithink.com","coniomi.com","paywithnk.com","paywithlnk.com","iluminatto.com.br","pundix.eu","xn--bttrx-esay.com","xn--bttrex-w8a.com","xn--bnance-bwa.com","xn--shpeshift-11a.com","xn--shapeshif-ts6d.com","xn--shapshift-yf7d.com","wwwbluzelle.com","bluzelie.com","nucleus-vision.org","omisegonetwork.site","etlherzero.com","etlherdelta.com","xn--condesk-0ya.com","xn--condesk-sfb.com","xn--coindsk-vs4c.com","iexecplatform.com","tongramico.com","nucleus-vision.eu","intchain.network","wanchain.cloud","bluzelle-ico.com","ethzero-wallet.com","xn--metherwalle-jb9et7d.com","xn--coinesk-jo3c.com","venchainfoundation.com","myenhtersvvailot.com","ether-zero.net","ins.foundation","nastoken.org","telcointoken.com","ether0.org","eterzero.org","bluzelle-ico.eu","bleuzelle.com","appcoinstoken.org","xn--quanstamp-8s6d.com","myehntersvvailct.com","myeherwalllet.com","ico-bluzelle.com","bluzelle.im","bluzelle.one","bluzele.sale","bluzele.co","sether.ws","xn--myetherwalet-6gf.com","xn--rnyethewaliet-om1g.com","rnyethervailet.com","mvetherwaliet.com","rnyetherwailet.com","myethervaliet.com","rnyethervaliet.com","mvetherwalilet.com","xn--myethewalie-3ic0947g.com","xn--mthrwallet-z6ac3y.com","xn--myeherwalie-vici.com","xn--myethervvalie-8vc.com","xn--mythrwallt-06acf.com","xn--mtherwallet-y9a6y.com","myetherwallet.applytoken.tk","ethereum-zero.com","quanstamptoken.tk","bluzelle.network","ether-wallet.org","tron-wallet.info","appcoinsproject.com","vechain.foundation","tronlab.site","tronlabs.network","bluzelle.cc","ethblender.com","ethpaperwallet.net","waltontoken.org","icoselfkey.org","etherzeroclaim.com","etherzero.promo","bluzelle.pro","token-selfkey.org","xn--etherdlta-0f7d.com","sether.in","xn--ttrex-ysa9423c.com","bluzelle.eu","bluzelle.site","gifto.tech","xn--os-g7s.com","selfkey.co","xn--myeherwalet-ns8exy.com","xn--coinelegraph-wk5f.com","dai-stablecoin.com","eos-token.org","venchain.org","gatcoins.io","deepbrainchain.co","myetherwalililet.info","myehvterwallet.com","myehterumswallet.com","nucleusico.com","tronlab.tech","0x-project.com","gift-token-events.mywebcommunity.org","funfairtoken.org","breadtokenapp.com","cloudpetstore.com","myethwalilet.com","selfkeys.org","wallet-ethereum.com","xn--methrwallt-26ar0z.com","xn--mytherwllet-r8a0c.com","bluzelle.promo","tokensale.bluzelle.promo","cedarlake.org","marketingleads4u.com","cashaa.co","xn--inance-hrb.com","wanchain.tech","zenprolocol.com","ethscan.io","etherscan.in","props-project.com","zilliaq.com","reqestnetwork.com","etherdelta.pw","ethereum-giveaway.org","mysimpletoken.org","binancc.com","blnance.org","elherdelta.io","xn--hapeshit-ez9c2y.com","tenxwallet.co","singularitynet.info","mytlherwaliet.info","iconmainnet.ml","tokenselfkey.org","xn--myetewallet-cm8e5y.com","envione.org","myetherwalletet.com","claimbcd.com","ripiocreditnetwork.in","xn--yeterwallet-ml8euo.com","ethclassicwallet.info","myltherwallet.ru.com","etherdella.com","xn--yeterwallet-bm8ewn.com","singularty.net","cloudkitties.co","iconfoundation.io","kittystat.com","gatscoin.io","singularitynet.in","sale.canay.io","canay.io","wabicoin.co","envion.top","sirinslabs.com","tronlab.co","paxful.com.ng","changellyli.com","ethereum-code.com","xn--plonex-6va6c.com","envion.co","envion.cc","envion.site","ethereumchain.info","xn--envon-1sa.org","xn--btstamp-rfb.net","envlon.org","envion-ico.org","spectivvr.org","sirinlbs.com","ethereumdoubler.life","xn--myetherwllet-fnb.com","sirin-labs.com","sirin-labs.org","envion.one","envion.live","propsproject.org","propsprojects.com","decentralland.org","xn--metherwalet-ns8ep4b.com","redpulsetoken.co","propsproject.tech","xn--myeterwalet-nl8emj.com","powrerledger.com","cryptokitties.com","sirinlabs.pro","sirinlabs.co","sirnlabs.com","superbitcoin-blockchain.info","hellobloom.me","mobus.network","powrrledger.com","xn--myeherwalet-ms8eyy.com","qlink-ico.com","gatcoin.in","tokensale.gamefllp.com","gamefllp.com","xn--myeherwalle-vici.com","xn--myetherwalet-39b.com","xn--polonex-ffb.com","xn--birex-leba.com","raiden-network.org","sirintabs.com","xn--metherwallt-79a30a.com","xn--myethrwllet-2kb3p.com","myethlerwallet.eu","xn--btrex-b4a.com","powerrledger.com","xn--cointeegraph-wz4f.com","myerherwalet.com","qauntstanp.com","myetherermwallet.com","xn--myethewalet-ns8eqq.com","xn--nvion-hza.org","nnyetherwallelt.ru.com","ico-wacoin.com","xn--myeterwalet-nl8enj.com","bitcoinsilver.io","t0zero.com","tokensale.gizer.in","gizer.in","wabitoken.com","gladius.ws","xn--metherwallt-8bb4w.com","quanttstamp.com","gladius.im","ethereumstorage.net","powerledgerr.com","xn--myeherwallet-4j5f.com","quamtstamp.com","quntstamp.com","xn--changely-j59c.com","shapeshlft.com","coinbasenews.co.uk","xn--metherwallet-hmb.com","envoin.org","powerledger.com","bitstannp.net","xn--myetherallet-4k5fwn.com","xn--coinbas-pya.com","requestt.network","oracls.network","sirinlabs.website","powrledger.io","slackconfirm.com","shape-shift.io","oracles-network.org","xn--myeherwalle-zb9eia.com","blockstack.one","urtust.io","bittrex.one","t0-ico.com","xn--cinbase-90a.com","xn--metherwalet-ns8ez1g.com","tzero-ico.com","tzero.su","tzero.website","blockstack.network","ico-tzero.com","spectre.site","tzero.pw","spectre-ai.net","xn--waxtokn-y8a.com","dmarket.pro","bittrex.com11648724328774.cf","bittrex.com1987465798.ga","autcus.org","t-zero.org","xn--zero-zxb.com","myetherwalletfork.com","blokclbain.info","datum.sale","spectre-ai.org","powerledgr.com","simpletoken.live","sale.simpletoken.live","qauntstamp.com","raiden-network.com","metalpayme.com","quantstamp-ico.com","myetherwailetclient.com","biockchain.biz","wallets-blockchain.com","golemairdrop.com","omisegoairdrop.net","blodkchainwallet.info","walton-chain.org","elite888-ico.com","bitflyerjp.com","chainlinksmartcontract.com","stormtoken.eu","omise-go.tech","saltending.com","stormltoken.com","xn--quanttamp-42b.com","stormtoken.co","storntoken.com","stromtoken.com","storm-token.com","stormtokens.io","ether-delta.com","ethconnect.live","ethconnect.trade","xn--bttrex-3va.net","quantstamp.com.co","wancha.in","augur-network.com","quantstamp.com.ua","myetherwalletmew.com","myetherumwalletts.com","xn--quanstamp-tmd.com","quantsstamps.com","changellyl.net","xn--myetherwalet-1fb.com","myethereumwallets.com","xn--myetherwalet-e9b.com","quantslamp.com","metelpay.com","xn--eterdelta-m75d.com","linksmartcontract.com","myetherwalletaccess.com","myetherwalletcheck.com","myetherwalletcheck.info","myetherwalletconf.com","myetherwalleteal.com","myetherwalletec.com","myetherwalletgeth.com","myetherwalletmetamask.com","myetherwalletmm.com","myetherwalletmy.com","myetherwalletnh.com","myetherwalletnod.com","myetherwalletrr.com","myetherwalletrty.com","myetherwalletsec.com","myetherwalletsecure.com","myetherwalletutc.com","myetherwalletver.info","myetherwalletview.com","myetherwalletview.info","myetherwalletvrf.com","myetherwalletmist.com","myetherwalletext.com","myetherwalletjson.com","mettalpay.com","bricklblock.io","bittrexy.com","utrust.so","myethierwallet.org","metallpay.com","kraken-wallet.com","dmarkt.io","etherdeltla.com","unlversa.io","universa.sale","mercuryprotocol.live","ripiocredlt.network","myetlherwa11et.com","dentacoin.in","rdrtg.com","myetherwallet.com.rdrgh.com","rdrgh.com","ripiocreditnetwork.co","riaden.network","hydrominer.biz","rdrblock.com","reqest.network","senstoken.com","myetherwallat.services","ripiocredit.net","xn--metherwallet-c06f.com","ico.ripiocredits.com","ripiocredits.com","raidens.network","artoken.co","myetherwalletlgn.com","etherblog.click","stormtoken.site","httpmyetherwallet.com","myetherwalletverify.com","byzantiumfork.com","myetherwallet.com.byzantiumfork.com","www-myethervvallet.com","ether24.info","block-v.io","bittrex.cash","shapishift.io","ripiocerdit.network","rnyetherwa11et.com","claimether.com","enigmatokensale.com","ethereum-org.com","mvetnerwallet.com","myctherwallet.com","myetherwaltet.com","myetherwatlet.com","privatix.me","myetherwalletcnf.com","myetherwalletver.com","privatix.top","privatix.pro","privatex.io","stormtoken.cc","raiden.online","stormstoken.com","myetereumwallet.com","stormtokens.net","myetherwalletconf.info","storrntoken.com","worldofbattles.io","ico.worldofbattles.io","privatix.live","riden.network","raidan.network","ralden.network","mymyetherwallet.com","myetherwallets.net","myetherwalletverify.info","stormxtoken.com","myethereum-wallet.com","myetherwallet-forkprep.pagedemo.co","myetnerwailet.com","www-mvetherwallet.com","etheirdelta.com","myetherwalletiu.com","myetherwaiiett.com","xn--mytherwalet-cbb87i.com","xn--myethrwallet-ivb.co","xn--myeterwallet-f1b.com","myehterwaliet.com","omegaone.co","myetherwaiietw.com","slack.com.ru","polkodot.network","request-network.net","requestnetwork.live","binancie.com","first-eth.info","myewerthwalliet.com","enjincoin.pw","xn--bitrex-k17b.com","alrswap.io","www-request.network","myetnenwallet.com","www-enigma.co","cryptoinsidenews.com","air-swap.tech","launch.airswap.cc","airswap.cc","airswaptoken.com","launch.airswap.in","airswap.in","security-steemit.com.mx","blockchalnwallet.com","blodkchainwallet.com","blodkchaln.com","myethereumwaiiet.com","myethereumwaliet.com","myethereumwalilet.com","myetherswailet.com","myetherswaliet.com","myetherswalilet.com","myetherwalilett.com","myetherwalletl.com","myetherwalletww.com","myethereunwallet.com","myethereumwallct.com","myetherwaiieti.com","myetherwaiiete.com","upfirng.com","paypie.net","paypie.tech","soam.co","myetherwaiict.com","numerai-token.com","www-bankera.com","vvanchain.org","omisegoairdrop.com","xn--enjncoin-41a.io","suncontract.su","myetherwaiietr.com","shapeshiff.io","warchain.org","myethwallett.com","myethervvaliet.com","wanchains.org","etherparty.in","enjincoin.me","etiam.io","invest.smartlands.tech","smartlands.tech","enijncoin.io","wanchain.network","nimiq.su","enjincoin.sale","tenxwallet.io","golem-network.net","myyethwallet.ml","mywetherwailiet.com","omg-omise.com","district0x.tech","centra-token.com","etherdetla.com","etnerparty.io","etherdelta.su","myetherwallett.neocities.org","myetherwallet-secure.com","myethereumwalletntw.info","real-markets.io","wallet-ethereum.org","request-network.com","shapeshifth.io","shiapeshift.in","coin.red-puise.com","ibittreix.com","coinkbase.com","cindicator.pro","myetherwallet.com.ailogin.me","eventchain.co","kinkik.in","myetherumwalletview.com","protostokenhub.com","coinrbase.com","myetherwalletlogin.com","omisegotoken.com","myethereumwalletntw.com","reall.markets","cobinhood.org","cobinhood.io","happy-coin.org","bitfinex.com.co","bitfienex.com","iconn.foundation","centra.vip","smartcontract.live","icon.community","air-token.com","centra.credit","myetherwallet-singin.com","smartcontractlink.com","shapesshift.io","0xtoken.io","augurproject.co","ethereumus.one","myetherumwalet.com","myetherwalletsignin.com","change-bank.org","charge-bank.com","myetherwalletsingin.com","myetherwalletcontract.com","change-bank.io","chainlink.tech","myetherwallet-confirm.com","tokensale.kybernet.network","kybernet.network","kyberr.network","kybernetwork.io","myetherwalletconfirm.com","kvnuke.github.io","kin.kikpro.co","myethereumwallet.co.uk","tokensale-kyber.network","kyber-network.co","tokensale.kyber-network.co","pyro0.github.io","tokensale.kyber.digital","kyber.digital","omise-go.me","my.etherwallet.com.de","bepartof.change-bank.co","change-bank.co","enigma-tokens.co","coinbase.com.eslogin.co","xn--bittrx-mva.com","ethrdelta.github.io","etherdellta.com","ico-nexus.social","red-pulse.tech","bitj0b.io","xn--bttrex-bwa.com","kin-klk.com","kin-crowdsale.com","ethedelta.com","coindash.su","myethwallet.co.uk","swarm.credit","myethereumwallet.uk","iconexu.social","wanchain.co","enigrna.co","linknetwork.co","qtum-token.com","omisego.com.co","rivetzintl.org","etherdelta.one","the-ether.pro","etherdelta.gitnub.io","kirkik.com","monetha.ltd","vlberate.io","ethereumwallet-kr.info","omise-go.org","iconexus.social","bittirrex.com","aventus.pro","atlant.solutions","aventus.group","metamak.io","omise.com.co","herotokens.io","starbase.pro","etherdelta.githulb.io","herotoken.co","kinico.net","dmarket.ltd","etherdelta.gilthub.io","golem-network.com","etnerscan.io","bllttriex.com","monetha.me","monetha.co","monetha-crowdsale.com","starbase.tech","aventus-crowdsale.com","shapeshift.pro","bllttrex.com","kickico.co","statustoken.im","bilttrex.com","tenxpay.io","bittrex.ltd","metalpay.im","aragon.im","coindash.tech","decentraland.tech","decentraland.pro","status-token.com","bittrex.cam","enigmatoken.com","unocoin.company","unocoin.fund","0xproject.io","0xtoken.com","numerai.tech","decentraiand.org","blockcrein.info","blockchealn.info","bllookchain.info","blockcbhain.info","myetherwallet.com.ethpromonodes.com","mettamask.io","tokenswap.org","netherum.com","etherexx.org","etherume.io","ethereum.plus","ehtereum.org","etereurm.org","etheream.com","ethererum.org","ethereum.io","etherdelta-glthub.com","cryptoalliance.herokuapp.com","bitspark2.com","indorsetoken.com","iconexus.tk","iconexus.ml","iconexus.ga","iconexus.cf","etherwallet.online","wallet-ethereum.net","bitsdigit.com","etherswap.org","eos.ac","uasfwallet.com","ziber.io","multiply-ethereum.info","bittrex.comze.com","karbon.vacau.com","etherdelta.gitlhub.io","etherdelta.glthub.io","digitaldevelopersfund.vacau.com","district-0x.io","coin-dash.com","coindash.ru","district0x.net","aragonproject.io","coin-wallet.info","coinswallet.info","contribute-status.im","ether-api.com","ether-wall.com","mycoinwallet.net","ethereumchamber.com","ethereumchamber.net","ethereumchest.com","ethewallet.com","myetherwallet.com.vc","myetherwallet.com.pe","myetherwallet.us.com","myetherwallet.com.u0387831.cp.regruhosting.ru","myethereumwallet.su","myetherweb.com.de","myetherieumwallet.com","myetehrwallet.com","myeterwalet.com","myetherwaiiet.com","myetherwallet.info","myetherwallet.ch","myetherwallet.om","myethervallet.com","myetherwallet.com.cm","myetherwallet.com.co","myetherwallet.com.de","myetherwallet.com.gl","myetherwallet.com.im","myetherwallet.com.ua","secure-myetherwallet.com","update-myetherwallet.com","wwwmyetherwallet.com","myeatherwallet.com","myetharwallet.com","myelherwallel.com","myetherwaillet.com","myetherwaliet.com","myetherwallel.com","myetherwallet.cam","myetherwallet.cc","myetherwallet.co","myetherwallet.cm","myetherwallet.cz","myetherwallet.org","myetherwallet.tech","myetherwallet.top","myetherwallet.net","myetherwallet.ru.com","myetherwallet.com.ru","metherwallet.com","myetrerwallet.com","myetlerwallet.com","myethterwallet.com","myethwallet.io","myethterwallet.co","myehterwallet.co","myaetherwallet.com","myetthterwallet.com","myetherwallet.one","myelterwallet.com","myetherwallet.gdn","myetherwallt.com","myeterwallet.com","myeteherwallet.com","myethearwailet.com","myetherwallelt.com","myetherwallett.com","etherwallet.org","myetherewallet.com","myeherwallet.com","myethcrwallet.com","myetherwallet.link","myetherwallets.com","myethearwaillet.com","myethearwallet.com","myetherawllet.com","myethereallet.com","myetherswallet.com","myetherwalet.com","myetherwaller.com","myetherwalliet.com","myetherwllet.com","etherwallet.io","myetherwallet.ca","myetherwallet.me","myetherwallet.ru","myetherwallet.xyz","myetherwallte.com","myethirwallet.com","myethrewallet.com","etherwallet.net","maetherwallet.com","meyetherwallet.com","my.ether-wallet.pw","myehterwallet.com","myeitherwallet.com","myelherwallet.com","myeltherwallet.com","myerherwallet.com","myethearwalet.com","myetherewalle.com","myethervvallet.com","myetherwallent.com","myetherwallet.fm","myetherwalllet.com","myetherwalltet.com","myetherwollet.com","myetlherwalet.com","myetlherwallet.com","rnyetherwallet.com","etherclassicwallet.com","omg-omise.co","omise-go.com","omise-go.net","omise-omg.com","omise-go.io","tenx-tech.com","bitclaive.com","tokensale-tenx.tech","ubiqcoin.org","metamask.com","ethtrade.io","myetcwallet.com","account-kigo.net","bitcoin-wallet.net","blocklichan.info","bloclkicihan.info","coindash.ml","eos-bonus.com","eos-io.info","ether-wallet.net","ethereum-wallet.info","ethereum-wallet.net","ethereumchest.net","reservations-kigo.net","reservations-lodgix.com","secure-liverez.com","secure-onerooftop.com","settings-liverez.com","software-liverez.com","software-lodgix.com","unhackableetherwallets.com","www-myetherwallet.com","etherwallet.co.za","etherwalletchain.com","etherwallets.net","etherwallets.nl","my-ethwallet.com","my.ether-wallet.co","myetherwallet.com.am","myetherwallet.com.ht","myetherwalletcom.com","myehterwailet.com","xn--myetherwalle-xoc.com","xn--myetherwalle-44i.com","xn--myetherwalle-xhk.com","xn--myetherwallt-cfb.com","xn--myetherwallt-6tb.com","xn--myetherwallt-xub.com","xn--myetherwallt-ovb.com","xn--myetherwallt-fwb.com","xn--myetherwallt-5wb.com","xn--myetherwallt-jzi.com","xn--myetherwallt-2ck.com","xn--myetherwallt-lok.com","xn--myetherwallt-lsl.com","xn--myetherwallt-ce6f.com","xn--myetherwalet-mcc.com","xn--myetherwalet-xhf.com","xn--myetherwalet-lcc.com","xn--myetherwaet-15ba.com","xn--myetherwalet-whf.com","xn--myetherwaet-v2ea.com","xn--myetherwllet-59a.com","xn--myetherwllet-jbb.com","xn--myetherwllet-wbb.com","xn--myetherwllet-9bb.com","xn--myetherwllet-ncb.com","xn--myetherwllet-0cb.com","xn--myetherwllet-5nb.com","xn--myetherwllet-ktd.com","xn--myetherwllet-mre.com","xn--myetherwllet-76e.com","xn--myetherwllet-o0l.com","xn--myetherwllet-c45f.com","xn--myetherallet-ejn.com","xn--myethewallet-4nf.com","xn--myethewallet-iof.com","xn--myethewallet-mpf.com","xn--myethewallet-6bk.com","xn--myethewallet-i31f.com","xn--myethrwallet-feb.com","xn--myethrwallt-fbbf.com","xn--myethrwallet-seb.com","xn--myethrwallt-rbbf.com","xn--myethrwallet-5eb.com","xn--myethrwallt-3bbf.com","xn--myethrwallet-0tb.com","xn--myethrwallt-tpbf.com","xn--myethrwallet-rub.com","xn--myethrwallt-iqbf.com","xn--myethrwallet-ivb.com","xn--myethrwallt-6qbf.com","xn--myethrwallet-8vb.com","xn--myethrwallt-vrbf.com","xn--myethrwallet-zwb.com","xn--myethrwallt-ksbf.com","xn--myethrwallet-dzi.com","xn--myethrwallt-wbif.com","xn--myethrwallet-wck.com","xn--myethrwallt-skjf.com","xn--myethrwallet-fok.com","xn--myethrwallt-fvjf.com","xn--myethrwallet-fsl.com","xn--myethrwallt-fwkf.com","xn--myethrwallet-5d6f.com","xn--myethrwallt-319ef.com","xn--myeterwallet-ufk.com","xn--myeterwallet-nrl.com","xn--myeterwallet-von.com","xn--myeterwallet-jl6c.com","xn--myeherwallet-ooc.com","xn--myeherwalle-6hci.com","xn--myeherwallet-v4i.com","xn--myeherwalle-zgii.com","xn--myeherwallet-ohk.com","xn--myeherwalle-6oji.com","xn--mytherwallet-ceb.com","xn--mythrwallet-cbbc.com","xn--mythrwallt-c7acf.com","xn--mytherwallet-peb.com","xn--mythrwallet-obbc.com","xn--mythrwallt-n7acf.com","xn--mytherwallet-2eb.com","xn--mythrwallet-0bbc.com","xn--mythrwallt-y7acf.com","xn--mytherwallet-xtb.com","xn--mythrwallet-qpbc.com","xn--mythrwallt-jlbcf.com","xn--mytherwallet-oub.com","xn--mythrwallet-fqbc.com","xn--mythrwallt-5lbcf.com","xn--mythrwallet-3qbc.com","xn--mythrwallt-smbcf.com","xn--mytherwallet-5vb.com","xn--mythrwallet-srbc.com","xn--mythrwallt-fnbcf.com","xn--mytherwallet-wwb.com","xn--mythrwallet-hsbc.com","xn--mythrwallt-1nbcf.com","xn--mytherwallet-9yi.com","xn--mythrwallet-tbic.com","xn--mythrwallt-dnhcf.com","xn--mytherwallet-tck.com","xn--mythrwallet-pkjc.com","xn--mythrwallt-lsicf.com","xn--mytherwallet-cok.com","xn--mythrwallet-cvjc.com","xn--mythrwallt-c2icf.com","xn--mytherwallet-csl.com","xn--mythrwallet-cwkc.com","xn--mythrwallt-c0jcf.com","xn--mytherwallet-2d6f.com","xn--mythrwallet-019ec.com","xn--mythrwallt-yq3ecf.com","xn--metherwallet-qlb.com","xn--metherwallet-1uf.com","xn--metherwallet-iyi.com","xn--metherwallet-zhk.com","xn--metherwallet-3ml.com","xn--mytherwallet-fvb.com","xn--myetherwallt-7db.com","xn--myetherwallt-leb.com","xn--myetherwallt-yeb.com","xn--yetherwallet-vjf.com","xn--yetherwallet-dfk.com","xn--yetherwallet-1t1f.com","xn--yetherwallet-634f.com","xn--myeherwallet-fpc.com","xn--myethewallt-crb.com","xn--metherwallet-1vc.com","xn--myeherwallt-kbb8039g.com","xn--myeherwallet-vk5f.com","xn--yethewallet-iw8ejl.com","xn--bittrx-th8b.com","xn--polniex-n0a.com","thekey.vin","thekey-vip.com","digitexftures.com","ethzero-wallet.org","zeepln.io","wepowers.network","wepower.vision"]}},"CurrencyController":{"currentCurrency":"usd","conversionRate":1112,"conversionDate":1517351401}}} \ No newline at end of file
+{"meta":{"version":20},"data":{"config":{},"NetworkController":{"provider":{"type":"mainnet","rpcTarget":"https://mainnet.infura.io/metamask"},"network":"1"},"firstTimeInfo":{"version":"3.12.1","date":1517351427287},"NoticeController":{"noticesList":[{"read":false,"date":"Thu Feb 09 2017","title":"Terms of Use","body":"# Terms of Use #\n\n**THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.**\n\n_Our Terms of Use have been updated as of September 5, 2016_\n\n## 1. Acceptance of Terms ##\n\nMetaMask provides a platform for managing Ethereum (or \"ETH\") accounts, and allowing ordinary websites to interact with the Ethereum blockchain, while keeping the user in control over what transactions they approve, through our website located at[ ](http://metamask.io)[https://metamask.io/](https://metamask.io/) and browser plugin (the \"Site\") — which includes text, images, audio, code and other materials (collectively, the “Content”) and all of the features, and services provided. The Site, and any other features, tools, materials, or other services offered from time to time by MetaMask are referred to here as the “Service.” Please read these Terms of Use (the “Terms” or “Terms of Use”) carefully before using the Service. By using or otherwise accessing the Services, or clicking to accept or agree to these Terms where that option is made available, you (1) accept and agree to these Terms (2) consent to the collection, use, disclosure and other handling of information as described in our Privacy Policy and (3) any additional terms, rules and conditions of participation issued by MetaMask from time to time. If you do not agree to the Terms, then you may not access or use the Content or Services.\n\n## 2. Modification of Terms of Use ##\n\nExcept for Section 13, providing for binding arbitration and waiver of class action rights, MetaMask reserves the right, at its sole discretion, to modify or replace the Terms of Use at any time. The most current version of these Terms will be posted on our Site. You shall be responsible for reviewing and becoming familiar with any such modifications. Use of the Services by you after any modification to the Terms constitutes your acceptance of the Terms of Use as modified.\n\n\n\n## 3. Eligibility ##\n\nYou hereby represent and warrant that you are fully able and competent to enter into the terms, conditions, obligations, affirmations, representations and warranties set forth in these Terms and to abide by and comply with these Terms.\n\nMetaMask is a global platform and by accessing the Content or Services, you are representing and warranting that, you are of the legal age of majority in your jurisdiction as is required to access such Services and Content and enter into arrangements as provided by the Service. You further represent that you are otherwise legally permitted to use the service in your jurisdiction including owning cryptographic tokens of value, and interacting with the Services or Content in any way. You further represent you are responsible for ensuring compliance with the laws of your jurisdiction and acknowledge that MetaMask is not liable for your compliance with such laws.\n\n## 4 Account Password and Security ##\n\nWhen setting up an account within MetaMask, you will be responsible for keeping your own account secrets, which may be a twelve-word seed phrase, an account file, or other locally stored secret information. MetaMask encrypts this information locally with a password you provide, that we never send to our servers. You agree to (a) never use the same password for MetaMask that you have ever used outside of this service; (b) keep your secret information and password confidential and do not share them with anyone else; (c) immediately notify MetaMask of any unauthorized use of your account or breach of security. MetaMask cannot and will not be liable for any loss or damage arising from your failure to comply with this section.\n\n## 5. Representations, Warranties, and Risks ##\n\n### 5.1. Warranty Disclaimer ###\n\nYou expressly understand and agree that your use of the Service is at your sole risk. The Service (including the Service and the Content) are provided on an \"AS IS\" and \"as available\" basis, without warranties of any kind, either express or implied, including, without limitation, implied warranties of merchantability, fitness for a particular purpose or non-infringement. You acknowledge that MetaMask has no control over, and no duty to take any action regarding: which users gain access to or use the Service; what effects the Content may have on you; how you may interpret or use the Content; or what actions you may take as a result of having been exposed to the Content. You release MetaMask from all liability for you having acquired or not acquired Content through the Service. MetaMask makes no representations concerning any Content contained in or accessed through the Service, and MetaMask will not be responsible or liable for the accuracy, copyright compliance, legality or decency of material contained in or accessed through the Service.\n\n### 5.2 Sophistication and Risk of Cryptographic Systems ###\n\nBy utilizing the Service or interacting with the Content or platform in any way, you represent that you understand the inherent risks associated with cryptographic systems; and warrant that you have an understanding of the usage and intricacies of native cryptographic tokens, like Ether (ETH) and Bitcoin (BTC), smart contract based tokens such as those that follow the Ethereum Token Standard (https://github.com/ethereum/EIPs/issues/20), and blockchain-based software systems.\n\n### 5.3 Risk of Regulatory Actions in One or More Jurisdictions ###\n\nMetaMask and ETH could be impacted by one or more regulatory inquiries or regulatory action, which could impede or limit the ability of MetaMask to continue to develop, or which could impede or limit your ability to access or use the Service or Ethereum blockchain.\n\n### 5.4 Risk of Weaknesses or Exploits in the Field of Cryptography ###\n\nYou acknowledge and understand that Cryptography is a progressing field. Advances in code cracking or technical advances such as the development of quantum computers may present risks to cryptocurrencies and Services of Content, which could result in the theft or loss of your cryptographic tokens or property. To the extent possible, MetaMask intends to update the protocol underlying Services to account for any advances in cryptography and to incorporate additional security measures, but does not guarantee or otherwise represent full security of the system. By using the Service or accessing Content, you acknowledge these inherent risks.\n\n### 5.5 Volatility of Crypto Currencies ###\n\nYou understand that Ethereum and other blockchain technologies and associated currencies or tokens are highly volatile due to many factors including but not limited to adoption, speculation, technology and security risks. You also acknowledge that the cost of transacting on such technologies is variable and may increase at any time causing impact to any activities taking place on the Ethereum blockchain. You acknowledge these risks and represent that MetaMask cannot be held liable for such fluctuations or increased costs.\n\n### 5.6 Application Security ###\n\nYou acknowledge that Ethereum applications are code subject to flaws and acknowledge that you are solely responsible for evaluating any code provided by the Services or Content and the trustworthiness of any third-party websites, products, smart-contracts, or Content you access or use through the Service. You further expressly acknowledge and represent that Ethereum applications can be written maliciously or negligently, that MetaMask cannot be held liable for your interaction with such applications and that such applications may cause the loss of property or even identity. This warning and others later provided by MetaMask in no way evidence or represent an on-going duty to alert you to all of the potential risks of utilizing the Service or Content.\n\n## 6. Indemnity ##\n\nYou agree to release and to indemnify, defend and hold harmless MetaMask and its parents, subsidiaries, affiliates and agencies, as well as the officers, directors, employees, shareholders and representatives of any of the foregoing entities, from and against any and all losses, liabilities, expenses, damages, costs (including attorneys’ fees and court costs) claims or actions of any kind whatsoever arising or resulting from your use of the Service, your violation of these Terms of Use, and any of your acts or omissions that implicate publicity rights, defamation or invasion of privacy. MetaMask reserves the right, at its own expense, to assume exclusive defense and control of any matter otherwise subject to indemnification by you and, in such case, you agree to cooperate with MetaMask in the defense of such matter.\n\n## 7. Limitation on liability ##\n\nYOU ACKNOWLEDGE AND AGREE THAT YOU ASSUME FULL RESPONSIBILITY FOR YOUR USE OF THE SITE AND SERVICE. YOU ACKNOWLEDGE AND AGREE THAT ANY INFORMATION YOU SEND OR RECEIVE DURING YOUR USE OF THE SITE AND SERVICE MAY NOT BE SECURE AND MAY BE INTERCEPTED OR LATER ACQUIRED BY UNAUTHORIZED PARTIES. YOU ACKNOWLEDGE AND AGREE THAT YOUR USE OF THE SITE AND SERVICE IS AT YOUR OWN RISK. RECOGNIZING SUCH, YOU UNDERSTAND AND AGREE THAT, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, NEITHER METAMASK NOR ITS SUPPLIERS OR LICENSORS WILL BE LIABLE TO YOU FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY OR OTHER DAMAGES OF ANY KIND, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER TANGIBLE OR INTANGIBLE LOSSES OR ANY OTHER DAMAGES BASED ON CONTRACT, TORT, STRICT LIABILITY OR ANY OTHER THEORY (EVEN IF METAMASK HAD BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES), RESULTING FROM THE SITE OR SERVICE; THE USE OR THE INABILITY TO USE THE SITE OR SERVICE; UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; STATEMENTS OR CONDUCT OF ANY THIRD PARTY ON THE SITE OR SERVICE; ANY ACTIONS WE TAKE OR FAIL TO TAKE AS A RESULT OF COMMUNICATIONS YOU SEND TO US; HUMAN ERRORS; TECHNICAL MALFUNCTIONS; FAILURES, INCLUDING PUBLIC UTILITY OR TELEPHONE OUTAGES; OMISSIONS, INTERRUPTIONS, LATENCY, DELETIONS OR DEFECTS OF ANY DEVICE OR NETWORK, PROVIDERS, OR SOFTWARE (INCLUDING, BUT NOT LIMITED TO, THOSE THAT DO NOT PERMIT PARTICIPATION IN THE SERVICE); ANY INJURY OR DAMAGE TO COMPUTER EQUIPMENT; INABILITY TO FULLY ACCESS THE SITE OR SERVICE OR ANY OTHER WEBSITE; THEFT, TAMPERING, DESTRUCTION, OR UNAUTHORIZED ACCESS TO, IMAGES OR OTHER CONTENT OF ANY KIND; DATA THAT IS PROCESSED LATE OR INCORRECTLY OR IS INCOMPLETE OR LOST; TYPOGRAPHICAL, PRINTING OR OTHER ERRORS, OR ANY COMBINATION THEREOF; OR ANY OTHER MATTER RELATING TO THE SITE OR SERVICE.\n\nSOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES. ACCORDINGLY, SOME OF THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU.\n\n## 8. Our Proprietary Rights ##\n\nAll title, ownership and intellectual property rights in and to the Service are owned by MetaMask or its licensors. You acknowledge and agree that the Service contains proprietary and confidential information that is protected by applicable intellectual property and other laws. Except as expressly authorized by MetaMask, you agree not to copy, modify, rent, lease, loan, sell, distribute, perform, display or create derivative works based on the Service, in whole or in part. MetaMask issues a license for MetaMask, found [here](https://github.com/MetaMask/metamask-plugin/blob/master/LICENSE). For information on other licenses utilized in the development of MetaMask, please see our attribution page at: [https://metamask.io/attributions.html](https://metamask.io/attributions.html)\n\n## 9. Links ##\n\nThe Service provides, or third parties may provide, links to other World Wide Web or accessible sites, applications or resources. Because MetaMask has no control over such sites, applications and resources, you acknowledge and agree that MetaMask is not responsible for the availability of such external sites, applications or resources, and does not endorse and is not responsible or liable for any content, advertising, products or other materials on or available from such sites or resources. You further acknowledge and agree that MetaMask shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such site or resource.\n\n## 10. Termination and Suspension ##\n\nMetaMask may terminate or suspend all or part of the Service and your MetaMask access immediately, without prior notice or liability, if you breach any of the terms or conditions of the Terms. Upon termination of your access, your right to use the Service will immediately cease.\n\nThe following provisions of the Terms survive any termination of these Terms: INDEMNITY; WARRANTY DISCLAIMERS; LIMITATION ON LIABILITY; OUR PROPRIETARY RIGHTS; LINKS; TERMINATION; NO THIRD PARTY BENEFICIARIES; BINDING ARBITRATION AND CLASS ACTION WAIVER; GENERAL INFORMATION.\n\n## 11. No Third Party Beneficiaries ##\n\nYou agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.\n\n## 12. Notice and Procedure For Making Claims of Copyright Infringement ##\n\nIf you believe that your copyright or the copyright of a person on whose behalf you are authorized to act has been infringed, please provide MetaMask’s Copyright Agent a written Notice containing the following information:\n\n· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;\n\n· a description of the copyrighted work or other intellectual property that you claim has been infringed;\n\n· a description of where the material that you claim is infringing is located on the Service;\n\n· your address, telephone number, and email address;\n\n· a statement by you that you have a good faith belief that the disputed use is not authorized by the copyright owner, its agent, or the law;\n\n· a statement by you, made under penalty of perjury, that the above information in your Notice is accurate and that you are the copyright or intellectual property owner or authorized to act on the copyright or intellectual property owner's behalf.\n\nMetaMask’s Copyright Agent can be reached at:\n\nEmail: copyright [at] metamask [dot] io\n\nMail:\n\nAttention:\n\nMetaMask Copyright ℅ ConsenSys\n\n49 Bogart Street\n\nBrooklyn, NY 11206\n\n## 13. Binding Arbitration and Class Action Waiver ##\n\nPLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT\n\n### 13.1 Initial Dispute Resolution ###\n\nThe parties shall use their best efforts to engage directly to settle any dispute, claim, question, or disagreement and engage in good faith negotiations which shall be a condition to either party initiating a lawsuit or arbitration.\n\n### 13.2 Binding Arbitration ###\n\nIf the parties do not reach an agreed upon solution within a period of 30 days from the time informal dispute resolution under the Initial Dispute Resolution provision begins, then either party may initiate binding arbitration as the sole means to resolve claims, subject to the terms set forth below. Specifically, all claims arising out of or relating to these Terms (including their formation, performance and breach), the parties’ relationship with each other and/or your use of the Service shall be finally settled by binding arbitration administered by the American Arbitration Association in accordance with the provisions of its Commercial Arbitration Rules and the supplementary procedures for consumer related disputes of the American Arbitration Association (the \"AAA\"), excluding any rules or procedures governing or permitting class actions.\n\nThe arbitrator, and not any federal, state or local court or agency, shall have exclusive authority to resolve all disputes arising out of or relating to the interpretation, applicability, enforceability or formation of these Terms, including, but not limited to any claim that all or any part of these Terms are void or voidable, or whether a claim is subject to arbitration. The arbitrator shall be empowered to grant whatever relief would be available in a court under law or in equity. The arbitrator’s award shall be written, and binding on the parties and may be entered as a judgment in any court of competent jurisdiction.\n\nThe parties understand that, absent this mandatory provision, they would have the right to sue in court and have a jury trial. They further understand that, in some instances, the costs of arbitration could exceed the costs of litigation and the right to discovery may be more limited in arbitration than in court.\n\n### 13.3 Location ###\n\nBinding arbitration shall take place in New York. You agree to submit to the personal jurisdiction of any federal or state court in New York County, New York, in order to compel arbitration, to stay proceedings pending arbitration, or to confirm, modify, vacate or enter judgment on the award entered by the arbitrator.\n\n### 13.4 Class Action Waiver ###\n\nThe parties further agree that any arbitration shall be conducted in their individual capacities only and not as a class action or other representative action, and the parties expressly waive their right to file a class action or seek relief on a class basis. YOU AND METAMASK AGREE THAT EACH MAY BRING CLAIMS AGAINST THE OTHER ONLY IN YOUR OR ITS INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING. If any court or arbitrator determines that the class action waiver set forth in this paragraph is void or unenforceable for any reason or that an arbitration can proceed on a class basis, then the arbitration provision set forth above shall be deemed null and void in its entirety and the parties shall be deemed to have not agreed to arbitrate disputes.\n\n### 13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims ###\n\nNotwithstanding the parties' decision to resolve all disputes through arbitration, either party may bring an action in state or federal court to protect its intellectual property rights (\"intellectual property rights\" means patents, copyrights, moral rights, trademarks, and trade secrets, but not privacy or publicity rights). Either party may also seek relief in a small claims court for disputes or claims within the scope of that court’s jurisdiction.\n\n### 13.6 30-Day Right to Opt Out ###\n\nYou have the right to opt-out and not be bound by the arbitration and class action waiver provisions set forth above by sending written notice of your decision to opt-out to the following address: MetaMask ℅ ConsenSys, 49 Bogart Street, Brooklyn NY 11206 and via email at support@metamask.io. The notice must be sent within 30 days of September 6, 2016 or your first use of the Service, whichever is later, otherwise you shall be bound to arbitrate disputes in accordance with the terms of those paragraphs. If you opt-out of these arbitration provisions, MetaMask also will not be bound by them.\n\n### 13.7 Changes to This Section ###\n\nMetaMask will provide 60-days’ notice of any changes to this section. Changes will become effective on the 60th day, and will apply prospectively only to any claims arising after the 60th day.\n\nFor any dispute not subject to arbitration you and MetaMask agree to submit to the personal and exclusive jurisdiction of and venue in the federal and state courts located in New York, New York. You further agree to accept service of process by mail, and hereby waive any and all jurisdictional and venue defenses otherwise available.\n\nThe Terms and the relationship between you and MetaMask shall be governed by the laws of the State of New York without regard to conflict of law provisions.\n\n## 14. General Information ##\n\n### 14.1 Entire Agreement ###\n\nThese Terms (and any additional terms, rules and conditions of participation that MetaMask may post on the Service) constitute the entire agreement between you and MetaMask with respect to the Service and supersedes any prior agreements, oral or written, between you and MetaMask. In the event of a conflict between these Terms and the additional terms, rules and conditions of participation, the latter will prevail over the Terms to the extent of the conflict.\n\n### 14.2 Waiver and Severability of Terms ###\n\nThe failure of MetaMask to exercise or enforce any right or provision of the Terms shall not constitute a waiver of such right or provision. If any provision of the Terms is found by an arbitrator or court of competent jurisdiction to be invalid, the parties nevertheless agree that the arbitrator or court should endeavor to give effect to the parties' intentions as reflected in the provision, and the other provisions of the Terms remain in full force and effect.\n\n### 14.3 Statute of Limitations ###\n\nYou agree that regardless of any statute or law to the contrary, any claim or cause of action arising out of or related to the use of the Service or the Terms must be filed within one (1) year after such claim or cause of action arose or be forever barred.\n\n### 14.4 Section Titles ###\n\nThe section titles in the Terms are for convenience only and have no legal or contractual effect.\n\n### 14.5 Communications ###\n\nUsers with questions, complaints or claims with respect to the Service may contact us using the relevant contact information set forth above and at communications@metamask.io.\n\n## 15 Related Links ##\n\n**[Terms of Use](https://metamask.io/terms.html)**\n\n**[Privacy](https://metamask.io/privacy.html)**\n\n**[Attributions](https://metamask.io/attributions.html)**\n\n","id":0},{"read":false,"date":"Mon May 08 2017","title":"Privacy Notice","body":"MetaMask is beta software. \n\nWhen you log in to MetaMask, your current account is visible to every new site you visit.\n\nFor your privacy, for now, please sign out of MetaMask when you're done using a site.\n\nAlso, by default, you will be signed in to a test network. To use real Ether, you must connect to the main network manually in the top left network menu.\n\n","id":2}]},"BlacklistController":{"phishing":{"version":2,"tolerance":2,"fuzzylist":["metamask.io","myetherwallet.com","cryptokitties.co"],"whitelist":["metahash.io","metahash.net","metahash.org","cryptotitties.com","cryptocities.net","cryptoshitties.co","cryptotitties.fun","cryptokitties.forsale","cryptokitties.care","metamate.cc","metamesh.tech","ico.nexus.social","metamesh.org","metatask.io","metmask.com","metarasa.com","metapack.com","metacase.com","metafas.nl","metamako.com","metamast.com","metamax.ru","metadesk.io","metadisk.com","metallsk.ru","metamag.fr","metamaks.ru","metamap.ru","metamaps.cc","metamats.com","metamax.by","metamax.com","metamax.io","metamuse.net","metarank.com","metaxas.com","megamas2.ru","metamask.io","myetherwallet.com","myethlerwallet.com","ethereum.org","myetheroll.com","myetherapi.com","ledgerwallet.com","databrokerdao.com","etherscan.io","etherid.org","ether.cards","etheroll.com","ethnews.com","ethex.market","ethereumdev.io","ethereumdev.kr","dether.io","ethermine.org","slaask.com","etherbtc.io","ethereal.capital","etherisc.com","m.famalk.net","etherecho.com","ethereum.os.tc","theethereum.wiki","metajack.im","etherhub.io","ethereum.network","ethereum.link","ethereum.com","prethereum.org","ethereumj.io","etheraus.com","ethereum.dev","1ethereum.ru","ethereum.nz","nethereum.com","metabank.com","metamas.com","aventus.io","metabase.com","etherdelta.com","metabase.one","cryptokitties.co"],"blacklist":["myetherwallet.uk.com","kodakone.cc","nyeihitervvallet.com","xn--myeterwalet-cm8eoi.com","nucleus.foundation","beetoken-ico.com","data-token.com","tron-labs.com","ocoin.tech","aionfoundation.com","ico-telegram.org","nyeihitervvallat.com","telegramcoin.us","daddi.cloud","daditoken.com","blockarray.org","dadi-cloud.net","wanchainfunding.org","ico-telegram.io","iconfoundation.site","iost.co","beetoken-ico.eu","cindicator.network","wanchainetwork.org","wamchain.org","wanchainltd.org","wanchainalliance.org","nucleus-vision.net","ledgerwallet.by","nucleuss.vision","myenhterswailct.com","cobin-hood.com","wanchainfoundation.org","xn--polniex-ex4c.com","xn--polniex-s1a.com","xn--polonex-ieb.com","xn--polonex-sza.com","xn--polonex-zw4c.com","xn--polonix-ws4c.com","xn--polonix-y8a.com","xn--pooniex-ojb.com","gramico.info","dimnsions.network","www-gemini.com","login-kucoin.net","venchain.foundation","grampreico.com","tgram.cc","ton-gramico.com","wwwpaywithink.com","coniomi.com","paywithnk.com","paywithlnk.com","iluminatto.com.br","pundix.eu","xn--bttrx-esay.com","xn--bttrex-w8a.com","xn--bnance-bwa.com","xn--shpeshift-11a.com","xn--shapeshif-ts6d.com","xn--shapshift-yf7d.com","wwwbluzelle.com","bluzelie.com","nucleus-vision.org","omisegonetwork.site","etlherzero.com","etlherdelta.com","xn--condesk-0ya.com","xn--condesk-sfb.com","xn--coindsk-vs4c.com","iexecplatform.com","tongramico.com","nucleus-vision.eu","intchain.network","wanchain.cloud","bluzelle-ico.com","ethzero-wallet.com","xn--metherwalle-jb9et7d.com","xn--coinesk-jo3c.com","venchainfoundation.com","myenhtersvvailot.com","ether-zero.net","ins.foundation","nastoken.org","telcointoken.com","ether0.org","eterzero.org","bluzelle-ico.eu","bleuzelle.com","appcoinstoken.org","xn--quanstamp-8s6d.com","myehntersvvailct.com","myeherwalllet.com","ico-bluzelle.com","bluzelle.im","bluzelle.one","bluzele.sale","bluzele.co","sether.ws","xn--myetherwalet-6gf.com","xn--rnyethewaliet-om1g.com","rnyethervailet.com","mvetherwaliet.com","rnyetherwailet.com","myethervaliet.com","rnyethervaliet.com","mvetherwalilet.com","xn--myethewalie-3ic0947g.com","xn--mthrwallet-z6ac3y.com","xn--myeherwalie-vici.com","xn--myethervvalie-8vc.com","xn--mythrwallt-06acf.com","xn--mtherwallet-y9a6y.com","myetherwallet.applytoken.tk","ethereum-zero.com","quanstamptoken.tk","bluzelle.network","ether-wallet.org","tron-wallet.info","appcoinsproject.com","vechain.foundation","tronlab.site","tronlabs.network","bluzelle.cc","ethblender.com","ethpaperwallet.net","waltontoken.org","icoselfkey.org","etherzeroclaim.com","etherzero.promo","bluzelle.pro","token-selfkey.org","xn--etherdlta-0f7d.com","sether.in","xn--ttrex-ysa9423c.com","bluzelle.eu","bluzelle.site","gifto.tech","xn--os-g7s.com","selfkey.co","xn--myeherwalet-ns8exy.com","xn--coinelegraph-wk5f.com","dai-stablecoin.com","eos-token.org","venchain.org","gatcoins.io","deepbrainchain.co","myetherwalililet.info","myehvterwallet.com","myehterumswallet.com","nucleusico.com","tronlab.tech","0x-project.com","gift-token-events.mywebcommunity.org","funfairtoken.org","breadtokenapp.com","cloudpetstore.com","myethwalilet.com","selfkeys.org","wallet-ethereum.com","xn--methrwallt-26ar0z.com","xn--mytherwllet-r8a0c.com","bluzelle.promo","tokensale.bluzelle.promo","cedarlake.org","marketingleads4u.com","cashaa.co","xn--inance-hrb.com","wanchain.tech","zenprolocol.com","ethscan.io","etherscan.in","props-project.com","zilliaq.com","reqestnetwork.com","etherdelta.pw","ethereum-giveaway.org","mysimpletoken.org","binancc.com","blnance.org","elherdelta.io","xn--hapeshit-ez9c2y.com","tenxwallet.co","singularitynet.info","mytlherwaliet.info","iconmainnet.ml","tokenselfkey.org","xn--myetewallet-cm8e5y.com","envione.org","myetherwalletet.com","claimbcd.com","ripiocreditnetwork.in","xn--yeterwallet-ml8euo.com","ethclassicwallet.info","myltherwallet.ru.com","etherdella.com","xn--yeterwallet-bm8ewn.com","singularty.net","cloudkitties.co","iconfoundation.io","kittystat.com","gatscoin.io","singularitynet.in","sale.canay.io","canay.io","wabicoin.co","envion.top","sirinslabs.com","tronlab.co","paxful.com.ng","changellyli.com","ethereum-code.com","xn--plonex-6va6c.com","envion.co","envion.cc","envion.site","ethereumchain.info","xn--envon-1sa.org","xn--btstamp-rfb.net","envlon.org","envion-ico.org","spectivvr.org","sirinlbs.com","ethereumdoubler.life","xn--myetherwllet-fnb.com","sirin-labs.com","sirin-labs.org","envion.one","envion.live","propsproject.org","propsprojects.com","decentralland.org","xn--metherwalet-ns8ep4b.com","redpulsetoken.co","propsproject.tech","xn--myeterwalet-nl8emj.com","powrerledger.com","cryptokitties.com","sirinlabs.pro","sirinlabs.co","sirnlabs.com","superbitcoin-blockchain.info","hellobloom.me","mobus.network","powrrledger.com","xn--myeherwalet-ms8eyy.com","qlink-ico.com","gatcoin.in","tokensale.gamefllp.com","gamefllp.com","xn--myeherwalle-vici.com","xn--myetherwalet-39b.com","xn--polonex-ffb.com","xn--birex-leba.com","raiden-network.org","sirintabs.com","xn--metherwallt-79a30a.com","xn--myethrwllet-2kb3p.com","myethlerwallet.eu","xn--btrex-b4a.com","powerrledger.com","xn--cointeegraph-wz4f.com","myerherwalet.com","qauntstanp.com","myetherermwallet.com","xn--myethewalet-ns8eqq.com","xn--nvion-hza.org","nnyetherwallelt.ru.com","ico-wacoin.com","xn--myeterwalet-nl8enj.com","bitcoinsilver.io","t0zero.com","tokensale.gizer.in","gizer.in","wabitoken.com","gladius.ws","xn--metherwallt-8bb4w.com","quanttstamp.com","gladius.im","ethereumstorage.net","powerledgerr.com","xn--myeherwallet-4j5f.com","quamtstamp.com","quntstamp.com","xn--changely-j59c.com","shapeshlft.com","coinbasenews.co.uk","xn--metherwallet-hmb.com","envoin.org","powerledger.com","bitstannp.net","xn--myetherallet-4k5fwn.com","xn--coinbas-pya.com","requestt.network","oracls.network","sirinlabs.website","powrledger.io","slackconfirm.com","shape-shift.io","oracles-network.org","xn--myeherwalle-zb9eia.com","blockstack.one","urtust.io","bittrex.one","t0-ico.com","xn--cinbase-90a.com","xn--metherwalet-ns8ez1g.com","tzero-ico.com","tzero.su","tzero.website","blockstack.network","ico-tzero.com","spectre.site","tzero.pw","spectre-ai.net","xn--waxtokn-y8a.com","dmarket.pro","bittrex.com11648724328774.cf","bittrex.com1987465798.ga","autcus.org","t-zero.org","xn--zero-zxb.com","myetherwalletfork.com","blokclbain.info","datum.sale","spectre-ai.org","powerledgr.com","simpletoken.live","sale.simpletoken.live","qauntstamp.com","raiden-network.com","metalpayme.com","quantstamp-ico.com","myetherwailetclient.com","biockchain.biz","wallets-blockchain.com","golemairdrop.com","omisegoairdrop.net","blodkchainwallet.info","walton-chain.org","elite888-ico.com","bitflyerjp.com","chainlinksmartcontract.com","stormtoken.eu","omise-go.tech","saltending.com","stormltoken.com","xn--quanttamp-42b.com","stormtoken.co","storntoken.com","stromtoken.com","storm-token.com","stormtokens.io","ether-delta.com","ethconnect.live","ethconnect.trade","xn--bttrex-3va.net","quantstamp.com.co","wancha.in","augur-network.com","quantstamp.com.ua","myetherwalletmew.com","myetherumwalletts.com","xn--quanstamp-tmd.com","quantsstamps.com","changellyl.net","xn--myetherwalet-1fb.com","myethereumwallets.com","xn--myetherwalet-e9b.com","quantslamp.com","metelpay.com","xn--eterdelta-m75d.com","linksmartcontract.com","myetherwalletaccess.com","myetherwalletcheck.com","myetherwalletcheck.info","myetherwalletconf.com","myetherwalleteal.com","myetherwalletec.com","myetherwalletgeth.com","myetherwalletmetamask.com","myetherwalletmm.com","myetherwalletmy.com","myetherwalletnh.com","myetherwalletnod.com","myetherwalletrr.com","myetherwalletrty.com","myetherwalletsec.com","myetherwalletsecure.com","myetherwalletutc.com","myetherwalletver.info","myetherwalletview.com","myetherwalletview.info","myetherwalletvrf.com","myetherwalletmist.com","myetherwalletext.com","myetherwalletjson.com","mettalpay.com","bricklblock.io","bittrexy.com","utrust.so","myethierwallet.org","metallpay.com","kraken-wallet.com","dmarkt.io","etherdeltla.com","unlversa.io","universa.sale","mercuryprotocol.live","ripiocredlt.network","myetlherwa11et.com","dentacoin.in","rdrtg.com","myetherwallet.com.rdrgh.com","rdrgh.com","ripiocreditnetwork.co","riaden.network","hydrominer.biz","rdrblock.com","reqest.network","senstoken.com","myetherwallat.services","ripiocredit.net","xn--metherwallet-c06f.com","ico.ripiocredits.com","ripiocredits.com","raidens.network","artoken.co","myetherwalletlgn.com","etherblog.click","stormtoken.site","httpmyetherwallet.com","myetherwalletverify.com","byzantiumfork.com","myetherwallet.com.byzantiumfork.com","www-myethervvallet.com","ether24.info","block-v.io","bittrex.cash","shapishift.io","ripiocerdit.network","rnyetherwa11et.com","claimether.com","enigmatokensale.com","ethereum-org.com","mvetnerwallet.com","myctherwallet.com","myetherwaltet.com","myetherwatlet.com","privatix.me","myetherwalletcnf.com","myetherwalletver.com","privatix.top","privatix.pro","privatex.io","stormtoken.cc","raiden.online","stormstoken.com","myetereumwallet.com","stormtokens.net","myetherwalletconf.info","storrntoken.com","worldofbattles.io","ico.worldofbattles.io","privatix.live","riden.network","raidan.network","ralden.network","mymyetherwallet.com","myetherwallets.net","myetherwalletverify.info","stormxtoken.com","myethereum-wallet.com","myetherwallet-forkprep.pagedemo.co","myetnerwailet.com","www-mvetherwallet.com","etheirdelta.com","myetherwalletiu.com","myetherwaiiett.com","xn--mytherwalet-cbb87i.com","xn--myethrwallet-ivb.co","xn--myeterwallet-f1b.com","myehterwaliet.com","omegaone.co","myetherwaiietw.com","slack.com.ru","polkodot.network","request-network.net","requestnetwork.live","binancie.com","first-eth.info","myewerthwalliet.com","enjincoin.pw","xn--bitrex-k17b.com","alrswap.io","www-request.network","myetnenwallet.com","www-enigma.co","cryptoinsidenews.com","air-swap.tech","launch.airswap.cc","airswap.cc","airswaptoken.com","launch.airswap.in","airswap.in","security-steemit.com.mx","blockchalnwallet.com","blodkchainwallet.com","blodkchaln.com","myethereumwaiiet.com","myethereumwaliet.com","myethereumwalilet.com","myetherswailet.com","myetherswaliet.com","myetherswalilet.com","myetherwalilett.com","myetherwalletl.com","myetherwalletww.com","myethereunwallet.com","myethereumwallct.com","myetherwaiieti.com","myetherwaiiete.com","upfirng.com","paypie.net","paypie.tech","soam.co","myetherwaiict.com","numerai-token.com","www-bankera.com","vvanchain.org","omisegoairdrop.com","xn--enjncoin-41a.io","suncontract.su","myetherwaiietr.com","shapeshiff.io","warchain.org","myethwallett.com","myethervvaliet.com","wanchains.org","etherparty.in","enjincoin.me","etiam.io","invest.smartlands.tech","smartlands.tech","enijncoin.io","wanchain.network","nimiq.su","enjincoin.sale","tenxwallet.io","golem-network.net","myyethwallet.ml","mywetherwailiet.com","omg-omise.com","district0x.tech","centra-token.com","etherdetla.com","etnerparty.io","etherdelta.su","myetherwallett.neocities.org","myetherwallet-secure.com","myethereumwalletntw.info","real-markets.io","wallet-ethereum.org","request-network.com","shapeshifth.io","shiapeshift.in","coin.red-puise.com","ibittreix.com","coinkbase.com","cindicator.pro","myetherwallet.com.ailogin.me","eventchain.co","kinkik.in","myetherumwalletview.com","protostokenhub.com","coinrbase.com","myetherwalletlogin.com","omisegotoken.com","myethereumwalletntw.com","reall.markets","cobinhood.org","cobinhood.io","happy-coin.org","bitfinex.com.co","bitfienex.com","iconn.foundation","centra.vip","smartcontract.live","icon.community","air-token.com","centra.credit","myetherwallet-singin.com","smartcontractlink.com","shapesshift.io","0xtoken.io","augurproject.co","ethereumus.one","myetherumwalet.com","myetherwalletsignin.com","change-bank.org","charge-bank.com","myetherwalletsingin.com","myetherwalletcontract.com","change-bank.io","chainlink.tech","myetherwallet-confirm.com","tokensale.kybernet.network","kybernet.network","kyberr.network","kybernetwork.io","myetherwalletconfirm.com","kvnuke.github.io","kin.kikpro.co","myethereumwallet.co.uk","tokensale-kyber.network","kyber-network.co","tokensale.kyber-network.co","pyro0.github.io","tokensale.kyber.digital","kyber.digital","omise-go.me","my.etherwallet.com.de","bepartof.change-bank.co","change-bank.co","enigma-tokens.co","coinbase.com.eslogin.co","xn--bittrx-mva.com","ethrdelta.github.io","etherdellta.com","ico-nexus.social","red-pulse.tech","bitj0b.io","xn--bttrex-bwa.com","kin-klk.com","kin-crowdsale.com","ethedelta.com","coindash.su","myethwallet.co.uk","swarm.credit","myethereumwallet.uk","iconexu.social","wanchain.co","enigrna.co","linknetwork.co","qtum-token.com","omisego.com.co","rivetzintl.org","etherdelta.one","the-ether.pro","etherdelta.gitnub.io","kirkik.com","monetha.ltd","vlberate.io","ethereumwallet-kr.info","omise-go.org","iconexus.social","bittirrex.com","aventus.pro","atlant.solutions","aventus.group","metamak.io","omise.com.co","herotokens.io","starbase.pro","etherdelta.githulb.io","herotoken.co","kinico.net","dmarket.ltd","etherdelta.gilthub.io","golem-network.com","etnerscan.io","bllttriex.com","monetha.me","monetha.co","monetha-crowdsale.com","starbase.tech","aventus-crowdsale.com","shapeshift.pro","bllttrex.com","kickico.co","statustoken.im","bilttrex.com","tenxpay.io","bittrex.ltd","metalpay.im","aragon.im","coindash.tech","decentraland.tech","decentraland.pro","status-token.com","bittrex.cam","enigmatoken.com","unocoin.company","unocoin.fund","0xproject.io","0xtoken.com","numerai.tech","decentraiand.org","blockcrein.info","blockchealn.info","bllookchain.info","blockcbhain.info","myetherwallet.com.ethpromonodes.com","mettamask.io","tokenswap.org","netherum.com","etherexx.org","etherume.io","ethereum.plus","ehtereum.org","etereurm.org","etheream.com","ethererum.org","ethereum.io","etherdelta-glthub.com","cryptoalliance.herokuapp.com","bitspark2.com","indorsetoken.com","iconexus.tk","iconexus.ml","iconexus.ga","iconexus.cf","etherwallet.online","wallet-ethereum.net","bitsdigit.com","etherswap.org","eos.ac","uasfwallet.com","ziber.io","multiply-ethereum.info","bittrex.comze.com","karbon.vacau.com","etherdelta.gitlhub.io","etherdelta.glthub.io","digitaldevelopersfund.vacau.com","district-0x.io","coin-dash.com","coindash.ru","district0x.net","aragonproject.io","coin-wallet.info","coinswallet.info","contribute-status.im","ether-api.com","ether-wall.com","mycoinwallet.net","ethereumchamber.com","ethereumchamber.net","ethereumchest.com","ethewallet.com","myetherwallet.com.vc","myetherwallet.com.pe","myetherwallet.us.com","myetherwallet.com.u0387831.cp.regruhosting.ru","myethereumwallet.su","myetherweb.com.de","myetherieumwallet.com","myetehrwallet.com","myeterwalet.com","myetherwaiiet.com","myetherwallet.info","myetherwallet.ch","myetherwallet.om","myethervallet.com","myetherwallet.com.cm","myetherwallet.com.co","myetherwallet.com.de","myetherwallet.com.gl","myetherwallet.com.im","myetherwallet.com.ua","secure-myetherwallet.com","update-myetherwallet.com","wwwmyetherwallet.com","myeatherwallet.com","myetharwallet.com","myelherwallel.com","myetherwaillet.com","myetherwaliet.com","myetherwallel.com","myetherwallet.cam","myetherwallet.cc","myetherwallet.co","myetherwallet.cm","myetherwallet.cz","myetherwallet.org","myetherwallet.tech","myetherwallet.top","myetherwallet.net","myetherwallet.ru.com","myetherwallet.com.ru","metherwallet.com","myetrerwallet.com","myetlerwallet.com","myethterwallet.com","myethwallet.io","myethterwallet.co","myehterwallet.co","myaetherwallet.com","myetthterwallet.com","myetherwallet.one","myelterwallet.com","myetherwallet.gdn","myetherwallt.com","myeterwallet.com","myeteherwallet.com","myethearwailet.com","myetherwallelt.com","myetherwallett.com","etherwallet.org","myetherewallet.com","myeherwallet.com","myethcrwallet.com","myetherwallet.link","myetherwallets.com","myethearwaillet.com","myethearwallet.com","myetherawllet.com","myethereallet.com","myetherswallet.com","myetherwalet.com","myetherwaller.com","myetherwalliet.com","myetherwllet.com","etherwallet.io","myetherwallet.ca","myetherwallet.me","myetherwallet.ru","myetherwallet.xyz","myetherwallte.com","myethirwallet.com","myethrewallet.com","etherwallet.net","maetherwallet.com","meyetherwallet.com","my.ether-wallet.pw","myehterwallet.com","myeitherwallet.com","myelherwallet.com","myeltherwallet.com","myerherwallet.com","myethearwalet.com","myetherewalle.com","myethervvallet.com","myetherwallent.com","myetherwallet.fm","myetherwalllet.com","myetherwalltet.com","myetherwollet.com","myetlherwalet.com","myetlherwallet.com","rnyetherwallet.com","etherclassicwallet.com","omg-omise.co","omise-go.com","omise-go.net","omise-omg.com","omise-go.io","tenx-tech.com","bitclaive.com","tokensale-tenx.tech","ubiqcoin.org","metamask.com","ethtrade.io","myetcwallet.com","account-kigo.net","bitcoin-wallet.net","blocklichan.info","bloclkicihan.info","coindash.ml","eos-bonus.com","eos-io.info","ether-wallet.net","ethereum-wallet.info","ethereum-wallet.net","ethereumchest.net","reservations-kigo.net","reservations-lodgix.com","secure-liverez.com","secure-onerooftop.com","settings-liverez.com","software-liverez.com","software-lodgix.com","unhackableetherwallets.com","www-myetherwallet.com","etherwallet.co.za","etherwalletchain.com","etherwallets.net","etherwallets.nl","my-ethwallet.com","my.ether-wallet.co","myetherwallet.com.am","myetherwallet.com.ht","myetherwalletcom.com","myehterwailet.com","xn--myetherwalle-xoc.com","xn--myetherwalle-44i.com","xn--myetherwalle-xhk.com","xn--myetherwallt-cfb.com","xn--myetherwallt-6tb.com","xn--myetherwallt-xub.com","xn--myetherwallt-ovb.com","xn--myetherwallt-fwb.com","xn--myetherwallt-5wb.com","xn--myetherwallt-jzi.com","xn--myetherwallt-2ck.com","xn--myetherwallt-lok.com","xn--myetherwallt-lsl.com","xn--myetherwallt-ce6f.com","xn--myetherwalet-mcc.com","xn--myetherwalet-xhf.com","xn--myetherwalet-lcc.com","xn--myetherwaet-15ba.com","xn--myetherwalet-whf.com","xn--myetherwaet-v2ea.com","xn--myetherwllet-59a.com","xn--myetherwllet-jbb.com","xn--myetherwllet-wbb.com","xn--myetherwllet-9bb.com","xn--myetherwllet-ncb.com","xn--myetherwllet-0cb.com","xn--myetherwllet-5nb.com","xn--myetherwllet-ktd.com","xn--myetherwllet-mre.com","xn--myetherwllet-76e.com","xn--myetherwllet-o0l.com","xn--myetherwllet-c45f.com","xn--myetherallet-ejn.com","xn--myethewallet-4nf.com","xn--myethewallet-iof.com","xn--myethewallet-mpf.com","xn--myethewallet-6bk.com","xn--myethewallet-i31f.com","xn--myethrwallet-feb.com","xn--myethrwallt-fbbf.com","xn--myethrwallet-seb.com","xn--myethrwallt-rbbf.com","xn--myethrwallet-5eb.com","xn--myethrwallt-3bbf.com","xn--myethrwallet-0tb.com","xn--myethrwallt-tpbf.com","xn--myethrwallet-rub.com","xn--myethrwallt-iqbf.com","xn--myethrwallet-ivb.com","xn--myethrwallt-6qbf.com","xn--myethrwallet-8vb.com","xn--myethrwallt-vrbf.com","xn--myethrwallet-zwb.com","xn--myethrwallt-ksbf.com","xn--myethrwallet-dzi.com","xn--myethrwallt-wbif.com","xn--myethrwallet-wck.com","xn--myethrwallt-skjf.com","xn--myethrwallet-fok.com","xn--myethrwallt-fvjf.com","xn--myethrwallet-fsl.com","xn--myethrwallt-fwkf.com","xn--myethrwallet-5d6f.com","xn--myethrwallt-319ef.com","xn--myeterwallet-ufk.com","xn--myeterwallet-nrl.com","xn--myeterwallet-von.com","xn--myeterwallet-jl6c.com","xn--myeherwallet-ooc.com","xn--myeherwalle-6hci.com","xn--myeherwallet-v4i.com","xn--myeherwalle-zgii.com","xn--myeherwallet-ohk.com","xn--myeherwalle-6oji.com","xn--mytherwallet-ceb.com","xn--mythrwallet-cbbc.com","xn--mythrwallt-c7acf.com","xn--mytherwallet-peb.com","xn--mythrwallet-obbc.com","xn--mythrwallt-n7acf.com","xn--mytherwallet-2eb.com","xn--mythrwallet-0bbc.com","xn--mythrwallt-y7acf.com","xn--mytherwallet-xtb.com","xn--mythrwallet-qpbc.com","xn--mythrwallt-jlbcf.com","xn--mytherwallet-oub.com","xn--mythrwallet-fqbc.com","xn--mythrwallt-5lbcf.com","xn--mythrwallet-3qbc.com","xn--mythrwallt-smbcf.com","xn--mytherwallet-5vb.com","xn--mythrwallet-srbc.com","xn--mythrwallt-fnbcf.com","xn--mytherwallet-wwb.com","xn--mythrwallet-hsbc.com","xn--mythrwallt-1nbcf.com","xn--mytherwallet-9yi.com","xn--mythrwallet-tbic.com","xn--mythrwallt-dnhcf.com","xn--mytherwallet-tck.com","xn--mythrwallet-pkjc.com","xn--mythrwallt-lsicf.com","xn--mytherwallet-cok.com","xn--mythrwallet-cvjc.com","xn--mythrwallt-c2icf.com","xn--mytherwallet-csl.com","xn--mythrwallet-cwkc.com","xn--mythrwallt-c0jcf.com","xn--mytherwallet-2d6f.com","xn--mythrwallet-019ec.com","xn--mythrwallt-yq3ecf.com","xn--metherwallet-qlb.com","xn--metherwallet-1uf.com","xn--metherwallet-iyi.com","xn--metherwallet-zhk.com","xn--metherwallet-3ml.com","xn--mytherwallet-fvb.com","xn--myetherwallt-7db.com","xn--myetherwallt-leb.com","xn--myetherwallt-yeb.com","xn--yetherwallet-vjf.com","xn--yetherwallet-dfk.com","xn--yetherwallet-1t1f.com","xn--yetherwallet-634f.com","xn--myeherwallet-fpc.com","xn--myethewallt-crb.com","xn--metherwallet-1vc.com","xn--myeherwallt-kbb8039g.com","xn--myeherwallet-vk5f.com","xn--yethewallet-iw8ejl.com","xn--bittrx-th8b.com","xn--polniex-n0a.com","thekey.vin","thekey-vip.com","digitexftures.com","ethzero-wallet.org","zeepln.io","wepowers.network","wepower.vision"]}},"CurrencyController":{"currentCurrency":"usd","conversionRate":1112,"conversionDate":1517351401}}}
diff --git a/test/lib/mock-encryptor.js b/test/lib/mock-encryptor.js
index ef229a82f..48aa9e52c 100644
--- a/test/lib/mock-encryptor.js
+++ b/test/lib/mock-encryptor.js
@@ -31,6 +31,6 @@ module.exports = {
getRandomValues () {
return 'SOO RANDO!!!1'
- }
+ },
}
diff --git a/test/lib/mock-tx-gen.js b/test/lib/mock-tx-gen.js
index 7aea09c59..106101500 100644
--- a/test/lib/mock-tx-gen.js
+++ b/test/lib/mock-tx-gen.js
@@ -17,14 +17,14 @@ class TxGenerator {
}
generate (tx = {}, opts = {}) {
- let { count, fromNonce } = opts
+ const { count, fromNonce } = opts
let nonce = fromNonce || this.txs.length
- let txs = []
+ const txs = []
for (let i = 0; i < count; i++) {
txs.push(extend(template, {
txParams: {
nonce: hexify(nonce++),
- }
+ },
}, tx))
}
this.txs = this.txs.concat(txs)
diff --git a/test/lib/react-trigger-change.js b/test/lib/react-trigger-change.js
index a25ddff00..d169dd614 100644
--- a/test/lib/react-trigger-change.js
+++ b/test/lib/react-trigger-change.js
@@ -1,7 +1,7 @@
// Trigger React's synthetic change events on input, textarea and select elements
// https://github.com/vitalyq/react-trigger-change
-/******************IMPORTANT NOTE******************/
+/** ****************IMPORTANT NOTE******************/
/* This file is a modification of the */
/* 'react-trigger-change' library linked above. */
/* That library breaks when 'onFocus' events are */
@@ -11,13 +11,13 @@
/* This modification removes the accomodations */
/* 'react-trigger-change' makes for IE to ensure */
/* our tests can pass in chrome and firefox. */
-/**************************************************/
+/** ************************************************/
-'use strict';
+'use strict'
// Constants and functions are declared inside the closure.
// In this way, reactTriggerChange can be passed directly to executeScript in Selenium.
-module.exports = function reactTriggerChange(node) {
+module.exports = function reactTriggerChange (node) {
var supportedInputTypes = {
color: true,
date: true,
@@ -33,47 +33,47 @@ module.exports = function reactTriggerChange(node) {
text: true,
time: true,
url: true,
- week: true
- };
- var nodeName = node.nodeName.toLowerCase();
- var type = node.type;
- var event;
- var descriptor;
- var initialValue;
- var initialChecked;
- var initialCheckedRadio;
+ week: true,
+ }
+ var nodeName = node.nodeName.toLowerCase()
+ var type = node.type
+ var event
+ var descriptor
+ var initialValue
+ var initialChecked
+ var initialCheckedRadio
// Do not try to delete non-configurable properties.
// Value and checked properties on DOM elements are non-configurable in PhantomJS.
- function deletePropertySafe(elem, prop) {
- var desc = Object.getOwnPropertyDescriptor(elem, prop);
+ function deletePropertySafe (elem, prop) {
+ var desc = Object.getOwnPropertyDescriptor(elem, prop)
if (desc && desc.configurable) {
- delete elem[prop];
+ delete elem[prop]
}
}
- function getCheckedRadio(radio) {
- var name = radio.name;
- var radios;
- var i;
+ function getCheckedRadio (radio) {
+ var name = radio.name
+ var radios
+ var i
if (name) {
- radios = document.querySelectorAll('input[type="radio"][name="' + name + '"]');
+ radios = document.querySelectorAll('input[type="radio"][name="' + name + '"]')
for (i = 0; i < radios.length; i += 1) {
if (radios[i].checked) {
- return radios[i] !== radio ? radios[i] : null;
+ return radios[i] !== radio ? radios[i] : null
}
}
}
- return null;
+ return null
}
- function preventChecking(e) {
- e.preventDefault();
+ function preventChecking (e) {
+ e.preventDefault()
if (!initialChecked) {
- e.target.checked = false;
+ e.target.checked = false
}
if (initialCheckedRadio) {
- initialCheckedRadio.checked = true;
+ initialCheckedRadio.checked = true
}
}
@@ -81,81 +81,81 @@ module.exports = function reactTriggerChange(node) {
(nodeName === 'input' && type === 'file')) {
// IE9-IE11, non-IE
// Dispatch change.
- event = document.createEvent('HTMLEvents');
- event.initEvent('change', true, false);
- node.dispatchEvent(event);
+ event = document.createEvent('HTMLEvents')
+ event.initEvent('change', true, false)
+ node.dispatchEvent(event)
} else if ((nodeName === 'input' && supportedInputTypes[type]) ||
nodeName === 'textarea') {
// React 16
// Cache artificial value property descriptor.
// Property doesn't exist in React <16, descriptor is undefined.
- descriptor = Object.getOwnPropertyDescriptor(node, 'value');
+ descriptor = Object.getOwnPropertyDescriptor(node, 'value')
// Update inputValueTracking cached value.
// Remove artificial value property.
// Restore initial value to trigger event with it.
- initialValue = node.value;
- node.value = initialValue + '#';
- deletePropertySafe(node, 'value');
- node.value = initialValue;
+ initialValue = node.value
+ node.value = initialValue + '#'
+ deletePropertySafe(node, 'value')
+ node.value = initialValue
// React 0.14: IE10-IE11, non-IE
// React 15: non-IE
// React 16: IE10-IE11, non-IE
- event = document.createEvent('HTMLEvents');
- event.initEvent('input', true, false);
- node.dispatchEvent(event);
+ event = document.createEvent('HTMLEvents')
+ event.initEvent('input', true, false)
+ node.dispatchEvent(event)
// React 16
// Restore artificial value property descriptor.
if (descriptor) {
- Object.defineProperty(node, 'value', descriptor);
+ Object.defineProperty(node, 'value', descriptor)
}
} else if (nodeName === 'input' && type === 'checkbox') {
// Invert inputValueTracking cached value.
- node.checked = !node.checked;
+ node.checked = !node.checked
// Dispatch click.
// Click event inverts checked value.
- event = document.createEvent('MouseEvents');
- event.initEvent('click', true, true);
- node.dispatchEvent(event);
+ event = document.createEvent('MouseEvents')
+ event.initEvent('click', true, true)
+ node.dispatchEvent(event)
} else if (nodeName === 'input' && type === 'radio') {
// Cache initial checked value.
- initialChecked = node.checked;
+ initialChecked = node.checked
// Find and cache initially checked radio in the group.
- initialCheckedRadio = getCheckedRadio(node);
+ initialCheckedRadio = getCheckedRadio(node)
// React 16
// Cache property descriptor.
// Invert inputValueTracking cached value.
// Remove artificial checked property.
// Restore initial value, otherwise preventDefault will eventually revert the value.
- descriptor = Object.getOwnPropertyDescriptor(node, 'checked');
- node.checked = !initialChecked;
- deletePropertySafe(node, 'checked');
- node.checked = initialChecked;
+ descriptor = Object.getOwnPropertyDescriptor(node, 'checked')
+ node.checked = !initialChecked
+ deletePropertySafe(node, 'checked')
+ node.checked = initialChecked
// Prevent toggling during event capturing phase.
// Set checked value to false if initialChecked is false,
// otherwise next listeners will see true.
// Restore initially checked radio in the group.
- node.addEventListener('click', preventChecking, true);
+ node.addEventListener('click', preventChecking, true)
// Dispatch click.
// Click event inverts checked value.
- event = document.createEvent('MouseEvents');
- event.initEvent('click', true, true);
- node.dispatchEvent(event);
+ event = document.createEvent('MouseEvents')
+ event.initEvent('click', true, true)
+ node.dispatchEvent(event)
// Remove listener to stop further change prevention.
- node.removeEventListener('click', preventChecking, true);
+ node.removeEventListener('click', preventChecking, true)
// React 16
// Restore artificial checked property descriptor.
if (descriptor) {
- Object.defineProperty(node, 'checked', descriptor);
+ Object.defineProperty(node, 'checked', descriptor)
}
}
-};
+}
diff --git a/test/lib/util.js b/test/lib/util.js
index 626280745..858565bb9 100644
--- a/test/lib/util.js
+++ b/test/lib/util.js
@@ -11,7 +11,7 @@ function timeout (time) {
})
}
-async function findAsync(container, selector, opts) {
+async function findAsync (container, selector, opts) {
try {
return await pollUntilTruthy(() => {
const result = container.find(selector)
@@ -22,7 +22,7 @@ async function findAsync(container, selector, opts) {
}
}
-async function queryAsync(jQuery, selector, opts) {
+async function queryAsync (jQuery, selector, opts) {
try {
return await pollUntilTruthy(() => {
const result = jQuery(selector)
@@ -33,7 +33,7 @@ async function queryAsync(jQuery, selector, opts) {
}
}
-async function pollUntilTruthy(fn, opts = {}){
+async function pollUntilTruthy (fn, opts = {}) {
const pollingInterval = opts.pollingInterval || 100
const timeoutInterval = opts.timeoutInterval || 5000
const start = Date.now()
diff --git a/test/mascara.conf.js b/test/mascara.conf.js
index 97e53fc2b..faf3147bd 100644
--- a/test/mascara.conf.js
+++ b/test/mascara.conf.js
@@ -1,13 +1,13 @@
const getBaseConfig = require('./base.conf.js')
-module.exports = function(config) {
+module.exports = function (config) {
const settings = getBaseConfig(config)
// ui and tests
settings.files.push('dist/mascara/ui.js')
settings.files.push('dist/mascara/tests.js')
// service worker background
- settings.files.push({ pattern: 'dist/mascara/background.js', watched: false, included: false, served: true }),
+ settings.files.push({ pattern: 'dist/mascara/background.js', watched: false, included: false, served: true })
settings.proxies['/background.js'] = '/base/dist/mascara/background.js'
// use this to keep the browser open for debugging
diff --git a/test/screens/new-ui.js b/test/screens/new-ui.js
index e3ba7f6ab..92d1b8378 100644
--- a/test/screens/new-ui.js
+++ b/test/screens/new-ui.js
@@ -12,7 +12,7 @@ const pngFileStream = require('png-file-stream')
const sizeOfPng = require('image-size/lib/types/png')
const By = webdriver.By
const localesIndex = require('../../app/_locales/index.json')
-const { delay, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, getExtensionIdChrome, getExtensionIdFirefox } = require('../e2e/func')
+const { delay, buildChromeWebDriver, getExtensionIdChrome } = require('../e2e/func')
const eth = new Ethjs(new Ethjs.HttpProvider('http://localhost:8545'))
@@ -41,11 +41,9 @@ captureAllScreens()
})
-async function captureAllScreens() {
+async function captureAllScreens () {
// common names
- let button
let tabs
- let element
await cleanScreenShotDir()
@@ -108,7 +106,7 @@ async function captureAllScreens() {
await captureLanguageScreenShots('terms')
await delay(300)
- element = driver.findElement(By.linkText('Attributions'))
+ const element = driver.findElement(By.linkText('Attributions'))
await driver.executeScript('arguments[0].scrollIntoView(true)', element)
await delay(300)
await captureLanguageScreenShots('terms-scrolled')
@@ -134,10 +132,10 @@ async function captureAllScreens() {
// enter seed phrase
const seedPhraseButtons = await driver.findElements(By.css('.backup-phrase__confirm-seed-options > button'))
const seedPhraseButtonWords = await Promise.all(seedPhraseButtons.map(button => button.getText()))
- for (let targetWord of seedPhraseWords) {
+ for (const targetWord of seedPhraseWords) {
const wordIndex = seedPhraseButtonWords.indexOf(targetWord)
if (wordIndex === -1) throw new Error(`Captured seed phrase word "${targetWord}" not in found seed phrase button options ${seedPhraseButtonWords.join(' ')}`)
- await driver.findElement(By.css(`.backup-phrase__confirm-seed-options > button:nth-child(${wordIndex+1})`)).click()
+ await driver.findElement(By.css(`.backup-phrase__confirm-seed-options > button:nth-child(${wordIndex + 1})`)).click()
await delay(100)
}
await captureLanguageScreenShots('confirm secret backup phrase - words selected correctly')
@@ -191,11 +189,11 @@ async function captureAllScreens() {
}
-async function captureLanguageScreenShots(label) {
+async function captureLanguageScreenShots (label) {
const nonEnglishLocales = localesIndex.filter(localeMeta => localeMeta.code !== 'en')
// take english shot
await captureScreenShot(`${label} (en)`)
- for (let localeMeta of nonEnglishLocales) {
+ for (const localeMeta of nonEnglishLocales) {
// set locale and take shot
await setLocale(localeMeta.code)
await delay(300)
@@ -206,19 +204,19 @@ async function captureLanguageScreenShots(label) {
await delay(300)
}
-async function setLocale(code) {
+async function setLocale (code) {
await driver.executeScript('window.metamask.updateCurrentLocale(arguments[0])', code)
}
-async function setProviderType(type) {
+async function setProviderType (type) {
await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
}
-async function cleanScreenShotDir() {
+async function cleanScreenShotDir () {
await pify(rimraf)(`./test-artifacts/screens/`)
}
-async function captureScreenShot(label) {
+async function captureScreenShot (label) {
const shotIndex = screenshotCount.toString().padStart(4, '0')
screenshotCount++
const artifactDir = `./test-artifacts/screens/`
@@ -228,7 +226,7 @@ async function captureScreenShot(label) {
await pify(fs.writeFile)(`${artifactDir}/${shotIndex} - ${label}.png`, screenshot, { encoding: 'base64' })
}
-async function generateGif(){
+async function generateGif () {
// calculate screenshot size
const screenshot = await driver.takeScreenshot()
const pngBuffer = Buffer.from(screenshot, 'base64')
@@ -244,7 +242,7 @@ async function generateGif(){
await pify(endOfStream)(stream)
}
-async function verboseReportOnFailure(test) {
+async function verboseReportOnFailure (test) {
const artifactDir = `./test-artifacts/${test.title}`
const filepathBase = `${artifactDir}/test-failure`
await pify(mkdirp)(artifactDir)
@@ -256,7 +254,7 @@ async function verboseReportOnFailure(test) {
await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource)
}
-async function requestEther(address) {
+async function requestEther (address) {
const accounts = await eth.accounts()
await eth.sendTransaction({ from: accounts[0], to: address, value: 1 * 1e18, data: '0x0' })
}
diff --git a/test/unit/actions/tx_test.js b/test/unit/actions/tx_test.js
index c110f71fc..160cd4552 100644
--- a/test/unit/actions/tx_test.js
+++ b/test/unit/actions/tx_test.js
@@ -1,74 +1,54 @@
-// var jsdom = require('mocha-jsdom')
var assert = require('assert')
-var freeze = require('deep-freeze-strict')
var path = require('path')
-var sinon = require('sinon')
-var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
-var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
+import configureMockStore from 'redux-mock-store'
+import thunk from 'redux-thunk'
-describe('tx confirmation screen', function () {
- beforeEach(function () {
- this.sinon = sinon.createSandbox()
- })
-
- afterEach(function () {
- this.sinon.restore()
- })
+const actions = require(path.join(__dirname, '../../../ui/app/actions.js'))
- var initialState, result
+const middlewares = [thunk]
+const mockStore = configureMockStore(middlewares)
- describe('when there is only one tx', function () {
- var firstTxId = 1457634084250832
-
- beforeEach(function () {
- initialState = {
- appState: {
- currentView: {
- name: 'confTx',
- },
- },
- metamask: {
- unapprovedTxs: {
- '1457634084250832': {
- id: 1457634084250832,
- status: 'unconfirmed',
- time: 1457634084250,
- },
- },
+describe('tx confirmation screen', function () {
+ const txId = 1457634084250832
+ const initialState = {
+ appState: {
+ currentView: {
+ name: 'confTx',
+ },
+ },
+ metamask: {
+ unapprovedTxs: {
+ [txId]: {
+ id: txId,
+ status: 'unconfirmed',
+ time: 1457634084250,
},
- }
- freeze(initialState)
+ },
+ },
+ }
+
+ const store = mockStore(initialState)
+
+ describe('cancelTx', function () {
+ before(function (done) {
+ actions._setBackgroundConnection({
+ approveTransaction (txId, cb) { cb('An error!') },
+ cancelTransaction (txId, cb) { cb() },
+ clearSeedWordCache (cb) { cb() },
+ getState (cb) { cb() },
+ })
+ done()
})
- describe('cancelTx', function () {
- before(function (done) {
- actions._setBackgroundConnection({
- approveTransaction (txId, cb) { cb('An error!') },
- cancelTransaction (txId, cb) { cb() },
- clearSeedWordCache (cb) { cb() },
+ it('creates COMPLETED_TX with the cancelled transaction ID', function (done) {
+ store.dispatch(actions.cancelTx({ id: txId }))
+ .then(() => {
+ const storeActions = store.getActions()
+ const completedTxAction = storeActions.find(({ type }) => type === actions.COMPLETED_TX)
+ assert.equal(completedTxAction.value, txId)
+ done()
})
-
- actions.cancelTx({value: firstTxId})((action) => {
- result = reducers(initialState, action)
- })
- done()
- })
-
- it('should transition to the account detail view', function () {
- assert.equal(result.appState.currentView.name, 'accountDetail')
- })
-
- it('should have no unconfirmed txs remaining', function () {
- var count = getUnconfirmedTxCount(result)
- assert.equal(count, 0)
- })
})
})
})
-
-function getUnconfirmedTxCount (state) {
- var txs = state.metamask.unapprovedTxs
- var count = Object.keys(txs).length
- return count
-}
diff --git a/test/unit/app/account-import-strategies.spec.js b/test/unit/app/account-import-strategies.spec.js
index 216c2f698..d20ba0f0b 100644
--- a/test/unit/app/account-import-strategies.spec.js
+++ b/test/unit/app/account-import-strategies.spec.js
@@ -1,5 +1,4 @@
const assert = require('assert')
-const path = require('path')
const ethUtil = require('ethereumjs-util')
const accountImporter = require('../../../app/scripts/account-import-strategies/index')
const { assertRejects } = require('../test-utils')
@@ -15,7 +14,7 @@ describe('Account Import Strategies', function () {
})
it('throws an error for empty string private key', async () => {
- assertRejects(async function() {
+ assertRejects(async function () {
await accountImporter.importAccount('Private Key', [ '' ])
}, Error, 'no empty strings')
})
diff --git a/test/unit/app/controllers/address-book-controller.js b/test/unit/app/controllers/address-book-controller.js
index dc4b8e3ff..1350e1a61 100644
--- a/test/unit/app/controllers/address-book-controller.js
+++ b/test/unit/app/controllers/address-book-controller.js
@@ -12,7 +12,7 @@ const stubPreferencesStore = {
},
}
},
-};
+}
describe('address-book-controller', function () {
var addressBookController
diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js
new file mode 100644
index 000000000..426ffe23a
--- /dev/null
+++ b/test/unit/app/controllers/detect-tokens-test.js
@@ -0,0 +1,141 @@
+const assert = require('assert')
+const sinon = require('sinon')
+const ObservableStore = require('obs-store')
+const DetectTokensController = require('../../../../app/scripts/controllers/detect-tokens')
+const NetworkController = require('../../../../app/scripts/controllers/network/network')
+const PreferencesController = require('../../../../app/scripts/controllers/preferences')
+
+describe('DetectTokensController', () => {
+ const sandbox = sinon.createSandbox()
+ let clock
+ let keyringMemStore
+ before(async () => {
+ keyringMemStore = new ObservableStore({ isUnlocked: false})
+ })
+ after(() => {
+ sandbox.restore()
+ })
+
+ it('should poll on correct interval', async () => {
+ const stub = sinon.stub(global, 'setInterval')
+ new DetectTokensController({ interval: 1337 }) // eslint-disable-line no-new
+ assert.strictEqual(stub.getCall(0).args[1], 1337)
+ stub.restore()
+ })
+
+ it('should be called on every polling period', async () => {
+ clock = sandbox.useFakeTimers()
+ const network = new NetworkController()
+ network.setProviderType('mainnet')
+ const preferences = new PreferencesController()
+ const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
+ controller.isOpen = true
+ controller.isUnlocked = true
+
+ var stub = sandbox.stub(controller, 'detectNewTokens')
+
+ clock.tick(1)
+ sandbox.assert.notCalled(stub)
+ clock.tick(180000)
+ sandbox.assert.called(stub)
+ clock.tick(180000)
+ sandbox.assert.calledTwice(stub)
+ clock.tick(180000)
+ sandbox.assert.calledThrice(stub)
+ })
+
+ it('should not check tokens while in test network', async () => {
+ const network = new NetworkController()
+ network.setProviderType('rinkeby')
+ const preferences = new PreferencesController()
+ const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
+ controller.isOpen = true
+ controller.isUnlocked = true
+
+ var stub = sandbox.stub(controller, 'detectTokenBalance')
+ .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true)
+ .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388').returns(true)
+
+ await controller.detectNewTokens()
+ sandbox.assert.notCalled(stub)
+ })
+
+ it('should only check and add tokens while in main network', async () => {
+ const network = new NetworkController()
+ network.setProviderType('mainnet')
+ const preferences = new PreferencesController()
+ const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
+ controller.isOpen = true
+ controller.isUnlocked = true
+
+ sandbox.stub(controller, 'detectTokenBalance')
+ .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4')
+ .returns(preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8))
+ .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388')
+ .returns(preferences.addToken('0xbc86727e770de68b1060c91f6bb6945c73e10388', 'XNK', 18))
+
+ await controller.detectNewTokens()
+ assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'},
+ {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}])
+ })
+
+ it('should not detect same token while in main network', async () => {
+ const network = new NetworkController()
+ network.setProviderType('mainnet')
+ const preferences = new PreferencesController()
+ preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8)
+ const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
+ controller.isOpen = true
+ controller.isUnlocked = true
+
+ sandbox.stub(controller, 'detectTokenBalance')
+ .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4')
+ .returns(preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8))
+ .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388')
+ .returns(preferences.addToken('0xbc86727e770de68b1060c91f6bb6945c73e10388', 'XNK', 18))
+
+ await controller.detectNewTokens()
+ assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'},
+ {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}])
+ })
+
+ it('should trigger detect new tokens when change address', async () => {
+ const network = new NetworkController()
+ network.setProviderType('mainnet')
+ const preferences = new PreferencesController()
+ const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
+ controller.isOpen = true
+ controller.isUnlocked = true
+ var stub = sandbox.stub(controller, 'detectNewTokens')
+ await preferences.setSelectedAddress('0xbc86727e770de68b1060c91f6bb6945c73e10388')
+ sandbox.assert.called(stub)
+ })
+
+ it('should trigger detect new tokens when submit password', async () => {
+ const network = new NetworkController()
+ network.setProviderType('mainnet')
+ const preferences = new PreferencesController()
+ const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
+ controller.isOpen = true
+ controller.selectedAddress = '0x0'
+ var stub = sandbox.stub(controller, 'detectNewTokens')
+ await controller._keyringMemStore.updateState({ isUnlocked: true })
+ sandbox.assert.called(stub)
+ })
+
+ it('should not trigger detect new tokens when not open or not unlocked', async () => {
+ const network = new NetworkController()
+ network.setProviderType('mainnet')
+ const preferences = new PreferencesController()
+ const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
+ controller.isOpen = true
+ controller.isUnlocked = false
+ var stub = sandbox.stub(controller, 'detectTokenBalance')
+ clock.tick(180000)
+ sandbox.assert.notCalled(stub)
+ controller.isOpen = false
+ controller.isUnlocked = true
+ clock.tick(180000)
+ sandbox.assert.notCalled(stub)
+ })
+})
diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js
index 0dda4609b..9164fe246 100644
--- a/test/unit/app/controllers/metamask-controller-test.js
+++ b/test/unit/app/controllers/metamask-controller-test.js
@@ -222,6 +222,129 @@ describe('MetaMaskController', function () {
})
})
+ describe('connectHardware', function () {
+
+ it('should throw if it receives an unknown device name', async function () {
+ try {
+ await metamaskController.connectHardware('Some random device name', 0)
+ } catch (e) {
+ assert.equal(e, 'Error: MetamaskController:connectHardware - Unknown device')
+ }
+ })
+
+ it('should add the Trezor Hardware keyring', async function () {
+ sinon.spy(metamaskController.keyringController, 'addNewKeyring')
+ await metamaskController.connectHardware('trezor', 0).catch((e) => null)
+ const keyrings = await metamaskController.keyringController.getKeyringsByType(
+ 'Trezor Hardware'
+ )
+ assert.equal(metamaskController.keyringController.addNewKeyring.getCall(0).args, 'Trezor Hardware')
+ assert.equal(keyrings.length, 1)
+ })
+
+ })
+
+ describe('checkHardwareStatus', function () {
+ it('should throw if it receives an unknown device name', async function () {
+ try {
+ await metamaskController.checkHardwareStatus('Some random device name')
+ } catch (e) {
+ assert.equal(e, 'Error: MetamaskController:checkHardwareStatus - Unknown device')
+ }
+ })
+
+ it('should be locked by default', async function () {
+ await metamaskController.connectHardware('trezor', 0).catch((e) => null)
+ const status = await metamaskController.checkHardwareStatus('trezor')
+ assert.equal(status, false)
+ })
+ })
+
+ describe('forgetDevice', function () {
+ it('should throw if it receives an unknown device name', async function () {
+ try {
+ await metamaskController.forgetDevice('Some random device name')
+ } catch (e) {
+ assert.equal(e, 'Error: MetamaskController:forgetDevice - Unknown device')
+ }
+ })
+
+ it('should wipe all the keyring info', async function () {
+ await metamaskController.connectHardware('trezor', 0).catch((e) => null)
+ await metamaskController.forgetDevice('trezor')
+ const keyrings = await metamaskController.keyringController.getKeyringsByType(
+ 'Trezor Hardware'
+ )
+
+ assert.deepEqual(keyrings[0].accounts, [])
+ assert.deepEqual(keyrings[0].page, 0)
+ assert.deepEqual(keyrings[0].isUnlocked(), false)
+ })
+ })
+
+ describe('unlockTrezorAccount', function () {
+ let accountToUnlock
+ let windowOpenStub
+ let addNewAccountStub
+ let getAccountsStub
+ beforeEach(async function () {
+ accountToUnlock = 10
+ windowOpenStub = sinon.stub(window, 'open')
+ windowOpenStub.returns(noop)
+
+ addNewAccountStub = sinon.stub(metamaskController.keyringController, 'addNewAccount')
+ addNewAccountStub.returns({})
+
+ getAccountsStub = sinon.stub(metamaskController.keyringController, 'getAccounts')
+ // Need to return different address to mock the behavior of
+ // adding a new account from the keyring
+ getAccountsStub.onCall(0).returns(Promise.resolve(['0x1']))
+ getAccountsStub.onCall(1).returns(Promise.resolve(['0x2']))
+ getAccountsStub.onCall(2).returns(Promise.resolve(['0x3']))
+ getAccountsStub.onCall(3).returns(Promise.resolve(['0x4']))
+ sinon.spy(metamaskController.preferencesController, 'setAddresses')
+ sinon.spy(metamaskController.preferencesController, 'setSelectedAddress')
+ sinon.spy(metamaskController.preferencesController, 'setAccountLabel')
+ await metamaskController.connectHardware('trezor', 0).catch((e) => null)
+ await metamaskController.unlockTrezorAccount(accountToUnlock).catch((e) => null)
+ })
+
+ afterEach(function () {
+ metamaskController.keyringController.addNewAccount.restore()
+ window.open.restore()
+ })
+
+ it('should set accountToUnlock in the keyring', async function () {
+ const keyrings = await metamaskController.keyringController.getKeyringsByType(
+ 'Trezor Hardware'
+ )
+ assert.equal(keyrings[0].unlockedAccount, accountToUnlock)
+ })
+
+
+ it('should call keyringController.addNewAccount', async function () {
+ assert(metamaskController.keyringController.addNewAccount.calledOnce)
+ })
+
+ it('should call keyringController.getAccounts ', async function () {
+ assert(metamaskController.keyringController.getAccounts.called)
+ })
+
+ it('should call preferencesController.setAddresses', async function () {
+ assert(metamaskController.preferencesController.setAddresses.calledOnce)
+ })
+
+ it('should call preferencesController.setSelectedAddress', async function () {
+ assert(metamaskController.preferencesController.setSelectedAddress.calledOnce)
+ })
+
+ it('should call preferencesController.setAccountLabel', async function () {
+ assert(metamaskController.preferencesController.setAccountLabel.calledOnce)
+ })
+
+
+ })
+
describe('#setCustomRpc', function () {
const customRPC = 'https://custom.rpc/'
let rpcTarget
@@ -362,6 +485,39 @@ describe('MetaMaskController', function () {
})
})
+ describe('#removeAccount', function () {
+ let ret
+ const addressToRemove = '0x1'
+
+ beforeEach(async function () {
+ sinon.stub(metamaskController.preferencesController, 'removeAddress')
+ sinon.stub(metamaskController.accountTracker, 'removeAccount')
+ sinon.stub(metamaskController.keyringController, 'removeAccount')
+
+ ret = await metamaskController.removeAccount(addressToRemove)
+
+ })
+
+ afterEach(function () {
+ metamaskController.keyringController.removeAccount.restore()
+ metamaskController.accountTracker.removeAccount.restore()
+ metamaskController.preferencesController.removeAddress.restore()
+ })
+
+ it('should call preferencesController.removeAddress', async function () {
+ assert(metamaskController.preferencesController.removeAddress.calledWith(addressToRemove))
+ })
+ it('should call accountTracker.removeAccount', async function () {
+ assert(metamaskController.accountTracker.removeAccount.calledWith(addressToRemove))
+ })
+ it('should call keyringController.removeAccount', async function () {
+ assert(metamaskController.keyringController.removeAccount.calledWith(addressToRemove))
+ })
+ it('should return address', async function () {
+ assert.equal(ret, '0x1')
+ })
+ })
+
describe('#clearSeedWordCache', function () {
it('should have set seed words', function () {
diff --git a/test/unit/app/controllers/network-contoller-test.js b/test/unit/app/controllers/network-contoller-test.js
index 789850ef3..e16fb104e 100644
--- a/test/unit/app/controllers/network-contoller-test.js
+++ b/test/unit/app/controllers/network-contoller-test.js
@@ -5,9 +5,6 @@ const {
getNetworkDisplayName,
} = require('../../../../app/scripts/controllers/network/util')
-const { createTestProviderTools } = require('../../../stub/provider')
-const providerResultStub = {}
-
describe('# Network Controller', function () {
let networkController
const noop = () => {}
diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js
index e5e751b57..e055500b1 100644
--- a/test/unit/app/controllers/preferences-controller-test.js
+++ b/test/unit/app/controllers/preferences-controller-test.js
@@ -52,6 +52,31 @@ describe('preferences controller', function () {
})
})
+ describe('removeAddress', function () {
+ it('should remove an address from state', function () {
+ preferencesController.setAddresses([
+ '0xda22le',
+ '0x7e57e2',
+ ])
+
+ preferencesController.removeAddress('0xda22le')
+
+ assert.equal(preferencesController.store.getState().identities['0xda22le'], undefined)
+ })
+
+ it('should switch accounts if the selected address is removed', function () {
+ preferencesController.setAddresses([
+ '0xda22le',
+ '0x7e57e2',
+ ])
+
+ preferencesController.setSelectedAddress('0x7e57e2')
+ preferencesController.removeAddress('0x7e57e2')
+
+ assert.equal(preferencesController.getSelectedAddress(), '0xda22le')
+ })
+ })
+
describe('setAccountLabel', function () {
it('should update a label for the given account', function () {
preferencesController.setAddresses([
diff --git a/test/unit/app/controllers/transactions/nonce-tracker-test.js b/test/unit/app/controllers/transactions/nonce-tracker-test.js
index fc852458c..6c0ac759f 100644
--- a/test/unit/app/controllers/transactions/nonce-tracker-test.js
+++ b/test/unit/app/controllers/transactions/nonce-tracker-test.js
@@ -1,12 +1,10 @@
const assert = require('assert')
const NonceTracker = require('../../../../../app/scripts/controllers/transactions/nonce-tracker')
const MockTxGen = require('../../../../lib/mock-tx-gen')
-let providerResultStub = {}
+const providerResultStub = {}
describe('Nonce Tracker', function () {
- let nonceTracker, provider
- let getPendingTransactions, pendingTxs
- let getConfirmedTransactions, confirmedTxs
+ let nonceTracker, pendingTxs, confirmedTxs
describe('#getNonceLock', function () {
@@ -182,8 +180,8 @@ describe('Nonce Tracker', function () {
describe('When all three return different values', function () {
beforeEach(function () {
const txGen = new MockTxGen()
- const confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 10 })
- const pendingTxs = txGen.generate({
+ confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 10 })
+ pendingTxs = txGen.generate({
status: 'submitted',
nonce: 100,
}, { count: 1 })
@@ -202,8 +200,8 @@ describe('Nonce Tracker', function () {
describe('Faq issue 67', function () {
beforeEach(function () {
const txGen = new MockTxGen()
- const confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 64 })
- const pendingTxs = txGen.generate({
+ confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 64 })
+ pendingTxs = txGen.generate({
status: 'submitted',
}, { count: 10 })
// 0x40 is 64 in hex:
diff --git a/test/unit/app/controllers/transactions/pending-tx-test.js b/test/unit/app/controllers/transactions/pending-tx-test.js
index e7705c594..8bf2da6f8 100644
--- a/test/unit/app/controllers/transactions/pending-tx-test.js
+++ b/test/unit/app/controllers/transactions/pending-tx-test.js
@@ -1,20 +1,12 @@
const assert = require('assert')
-const ethUtil = require('ethereumjs-util')
-const EthTx = require('ethereumjs-tx')
-const ObservableStore = require('obs-store')
-const clone = require('clone')
const { createTestProviderTools } = require('../../../../stub/provider')
const PendingTransactionTracker = require('../../../../../app/scripts/controllers/transactions/pending-tx-tracker')
const MockTxGen = require('../../../../lib/mock-tx-gen')
const sinon = require('sinon')
-const noop = () => true
-const currentNetworkId = 42
-const otherNetworkId = 36
-const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f33003270ec03e', 'hex')
describe('PendingTransactionTracker', function () {
- let pendingTxTracker, txMeta, txMetaNoHash, txMetaNoRawTx, providerResultStub,
+ let pendingTxTracker, txMeta, txMetaNoHash, providerResultStub,
provider, txMeta3, txList, knownErrors
this.timeout(10000)
beforeEach(function () {
@@ -34,11 +26,7 @@ describe('PendingTransactionTracker', function () {
status: 'signed',
txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d'},
}
- txMetaNoRawTx = {
- hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
- status: 'signed',
- txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d'},
- }
+
providerResultStub = {}
provider = createTestProviderTools({ scaffold: providerResultStub }).provider
@@ -47,10 +35,10 @@ describe('PendingTransactionTracker', function () {
nonceTracker: {
getGlobalLock: async () => {
return { releaseLock: () => {} }
- }
+ },
},
- getPendingTransactions: () => {return []},
- getCompletedTransactions: () => {return []},
+ getPendingTransactions: () => { return [] },
+ getCompletedTransactions: () => { return [] },
publishTransaction: () => {},
})
})
@@ -133,22 +121,20 @@ describe('PendingTransactionTracker', function () {
})
describe('#queryPendingTxs', function () {
it('should call #_checkPendingTxs if their is no oldBlock', function (done) {
- let newBlock, oldBlock
- newBlock = { number: '0x01' }
+ let oldBlock
+ const newBlock = { number: '0x01' }
pendingTxTracker._checkPendingTxs = done
pendingTxTracker.queryPendingTxs({ oldBlock, newBlock })
})
it('should call #_checkPendingTxs if oldBlock and the newBlock have a diff of greater then 1', function (done) {
- let newBlock, oldBlock
- oldBlock = { number: '0x01' }
- newBlock = { number: '0x03' }
+ const oldBlock = { number: '0x01' }
+ const newBlock = { number: '0x03' }
pendingTxTracker._checkPendingTxs = done
pendingTxTracker.queryPendingTxs({ oldBlock, newBlock })
})
it('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less', function (done) {
- let newBlock, oldBlock
- oldBlock = { number: '0x1' }
- newBlock = { number: '0x2' }
+ const oldBlock = { number: '0x1' }
+ const newBlock = { number: '0x2' }
pendingTxTracker._checkPendingTxs = () => {
const err = new Error('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less')
done(err)
@@ -189,7 +175,7 @@ describe('PendingTransactionTracker', function () {
txMeta2.id = 2
txMeta3.id = 3
txList = [txMeta, txMeta2, txMeta3].map((tx) => {
- tx.processed = new Promise ((resolve) => { tx.resolve = resolve })
+ tx.processed = new Promise((resolve) => { tx.resolve = resolve })
return tx
})
})
@@ -197,7 +183,6 @@ describe('PendingTransactionTracker', function () {
it('should warp all txMeta\'s in #_checkPendingTx', function (done) {
pendingTxTracker.getPendingTransactions = () => txList
pendingTxTracker._checkPendingTx = (tx) => { tx.resolve(tx) }
- const list = txList.map
Promise.all(txList.map((tx) => tx.processed))
.then((txCompletedList) => done())
.catch(done)
@@ -207,11 +192,11 @@ describe('PendingTransactionTracker', function () {
})
describe('#resubmitPendingTxs', function () {
- const blockStub = { number: '0x0' };
+ const blockStub = { number: '0x0' }
beforeEach(function () {
const txMeta2 = txMeta3 = txMeta
txList = [txMeta, txMeta2, txMeta3].map((tx) => {
- tx.processed = new Promise ((resolve) => { tx.resolve = resolve })
+ tx.processed = new Promise((resolve) => { tx.resolve = resolve })
return tx
})
})
@@ -228,7 +213,7 @@ describe('PendingTransactionTracker', function () {
pendingTxTracker.resubmitPendingTxs(blockStub)
})
it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) {
- knownErrors =[
+ knownErrors = [
// geth
' Replacement transaction Underpriced ',
' known transaction',
@@ -275,7 +260,7 @@ describe('PendingTransactionTracker', function () {
})
describe('#_resubmitTx', function () {
const mockFirstRetryBlockNumber = '0x1'
- let txMetaToTestExponentialBackoff
+ let txMetaToTestExponentialBackoff, enoughBalance
beforeEach(() => {
pendingTxTracker.getBalance = (address) => {
@@ -298,7 +283,7 @@ describe('PendingTransactionTracker', function () {
})
it('should publish the transaction', function (done) {
- const enoughBalance = '0x100000'
+ enoughBalance = '0x100000'
// Stubbing out current account state:
// Adding the fake tx:
@@ -313,7 +298,7 @@ describe('PendingTransactionTracker', function () {
})
it('should not publish the transaction if the limit of retries has been exceeded', function (done) {
- const enoughBalance = '0x100000'
+ enoughBalance = '0x100000'
const mockLatestBlockNumber = '0x5'
pendingTxTracker._resubmitTx(txMetaToTestExponentialBackoff, mockLatestBlockNumber)
@@ -327,7 +312,7 @@ describe('PendingTransactionTracker', function () {
})
it('should publish the transaction if the number of blocks since last retry exceeds the last set limit', function (done) {
- const enoughBalance = '0x100000'
+ enoughBalance = '0x100000'
const mockLatestBlockNumber = '0x11'
pendingTxTracker._resubmitTx(txMetaToTestExponentialBackoff, mockLatestBlockNumber)
@@ -342,8 +327,8 @@ describe('PendingTransactionTracker', function () {
})
describe('#_checkIfNonceIsTaken', function () {
- beforeEach ( function () {
- let confirmedTxList = [{
+ beforeEach(function () {
+ const confirmedTxList = [{
id: 1,
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: 'confirmed',
diff --git a/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js b/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js
index 56e8d50db..cb413545f 100644
--- a/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js
+++ b/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js
@@ -28,7 +28,7 @@ describe('Recipient Blacklist Checker', function () {
it('does not fail on test networks', function () {
let callCount = 0
const networks = [ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE]
- for (let networkId in networks) {
+ for (const networkId in networks) {
publicAccounts.forEach((account) => {
recipientBlackListChecker.checkAccount(networkId, account)
callCount++
@@ -61,7 +61,7 @@ describe('Recipient Blacklist Checker', function () {
} catch (err) {
assert.equal(err.message, 'Recipient is a public account')
}
- })
+ })
it('fails for public account - lowercase', async function () {
const mainnetId = 1
@@ -72,6 +72,6 @@ describe('Recipient Blacklist Checker', function () {
} catch (err) {
assert.equal(err.message, 'Recipient is a public account')
}
- })
+ })
})
})
diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js
index 9bdfe7c1a..26dc7b656 100644
--- a/test/unit/app/controllers/transactions/tx-controller-test.js
+++ b/test/unit/app/controllers/transactions/tx-controller-test.js
@@ -1,20 +1,17 @@
const assert = require('assert')
const ethUtil = require('ethereumjs-util')
const EthTx = require('ethereumjs-tx')
-const EthjsQuery = require('ethjs-query')
const ObservableStore = require('obs-store')
const sinon = require('sinon')
const TransactionController = require('../../../../../app/scripts/controllers/transactions')
-const TxGasUtils = require('../../../../../app/scripts/controllers/transactions/tx-gas-utils')
const { createTestProviderTools, getTestAccounts } = require('../../../../stub/provider')
const noop = () => true
const currentNetworkId = 42
-const otherNetworkId = 36
describe('Transaction Controller', function () {
- let txController, provider, providerResultStub, query, fromAccount
+ let txController, provider, providerResultStub, fromAccount
beforeEach(function () {
providerResultStub = {
@@ -24,7 +21,6 @@ describe('Transaction Controller', function () {
eth_getCode: '0x',
}
provider = createTestProviderTools({ scaffold: providerResultStub }).provider
- query = new EthjsQuery(provider)
fromAccount = getTestAccounts()[0]
txController = new TransactionController({
@@ -357,9 +353,16 @@ describe('Transaction Controller', function () {
])
})
- it('should set the transaction to rejected from unapproved', async function () {
- await txController.cancelTransaction(0)
- assert.equal(txController.txStateManager.getTx(0).status, 'rejected')
+ it('should emit a status change to rejected', function (done) {
+ txController.once('tx:status-update', (txId, status) => {
+ try {
+ assert.equal(status, 'rejected', 'status should e rejected')
+ assert.equal(txId, 0, 'id should e 0')
+ done()
+ } catch (e) { done(e) }
+ })
+
+ txController.cancelTransaction(0)
})
})
@@ -388,7 +391,7 @@ describe('Transaction Controller', function () {
describe('#retryTransaction', function () {
it('should create a new txMeta with the same txParams as the original one', function (done) {
- let txParams = {
+ const txParams = {
nonce: '0x00',
from: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4',
to: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4',
diff --git a/test/unit/app/controllers/transactions/tx-gas-util-test.js b/test/unit/app/controllers/transactions/tx-gas-util-test.js
index d1ee86033..31defd6ed 100644
--- a/test/unit/app/controllers/transactions/tx-gas-util-test.js
+++ b/test/unit/app/controllers/transactions/tx-gas-util-test.js
@@ -1,6 +1,5 @@
const assert = require('assert')
const Transaction = require('ethereumjs-tx')
-const BN = require('bn.js')
const { hexToBn, bnToHex } = require('../../../../../app/scripts/lib/util')
diff --git a/test/unit/app/controllers/transactions/tx-state-history-helper-test.js b/test/unit/app/controllers/transactions/tx-state-history-helper-test.js
index f4c3a6be1..fba0e7fda 100644
--- a/test/unit/app/controllers/transactions/tx-state-history-helper-test.js
+++ b/test/unit/app/controllers/transactions/tx-state-history-helper-test.js
@@ -2,16 +2,16 @@ const assert = require('assert')
const txStateHistoryHelper = require('../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
const testVault = require('../../../../data/v17-long-history.json')
-describe ('Transaction state history helper', function () {
+describe('Transaction state history helper', function () {
describe('#snapshotFromTxMeta', function () {
it('should clone deep', function () {
const input = {
foo: {
bar: {
- bam: 'baz'
- }
- }
+ bam: 'baz',
+ },
+ },
}
const output = txStateHistoryHelper.snapshotFromTxMeta(input)
assert('foo' in output, 'has a foo key')
@@ -50,14 +50,14 @@ describe ('Transaction state history helper', function () {
it('replaying history does not mutate the original obj', function () {
const initialState = { test: true, message: 'hello', value: 1 }
const diff1 = [{
- "op": "replace",
- "path": "/message",
- "value": "haay",
+ 'op': 'replace',
+ 'path': '/message',
+ 'value': 'haay',
}]
const diff2 = [{
- "op": "replace",
- "path": "/value",
- "value": 2,
+ 'op': 'replace',
+ 'path': '/value',
+ 'value': 2,
}]
const history = [initialState, diff1, diff2]
@@ -72,15 +72,15 @@ describe ('Transaction state history helper', function () {
describe('#generateHistoryEntry', function () {
- function generateHistoryEntryTest(note) {
+ function generateHistoryEntryTest (note) {
const prevState = {
someValue: 'value 1',
foo: {
bar: {
- bam: 'baz'
- }
- }
+ bam: 'baz',
+ },
+ },
}
const nextState = {
@@ -89,9 +89,9 @@ describe ('Transaction state history helper', function () {
foo: {
newPropFirstLevel: 'new property - first level',
bar: {
- bam: 'baz'
- }
- }
+ bam: 'baz',
+ },
+ },
}
const before = new Date().getTime()
@@ -106,8 +106,7 @@ describe ('Transaction state history helper', function () {
assert.equal(result[0].path, expectedEntry1.path)
assert.equal(result[0].value, expectedEntry1.value)
assert.equal(result[0].value, expectedEntry1.value)
- if (note)
- assert.equal(result[0].note, note)
+ if (note) { assert.equal(result[0].note, note) }
assert.ok(result[0].timestamp >= before && result[0].timestamp <= after)
@@ -124,6 +123,6 @@ describe ('Transaction state history helper', function () {
it('should add note to first entry', function () {
generateHistoryEntryTest('custom note')
- })
+ })
})
-}) \ No newline at end of file
+})
diff --git a/test/unit/app/controllers/transactions/tx-state-manager-test.js b/test/unit/app/controllers/transactions/tx-state-manager-test.js
index 20bc08b94..88bdaa60e 100644
--- a/test/unit/app/controllers/transactions/tx-state-manager-test.js
+++ b/test/unit/app/controllers/transactions/tx-state-manager-test.js
@@ -1,6 +1,4 @@
const assert = require('assert')
-const clone = require('clone')
-const ObservableStore = require('obs-store')
const TxStateManager = require('../../../../../app/scripts/controllers/transactions/tx-state-manager')
const txStateHistoryHelper = require('../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
const noop = () => true
@@ -16,23 +14,23 @@ describe('TransactionStateManager', function () {
transactions: [],
},
txHistoryLimit: 10,
- getNetwork: () => currentNetworkId
+ getNetwork: () => currentNetworkId,
})
})
describe('#setTxStatusSigned', function () {
it('sets the tx status to signed', function () {
- let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
+ const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop)
txStateManager.setTxStatusSigned(1)
- let result = txStateManager.getTxList()
+ const result = txStateManager.getTxList()
assert.ok(Array.isArray(result))
assert.equal(result.length, 1)
assert.equal(result[0].status, 'signed')
})
it('should emit a signed event to signal the exciton of callback', (done) => {
- let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
+ const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
const noop = function () {
assert(true, 'event listener has been triggered and noop executed')
done()
@@ -45,22 +43,24 @@ describe('TransactionStateManager', function () {
})
describe('#setTxStatusRejected', function () {
- it('sets the tx status to rejected', function () {
- let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
+ it('sets the tx status to rejected and removes it from history', function () {
+ const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx)
txStateManager.setTxStatusRejected(1)
- let result = txStateManager.getTxList()
+ const result = txStateManager.getTxList()
assert.ok(Array.isArray(result))
- assert.equal(result.length, 1)
- assert.equal(result[0].status, 'rejected')
+ assert.equal(result.length, 0)
})
it('should emit a rejected event to signal the exciton of callback', (done) => {
- let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
+ const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx)
const noop = function (err, txId) {
- assert(true, 'event listener has been triggered and noop executed')
- done()
+ if (err) {
+ console.log('Error: ', err)
+ }
+ assert(true, 'event listener has been triggered and noop executed')
+ done()
}
txStateManager.on('1:rejected', noop)
txStateManager.setTxStatusRejected(1)
@@ -69,7 +69,7 @@ describe('TransactionStateManager', function () {
describe('#getFullTxList', function () {
it('when new should return empty array', function () {
- let result = txStateManager.getTxList()
+ const result = txStateManager.getTxList()
assert.ok(Array.isArray(result))
assert.equal(result.length, 0)
})
@@ -77,7 +77,7 @@ describe('TransactionStateManager', function () {
describe('#getTxList', function () {
it('when new should return empty array', function () {
- let result = txStateManager.getTxList()
+ const result = txStateManager.getTxList()
assert.ok(Array.isArray(result))
assert.equal(result.length, 0)
})
@@ -85,21 +85,21 @@ describe('TransactionStateManager', function () {
describe('#addTx', function () {
it('adds a tx returned in getTxList', function () {
- let tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
+ const tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop)
- let result = txStateManager.getTxList()
+ const result = txStateManager.getTxList()
assert.ok(Array.isArray(result))
assert.equal(result.length, 1)
assert.equal(result[0].id, 1)
})
it('does not override txs from other networks', function () {
- let tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
- let tx2 = { id: 2, status: 'confirmed', metamaskNetworkId: otherNetworkId, txParams: {} }
+ const tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
+ const tx2 = { id: 2, status: 'confirmed', metamaskNetworkId: otherNetworkId, txParams: {} }
txStateManager.addTx(tx, noop)
txStateManager.addTx(tx2, noop)
- let result = txStateManager.getFullTxList()
- let result2 = txStateManager.getTxList()
+ const result = txStateManager.getFullTxList()
+ const result2 = txStateManager.getTxList()
assert.equal(result.length, 2, 'txs were deleted')
assert.equal(result2.length, 1, 'incorrect number of txs on network.')
})
@@ -110,7 +110,7 @@ describe('TransactionStateManager', function () {
const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop)
}
- let result = txStateManager.getTxList()
+ const result = txStateManager.getTxList()
assert.equal(result.length, limit, `limit of ${limit} txs enforced`)
assert.equal(result[0].id, 1, 'early txs truncted')
})
@@ -121,20 +121,20 @@ describe('TransactionStateManager', function () {
const tx = { id: i, time: new Date(), status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop)
}
- let result = txStateManager.getTxList()
+ const result = txStateManager.getTxList()
assert.equal(result.length, limit, `limit of ${limit} txs enforced`)
assert.equal(result[0].id, 1, 'early txs truncted')
})
it('cuts off early txs beyond a limit but does not cut unapproved txs', function () {
- let unconfirmedTx = { id: 0, time: new Date(), status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
+ const unconfirmedTx = { id: 0, time: new Date(), status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(unconfirmedTx, noop)
const limit = txStateManager.txHistoryLimit
for (let i = 1; i < limit + 1; i++) {
const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop)
}
- let result = txStateManager.getTxList()
+ const result = txStateManager.getTxList()
assert.equal(result.length, limit, `limit of ${limit} txs enforced`)
assert.equal(result[0].id, 0, 'first tx should still be there')
assert.equal(result[0].status, 'unapproved', 'first tx should be unapproved')
@@ -149,7 +149,7 @@ describe('TransactionStateManager', function () {
const txMeta = txStateManager.getTx('1')
txMeta.hash = 'foo'
txStateManager.updateTx(txMeta)
- let result = txStateManager.getTx('1')
+ const result = txStateManager.getTx('1')
assert.equal(result.hash, 'foo')
})
@@ -166,8 +166,6 @@ describe('TransactionStateManager', function () {
},
}
- const updatedMeta = clone(txMeta)
-
txStateManager.addTx(txMeta)
const updatedTx = txStateManager.getTx('1')
// verify tx was initialized correctly
@@ -185,7 +183,7 @@ describe('TransactionStateManager', function () {
// validate history was updated
assert.equal(result.history.length, 2, 'two history items (initial + diff)')
assert.equal(result.history[1].length, 1, 'two history state items (initial + diff)')
-
+
const expectedEntry = { op: 'replace', path: '/txParams/gasPrice', value: desiredGasPrice }
assert.deepEqual(result.history[1][0].op, expectedEntry.op, 'two history items (initial + diff) operation')
assert.deepEqual(result.history[1][0].path, expectedEntry.path, 'two history items (initial + diff) path')
@@ -288,4 +286,18 @@ describe('TransactionStateManager', function () {
})
})
+
+ describe('#_removeTx', function () {
+ it('should remove the transaction from the storage', () => {
+ txStateManager._saveTxList([ {id: 1} ])
+ txStateManager._removeTx(1)
+ assert(!txStateManager.getFullTxList().length, 'txList should be empty')
+ })
+
+ it('should only remove the transaction with ID 1 from the storage', () => {
+ txStateManager._saveTxList([ {id: 1}, {id: 2} ])
+ txStateManager._removeTx(1)
+ assert.equal(txStateManager.getFullTxList()[0].id, 2, 'txList should have a id of 2')
+ })
+ })
})
diff --git a/test/unit/app/controllers/transactions/tx-utils-test.js b/test/unit/app/controllers/transactions/tx-utils-test.js
index 115127f85..029fab4d5 100644
--- a/test/unit/app/controllers/transactions/tx-utils-test.js
+++ b/test/unit/app/controllers/transactions/tx-utils-test.js
@@ -27,7 +27,7 @@ describe('txUtils', function () {
describe('#normalizeTxParams', () => {
it('should normalize txParams', () => {
- let txParams = {
+ const txParams = {
chainId: '0x1',
from: 'a7df1beDBF813f57096dF77FCd515f0B3900e402',
to: null,
@@ -91,7 +91,7 @@ describe('txUtils', function () {
assert.throws(() => { txUtils.validateFrom(txParams) }, Error, `Invalid from address`)
// should run
- txParams.from ='0x1678a085c290ebd122dc42cba69373b5953b831d'
+ txParams.from = '0x1678a085c290ebd122dc42cba69373b5953b831d'
txUtils.validateFrom(txParams)
})
})
diff --git a/test/unit/app/edge-encryptor-test.js b/test/unit/app/edge-encryptor-test.js
index cc9777389..1a6255b36 100644
--- a/test/unit/app/edge-encryptor-test.js
+++ b/test/unit/app/edge-encryptor-test.js
@@ -11,7 +11,7 @@ global.crypto = global.crypto || {
array[i] = Math.random() * 100
}
return array
- }
+ },
}
describe('EdgeEncryptor', function () {
@@ -33,10 +33,10 @@ describe('EdgeEncryptor', function () {
it('should return proper format.', function (done) {
edgeEncryptor.encrypt(password, data)
.then(function (encryptedData) {
- let encryptedObject = JSON.parse(encryptedData)
+ const encryptedObject = JSON.parse(encryptedData)
assert.ok(encryptedObject.data, 'there is no data')
- assert.ok(encryptedObject.iv && encryptedObject.iv.length != 0, 'there is no iv')
- assert.ok(encryptedObject.salt && encryptedObject.salt.length != 0, 'there is no salt')
+ assert.ok(encryptedObject.iv && encryptedObject.iv.length !== 0, 'there is no iv')
+ assert.ok(encryptedObject.salt && encryptedObject.salt.length !== 0, 'there is no salt')
done()
}).catch(function (err) {
done(err)
@@ -56,7 +56,7 @@ describe('EdgeEncryptor', function () {
assert.notEqual(encryptedData[1].length, 0)
done()
})
- })
+ })
})
describe('decrypt', function () {
diff --git a/test/unit/app/nodeify-test.js b/test/unit/app/nodeify-test.js
index 901603c8b..938b76c68 100644
--- a/test/unit/app/nodeify-test.js
+++ b/test/unit/app/nodeify-test.js
@@ -13,8 +13,12 @@ describe('nodeify', function () {
it('should retain original context', function (done) {
var nodified = nodeify(obj.promiseFunc, obj)
nodified('baz', function (err, res) {
- assert.equal(res, 'barbaz')
- done()
+ if (!err) {
+ assert.equal(res, 'barbaz')
+ done()
+ } else {
+ done(new Error(err.toString()))
+ }
})
})
diff --git a/test/unit/app/pending-balance-test.js b/test/unit/app/pending-balance-test.js
index 1418e4a4e..508635c46 100644
--- a/test/unit/app/pending-balance-test.js
+++ b/test/unit/app/pending-balance-test.js
@@ -2,7 +2,6 @@ const assert = require('assert')
const PendingBalanceCalculator = require('../../../app/scripts/lib/pending-balance-calculator')
const MockTxGen = require('../../lib/mock-tx-gen')
const BN = require('ethereumjs-util').BN
-let providerResultStub = {}
const zeroBn = new BN(0)
const etherBn = new BN(String(1e18))
@@ -20,7 +19,7 @@ describe('PendingBalanceCalculator', function () {
value: ether,
gasPrice: '0x0',
gas: '0x0',
- }
+ },
}, { count: 1 })
const balanceCalculator = generateBalanceCalcWith([], zeroBn)
@@ -36,7 +35,7 @@ describe('PendingBalanceCalculator', function () {
value: '0x0',
gasPrice: '0x2',
gas: '0x3',
- }
+ },
}, { count: 1 })
const balanceCalculator = generateBalanceCalcWith([], zeroBn)
@@ -66,7 +65,7 @@ describe('PendingBalanceCalculator', function () {
value: ether,
gasPrice: '0x0',
gas: '0x0',
- }
+ },
}, { count: 1 })
balanceCalculator = generateBalanceCalcWith(pendingTxs, etherBn)
diff --git a/test/unit/app/seed-phrase-verifier-test.js b/test/unit/app/seed-phrase-verifier-test.js
index b0da534da..d8720d5a0 100644
--- a/test/unit/app/seed-phrase-verifier-test.js
+++ b/test/unit/app/seed-phrase-verifier-test.js
@@ -9,11 +9,10 @@ describe('SeedPhraseVerifier', function () {
describe('verifyAccounts', function () {
- let password = 'passw0rd1'
- let hdKeyTree = 'HD Key Tree'
+ const password = 'passw0rd1'
+ const hdKeyTree = 'HD Key Tree'
let keyringController
- let vault
let primaryKeyring
beforeEach(async function () {
@@ -24,60 +23,60 @@ describe('SeedPhraseVerifier', function () {
assert(keyringController)
- vault = await keyringController.createNewVaultAndKeychain(password)
+ await keyringController.createNewVaultAndKeychain(password)
primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0]
})
it('should be able to verify created account with seed words', async function () {
- let createdAccounts = await primaryKeyring.getAccounts()
+ const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1)
- let serialized = await primaryKeyring.serialize()
- let seedWords = serialized.mnemonic
+ const serialized = await primaryKeyring.serialize()
+ const seedWords = serialized.mnemonic
assert.notEqual(seedWords.length, 0)
-
- let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords)
+
+ await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords)
})
it('should be able to verify created account (upper case) with seed words', async function () {
- let createdAccounts = await primaryKeyring.getAccounts()
+ const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1)
- let upperCaseAccounts = [createdAccounts[0].toUpperCase()]
+ const upperCaseAccounts = [createdAccounts[0].toUpperCase()]
- let serialized = await primaryKeyring.serialize()
- let seedWords = serialized.mnemonic
+ const serialized = await primaryKeyring.serialize()
+ const seedWords = serialized.mnemonic
assert.notEqual(seedWords.length, 0)
-
- let result = await seedPhraseVerifier.verifyAccounts(upperCaseAccounts, seedWords)
+
+ await seedPhraseVerifier.verifyAccounts(upperCaseAccounts, seedWords)
})
it('should be able to verify created account (lower case) with seed words', async function () {
- let createdAccounts = await primaryKeyring.getAccounts()
+ const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1)
- let lowerCaseAccounts = [createdAccounts[0].toLowerCase()]
+ const lowerCaseAccounts = [createdAccounts[0].toLowerCase()]
- let serialized = await primaryKeyring.serialize()
- let seedWords = serialized.mnemonic
+ const serialized = await primaryKeyring.serialize()
+ const seedWords = serialized.mnemonic
assert.notEqual(seedWords.length, 0)
-
- let result = await seedPhraseVerifier.verifyAccounts(lowerCaseAccounts, seedWords)
+
+ await seedPhraseVerifier.verifyAccounts(lowerCaseAccounts, seedWords)
})
it('should return error with good but different seed words', async function () {
- let createdAccounts = await primaryKeyring.getAccounts()
+ const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1)
- let serialized = await primaryKeyring.serialize()
- let seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
-
- try {
- let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords)
- assert.fail("Should reject")
+ await primaryKeyring.serialize()
+ const seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
+
+ try {
+ await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords)
+ assert.fail('Should reject')
} catch (err) {
assert.ok(err.message.indexOf('Not identical accounts!') >= 0, 'Wrong error message')
}
@@ -85,15 +84,15 @@ describe('SeedPhraseVerifier', function () {
it('should return error with undefined existing accounts', async function () {
- let createdAccounts = await primaryKeyring.getAccounts()
+ const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1)
- let serialized = await primaryKeyring.serialize()
- let seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
+ await primaryKeyring.serialize()
+ const seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
- try {
- let result = await seedPhraseVerifier.verifyAccounts(undefined, seedWords)
- assert.fail("Should reject")
+ try {
+ await seedPhraseVerifier.verifyAccounts(undefined, seedWords)
+ assert.fail('Should reject')
} catch (err) {
assert.equal(err.message, 'No created accounts defined.')
}
@@ -101,15 +100,15 @@ describe('SeedPhraseVerifier', function () {
it('should return error with empty accounts array', async function () {
- let createdAccounts = await primaryKeyring.getAccounts()
+ const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1)
- let serialized = await primaryKeyring.serialize()
- let seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
+ await primaryKeyring.serialize()
+ const seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
- try {
- let result = await seedPhraseVerifier.verifyAccounts([], seedWords)
- assert.fail("Should reject")
+ try {
+ await seedPhraseVerifier.verifyAccounts([], seedWords)
+ assert.fail('Should reject')
} catch (err) {
assert.equal(err.message, 'No created accounts defined.')
}
@@ -117,17 +116,17 @@ describe('SeedPhraseVerifier', function () {
it('should be able to verify more than one created account with seed words', async function () {
- const keyState = await keyringController.addNewAccount(primaryKeyring)
- const keyState2 = await keyringController.addNewAccount(primaryKeyring)
+ await keyringController.addNewAccount(primaryKeyring)
+ await keyringController.addNewAccount(primaryKeyring)
- let createdAccounts = await primaryKeyring.getAccounts()
+ const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 3)
- let serialized = await primaryKeyring.serialize()
- let seedWords = serialized.mnemonic
+ const serialized = await primaryKeyring.serialize()
+ const seedWords = serialized.mnemonic
assert.notEqual(seedWords.length, 0)
-
- let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords)
+
+ await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords)
})
})
})
diff --git a/test/unit/app/util-test.js b/test/unit/app/util-test.js
index 670bc4d22..656b22d92 100644
--- a/test/unit/app/util-test.js
+++ b/test/unit/app/util-test.js
@@ -38,4 +38,4 @@ describe('SufficientBalance', function () {
const result = sufficientBalance(tx, balance)
assert.ok(!result, 'insufficient balance found.')
})
-}) \ No newline at end of file
+})
diff --git a/test/unit/components/balance-component-test.js b/test/unit/components/balance-component-test.js
index 9b1e82acf..81e6fdf9e 100644
--- a/test/unit/components/balance-component-test.js
+++ b/test/unit/components/balance-component-test.js
@@ -8,7 +8,7 @@ const mockState = {
accounts: { abc: {} },
network: 1,
selectedAddress: 'abc',
- }
+ },
}
describe('BalanceComponent', function () {
diff --git a/test/unit/components/bn-as-decimal-input-test.js b/test/unit/components/bn-as-decimal-input-test.js
index 7b9d9814f..fab396548 100644
--- a/test/unit/components/bn-as-decimal-input-test.js
+++ b/test/unit/components/bn-as-decimal-input-test.js
@@ -52,13 +52,13 @@ describe('BnInput', function () {
it('can tolerate wei precision', function (done) {
const renderer = ReactTestUtils.createRenderer()
- let valueStr = '1000000000'
+ const valueStr = '1000000000'
const value = new BN(valueStr, 10)
const inputStr = '1.000000001'
- let targetStr = '1000000001'
+ const targetStr = '1000000001'
const target = new BN(targetStr, 10)
diff --git a/test/unit/components/pending-tx-test.js b/test/unit/components/pending-tx-test.js
deleted file mode 100644
index c6c588e1c..000000000
--- a/test/unit/components/pending-tx-test.js
+++ /dev/null
@@ -1,67 +0,0 @@
-const assert = require('assert')
-const h = require('react-hyperscript')
-const PendingTx = require('../../../ui/app/components/pending-tx')
-const ethUtil = require('ethereumjs-util')
-
-const { createMockStore } = require('redux-test-utils')
-const { shallowWithStore } = require('../../lib/shallow-with-store')
-
-const identities = { abc: {}, def: {} }
-const mockState = {
- metamask: {
- accounts: { abc: {} },
- identities,
- conversionRate: 10,
- selectedAddress: 'abc',
- }
-}
-
-describe('PendingTx', function () {
- const gasPrice = '0x4A817C800' // 20 Gwei
- const txData = {
- 'id': 5021615666270214,
- 'time': 1494458763011,
- 'status': 'unapproved',
- 'metamaskNetworkId': '1494442339676',
- 'txParams': {
- 'from': '0xfdea65c8e26263f6d9a1b5de9555d2931a33b826',
- 'to': '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
- 'value': '0xde0b6b3a7640000',
- gasPrice,
- 'gas': '0x7b0c',
- },
- 'gasLimitSpecified': false,
- 'estimatedGas': '0x5208',
- }
- const newGasPrice = '0x77359400'
-
- const computedBalances = {}
- computedBalances[Object.keys(identities)[0]] = {
- ethBalance: '0x00000000000000056bc75e2d63100000',
- }
- const props = {
- txData,
- computedBalances,
- sendTransaction: (txMeta, event) => {
- // Assert changes:
- const result = ethUtil.addHexPrefix(txMeta.txParams.gasPrice)
- assert.notEqual(result, gasPrice, 'gas price should change')
- assert.equal(result, newGasPrice, 'gas price assigned.')
- },
- }
-
- let pendingTxComponent
- let store
- let component
- beforeEach(function () {
- store = createMockStore(mockState)
- component = shallowWithStore(h(PendingTx, props), store)
- pendingTxComponent = component
- })
-
- it('should render correctly', function (done) {
- assert.equal(pendingTxComponent.props().identities, identities)
- done()
- })
-})
-
diff --git a/test/unit/migrations/022-test.js b/test/unit/migrations/022-test.js
index 1333d929d..f8ee00e38 100644
--- a/test/unit/migrations/022-test.js
+++ b/test/unit/migrations/022-test.js
@@ -2,14 +2,14 @@ const assert = require('assert')
const migration22 = require('../../../app/scripts/migrations/022')
const properTime = (new Date()).getTime()
const storage = {
- "meta": {},
- "data": {
- "TransactionController": {
- "transactions": [
- { "status": "submitted" },
- { "status": "submitted", "submittedTime": properTime },
- {"status": "confirmed"},
- ]
+ 'meta': {},
+ 'data': {
+ 'TransactionController': {
+ 'transactions': [
+ { 'status': 'submitted' },
+ { 'status': 'submitted', 'submittedTime': properTime },
+ {'status': 'confirmed'},
+ ],
},
},
}
diff --git a/test/unit/migrations/023-test.js b/test/unit/migrations/023-test.js
index be432d9fa..7da94448d 100644
--- a/test/unit/migrations/023-test.js
+++ b/test/unit/migrations/023-test.js
@@ -1,12 +1,11 @@
const assert = require('assert')
const migration23 = require('../../../app/scripts/migrations/023')
-const properTime = (new Date()).getTime()
const storage = {
- "meta": {},
- "data": {
- "TransactionController": {
- "transactions": [
- ]
+ 'meta': {},
+ 'data': {
+ 'TransactionController': {
+ 'transactions': [
+ ],
},
},
}
@@ -53,7 +52,6 @@ while (transactions20.length < 20) {
}
-
storage.data.TransactionController.transactions = transactions
describe('storage is migrated successfully and the proper transactions are remove from state', () => {
diff --git a/test/unit/migrations/024-test.js b/test/unit/migrations/024-test.js
index c3c03d06b..c7b0611bc 100644
--- a/test/unit/migrations/024-test.js
+++ b/test/unit/migrations/024-test.js
@@ -4,13 +4,12 @@ const firstTimeState = {
meta: {},
data: require('../../../app/scripts/first-time-state'),
}
-const properTime = (new Date()).getTime()
const storage = {
- "meta": {},
- "data": {
- "TransactionController": {
- "transactions": [
- ]
+ 'meta': {},
+ 'data': {
+ 'TransactionController': {
+ 'transactions': [
+ ],
},
},
}
diff --git a/test/unit/migrations/025-test.js b/test/unit/migrations/025-test.js
index 76c25dbb6..1e56913a1 100644
--- a/test/unit/migrations/025-test.js
+++ b/test/unit/migrations/025-test.js
@@ -6,11 +6,11 @@ const firstTimeState = {
}
const storage = {
- "meta": {},
- "data": {
- "TransactionController": {
- "transactions": [
- ]
+ 'meta': {},
+ 'data': {
+ 'TransactionController': {
+ 'transactions': [
+ ],
},
},
}
diff --git a/test/unit/migrations/027-test.js b/test/unit/migrations/027-test.js
new file mode 100644
index 000000000..3ec9f0c0e
--- /dev/null
+++ b/test/unit/migrations/027-test.js
@@ -0,0 +1,50 @@
+const assert = require('assert')
+const migration27 = require('../../../app/scripts/migrations/027')
+
+const oldStorage = {
+ 'meta': {},
+ 'data': {
+ 'TransactionController': {
+ 'transactions': [
+ ],
+ },
+ },
+}
+
+const transactions = []
+
+
+while (transactions.length < 9) {
+ transactions.push({status: 'rejected'})
+ transactions.push({status: 'unapproved'})
+ transactions.push({status: 'approved'})
+}
+
+
+oldStorage.data.TransactionController.transactions = transactions
+
+describe('migration #27', () => {
+ it('should remove rejected transactions', (done) => {
+ migration27.migrate(oldStorage)
+ .then((newStorage) => {
+ const newTransactions = newStorage.data.TransactionController.transactions
+ assert.equal(newTransactions.length, 6, 'transactions is expected to have the length of 6')
+ newTransactions.forEach((txMeta) => {
+ if (txMeta.status === 'rejected') done(new Error('transaction was found with a status of rejected'))
+ })
+ done()
+ })
+ .catch(done)
+ })
+
+ it('should successfully migrate first time state', (done) => {
+ migration27.migrate({
+ meta: {},
+ data: require('../../../app/scripts/first-time-state'),
+ })
+ .then((migratedData) => {
+ assert.equal(migratedData.meta.version, migration27.version)
+ done()
+ }).catch(done)
+ })
+})
diff --git a/test/unit/migrations/template-test.js b/test/unit/migrations/template-test.js
index 35060e2fe..0db69d65a 100644
--- a/test/unit/migrations/template-test.js
+++ b/test/unit/migrations/template-test.js
@@ -1,6 +1,5 @@
const assert = require('assert')
const migrationTemplate = require('../../../app/scripts/migrations/template')
-const properTime = (new Date()).getTime()
const storage = {
meta: {},
data: {},
diff --git a/test/unit/responsive/components/dropdown-test.js b/test/unit/responsive/components/dropdown-test.js
index 982d8c6ec..493b01918 100644
--- a/test/unit/responsive/components/dropdown-test.js
+++ b/test/unit/responsive/components/dropdown-test.js
@@ -1,24 +1,24 @@
-const assert = require('assert');
+const assert = require('assert')
-const h = require('react-hyperscript');
-const sinon = require('sinon');
-const path = require('path');
-const Dropdown = require(path.join(__dirname, '..', '..', '..', '..', 'ui', 'app', 'components', 'dropdowns', 'index.js')).Dropdown;
+const h = require('react-hyperscript')
+const sinon = require('sinon')
+const path = require('path')
+const Dropdown = require(path.join(__dirname, '..', '..', '..', '..', 'ui', 'app', 'components', 'dropdowns', 'index.js')).Dropdown
const { createMockStore } = require('redux-test-utils')
const { mountWithStore } = require('../../../lib/shallow-with-store')
const mockState = {
metamask: {
- }
+ },
}
describe('Dropdown components', function () {
- let onClickOutside;
- let closeMenu;
- let onClick;
+ let onClickOutside
+ let closeMenu
+ let onClick
- let dropdownComponentProps = {
+ const dropdownComponentProps = {
isOpen: true,
zIndex: 11,
onClickOutside,
@@ -34,9 +34,9 @@ describe('Dropdown components', function () {
let store
let component
beforeEach(function () {
- onClickOutside = sinon.spy();
- closeMenu = sinon.spy();
- onClick = sinon.spy();
+ onClickOutside = sinon.spy()
+ closeMenu = sinon.spy()
+ onClick = sinon.spy()
store = createMockStore(mockState)
component = mountWithStore(h(
@@ -61,21 +61,21 @@ describe('Dropdown components', function () {
})
it('can render two items', function () {
- const items = dropdownComponent.find('li');
- assert.equal(items.length, 2);
- });
+ const items = dropdownComponent.find('li')
+ assert.equal(items.length, 2)
+ })
- it('closes when item clicked', function() {
- const items = dropdownComponent.find('li');
- const node = items.at(0);
- node.simulate('click');
- assert.equal(node.props().closeMenu, closeMenu);
- });
+ it('closes when item clicked', function () {
+ const items = dropdownComponent.find('li')
+ const node = items.at(0)
+ node.simulate('click')
+ assert.equal(node.props().closeMenu, closeMenu)
+ })
- it('invokes click handler when item clicked', function() {
- const items = dropdownComponent.find('li');
- const node = items.at(0);
- node.simulate('click');
- assert.equal(onClick.calledOnce, true);
- });
-});
+ it('invokes click handler when item clicked', function () {
+ const items = dropdownComponent.find('li')
+ const node = items.at(0)
+ node.simulate('click')
+ assert.equal(onClick.calledOnce, true)
+ })
+})