From d452403322c517eee4fc6120de1ead68ed65ee6a Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Mon, 5 Feb 2018 18:47:46 -0800 Subject: [PATCH] Add functional integration testing to Add Token flow (#3189) --- development/states/add-token.json | 132 +++++++++++++++++++++++++ development/states/first-time.json | 10 +- test/integration/lib/add-token.js | 153 +++++++++++++++++++++++++++++ test/integration/lib/first-time.js | 7 ++ ui/app/components/token-cell.js | 7 +- 5 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 development/states/add-token.json create mode 100644 test/integration/lib/add-token.js diff --git a/development/states/add-token.json b/development/states/add-token.json new file mode 100644 index 000000000..e78393b7f --- /dev/null +++ b/development/states/add-token.json @@ -0,0 +1,132 @@ +{ + "metamask": { + "isInitialized": true, + "isUnlocked": true, + "featureFlags": {"betaUI": true}, + "rpcTarget": "https://rawtestrpc.metamask.io/", + "identities": { + "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { + "address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", + "name": "Send Account 1" + }, + "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { + "address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb", + "name": "Send Account 2" + }, + "0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { + "address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d", + "name": "Send Account 3" + }, + "0xd85a4b6a394794842887b8284293d69163007bbb": { + "address": "0xd85a4b6a394794842887b8284293d69163007bbb", + "name": "Send Account 4" + } + }, + "unapprovedTxs": {}, + "conversionRate": 1200.88200327, + "conversionDate": 1489013762, + "noActiveNotices": true, + "frequentRpcList": [], + "network": "3", + "accounts": { + "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { + "code": "0x", + "balance": "0x47c9d71831c76efe", + "nonce": "0x1b", + "address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" + }, + "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { + "code": "0x", + "balance": "0x37452b1315889f80", + "nonce": "0xa", + "address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb" + }, + "0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { + "code": "0x", + "balance": "0x30c9d71831c76efe", + "nonce": "0x1c", + "address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d" + }, + "0xd85a4b6a394794842887b8284293d69163007bbb": { + "code": "0x", + "balance": "0x0", + "nonce": "0x0", + "address": "0xd85a4b6a394794842887b8284293d69163007bbb" + } + }, + "addressBook": [ + { + "address": "0x06195827297c7a80a443b6894d3bdb8824b43896", + "name": "Address Book Account 1" + } + ], + "tokens": [], + "transactions": {}, + "selectedAddressTxList": [], + "unapprovedMsgs": {}, + "unapprovedMsgCount": 0, + "unapprovedPersonalMsgs": {}, + "unapprovedPersonalMsgCount": 0, + "keyringTypes": [ + "Simple Key Pair", + "HD Key Tree" + ], + "keyrings": [ + { + "type": "HD Key Tree", + "accounts": [ + "fdea65c8e26263f6d9a1b5de9555d2931a33b825", + "c5b8dbac4c1d3f152cdeb400e2313f309c410acb", + "2f8d4a878cfa04a6e60d46362f5644deab66572d" + ] + }, + { + "type": "Simple Key Pair", + "accounts": [ + "0xd85a4b6a394794842887b8284293d69163007bbb" + ] + } + ], + "selectedAddress": "0xd85a4b6a394794842887b8284293d69163007bbb", + "currentCurrency": "USD", + "provider": { + "type": "testnet" + }, + "shapeShiftTxList": [], + "lostAccounts": [], + "send": { + "gasLimit": null, + "gasPrice": null, + "gasTotal": "0xb451dc41b578", + "tokenBalance": null, + "from": "", + "to": "", + "amount": "0x0", + "memo": "", + "errors": {}, + "maxModeOn": false, + "editingTransactionId": null + } + }, + "appState": { + "menuOpen": false, + "currentView": { + "name": "accountDetail", + "detailView": null, + "context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc" + }, + "accountDetail": { + "subview": "transactions" + }, + "modal": { + "modalState": {}, + "previousModalState": {} + }, + "transForward": true, + "isLoading": false, + "warning": null, + "scrollToBottom": false, + "forgottenPassword": null + }, + "identities": {} +} diff --git a/development/states/first-time.json b/development/states/first-time.json index 480839d59..6e7435db1 100644 --- a/development/states/first-time.json +++ b/development/states/first-time.json @@ -35,7 +35,8 @@ "type": "testnet" }, "shapeShiftTxList": [], - "lostAccounts": [] + "lostAccounts": [], + "tokens": [] }, "appState": { "menuOpen": false, @@ -48,7 +49,12 @@ }, "transForward": true, "isLoading": false, - "warning": null + "warning": null, + "modal": { + "modalState": {"name": null}, + "open": false, + "previousModalState": {"name": null} + } }, "identities": {}, "computedBalances": {} diff --git a/test/integration/lib/add-token.js b/test/integration/lib/add-token.js new file mode 100644 index 000000000..dd4251cc4 --- /dev/null +++ b/test/integration/lib/add-token.js @@ -0,0 +1,153 @@ +const reactTriggerChange = require('react-trigger-change') + +QUnit.module('Add token flow') + +QUnit.test('successful add token flow', (assert) => { + const done = assert.async() + runAddTokenFlowTest(assert) + .then(done) + .catch(err => { + assert.notOk(err, `Error was thrown: ${err.stack}`) + done() + }) +}) + +async function runAddTokenFlowTest (assert, done) { + const selectState = $('select') + selectState.val('add token') + reactTriggerChange(selectState[0]) + + await timeout(2000) + + // Check that no tokens have been added + assert.ok($('.token-list-item').length === 0, 'no tokens added') + + // Go to Add Token screen + let addTokenButton = $('button.btn-clear.wallet-view__add-token-button') + assert.ok(addTokenButton[0], 'add token button present') + addTokenButton[0].click() + + await timeout(1000) + + // Verify Add Token screen + let addTokenWrapper = $('.add-token__wrapper') + assert.ok(addTokenWrapper[0], 'add token wrapper renders') + + let addTokenTitle = $('.add-token__title') + assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct') + + // Cancel Add Token + const cancelAddTokenButton = $('button.btn-cancel.add-token__button') + assert.ok(cancelAddTokenButton[0], 'cancel add token button present') + cancelAddTokenButton.click() + + await timeout(1000) + + assert.ok($('.wallet-view')[0], 'cancelled and returned to account detail wallet view') + + // Return to Add Token Screen + addTokenButton = $('button.btn-clear.wallet-view__add-token-button') + assert.ok(addTokenButton[0], 'add token button present') + addTokenButton[0].click() + + await timeout(1000) + + // Verify Add Token Screen + addTokenWrapper = $('.add-token__wrapper') + addTokenTitle = $('.add-token__title') + assert.ok(addTokenWrapper[0], 'add token wrapper renders') + assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct') + + // Search for token + const searchInput = $('input.add-token__input') + searchInput.val('a') + reactTriggerChange(searchInput[0]) + + await timeout() + + // Click token to add + const tokenWrapper = $('div.add-token__token-wrapper') + assert.ok(tokenWrapper[0], 'token found') + const tokenImageProp = tokenWrapper.find('.add-token__token-icon').css('background-image') + const tokenImageUrl = tokenImageProp.slice(5, -2) + tokenWrapper[0].click() + + await timeout() + + // Click Next button + let nextButton = $('button.btn-clear.add-token__button') + assert.equal(nextButton[0].textContent, 'Next', 'next button rendered') + nextButton[0].click() + + await timeout() + + // Confirm Add token + assert.equal( + $('.add-token__description')[0].textContent, + 'Would you like to add these tokens?', + 'confirm add token rendered' + ) + assert.ok($('button.btn-clear.add-token__button')[0], 'confirm add token button found') + $('button.btn-clear.add-token__button')[0].click() + + await timeout(2000) + + // Verify added token image + let heroBalance = $('.hero-balance') + assert.ok(heroBalance, 'rendered hero balance') + assert.ok(tokenImageUrl.indexOf(heroBalance.find('img').attr('src')) > -1, 'token added') + + // Return to Add Token Screen + addTokenButton = $('button.btn-clear.wallet-view__add-token-button') + assert.ok(addTokenButton[0], 'add token button present') + addTokenButton[0].click() + + await timeout(1000) + + const addCustom = $('.add-token__add-custom') + assert.ok(addCustom[0], 'add custom token button present') + addCustom[0].click() + + await timeout() + + // Input token contract address + const customInput = $('input.add-token__add-custom-input') + customInput.val('0x177af043D3A1Aed7cc5f2397C70248Fc6cDC056c') + reactTriggerChange(customInput[0]) + + await timeout(1000) + + // Click Next button + nextButton = $('button.btn-clear.add-token__button') + assert.equal(nextButton[0].textContent, 'Next', 'next button rendered') + nextButton[0].click() + + await timeout(1000) + + // Verify symbol length error since contract address won't return symbol + const errorMessage = $('.add-token__add-custom-error-message') + assert.ok(errorMessage[0], 'error rendered') + $('button.btn-cancel.add-token__button')[0].click() + + await timeout(2000) + + // // Confirm Add token + // assert.equal( + // $('.add-token__description')[0].textContent, + // 'Would you like to add these tokens?', + // 'confirm add token rendered' + // ) + // assert.ok($('button.btn-clear.add-token__button')[0], 'confirm add token button found') + // $('button.btn-clear.add-token__button')[0].click() + + // // Verify added token image + // heroBalance = $('.hero-balance') + // assert.ok(heroBalance, 'rendered hero balance') + // assert.ok(heroBalance.find('.identicon')[0], 'token added') +} + +function timeout (time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time || 1500) + }) +} diff --git a/test/integration/lib/first-time.js b/test/integration/lib/first-time.js index 06325ab98..6e879dcd0 100644 --- a/test/integration/lib/first-time.js +++ b/test/integration/lib/first-time.js @@ -1,3 +1,4 @@ +const reactTriggerChange = require('react-trigger-change') const PASSWORD = 'password123' const runMascaraFirstTimeTest = require('./mascara-first-time') @@ -16,6 +17,12 @@ async function runFirstTimeUsageTest(assert, done) { return runMascaraFirstTimeTest(assert, done) } + const selectState = $('select') + selectState.val('first time') + reactTriggerChange(selectState[0]) + + await timeout(2000) + const app = $('#app-content') // recurse notices diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js index a5d032a0d..5c1c36465 100644 --- a/ui/app/components/token-cell.js +++ b/ui/app/components/token-cell.js @@ -111,9 +111,10 @@ TokenCell.prototype.render = function () { network, }), - h('div.token-list-item__balance-ellipsis', [ + h('div.token-list-item__balance-wrapper', null, [ + h('h3.token-list-item__token-balance', `${string || 0} ${symbol}`), - h('h.token-list-item__balance-wrapper', null, [ + h('div.token-list-item__balance-wrapper', null, [ h('h3.token-list-item__token-balance', `${string || 0} ${symbol}`), showFiat && h('div.token-list-item__fiat-amount', { @@ -129,7 +130,7 @@ TokenCell.prototype.render = function () { }), ]), - + tokenMenuOpen && h(TokenMenuDropdown, { onClose: () => this.setState({ tokenMenuOpen: false }),