diff --git a/package-lock.json b/package-lock.json index 60b9badc7..ae003932a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10630,6 +10630,16 @@ "requires": { "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } } }, "ethereumjs-abi": { diff --git a/test/e2e/elements.js b/test/e2e/elements.js index c43e2aea2..1911569e4 100644 --- a/test/e2e/elements.js +++ b/test/e2e/elements.js @@ -3,6 +3,7 @@ const { By } = webdriver module.exports = { elements: { loader: By.css('#app-content > div > div.full-flex-height > img'), + poaABI: '[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"abstractStorageAddr","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":""}],"name":"getCrowdsalesForUser","inputs":[{"type":"address","name":"deployer"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"countCrowdsalesForUser","inputs":[{"type":"address","name":"deployer"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"changeMintedCappedIdx","inputs":[{"type":"address","name":"newMintedCappedIdxAddr"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"changeDutchIdxAddr","inputs":[{"type":"address","name":"newDutchIdxAddr"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"dutchIdxAddr","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"mintedCappedIdxAddr","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"changeAbstractStorage","inputs":[{"type":"address","name":"newAbstractStorageAddr"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"trackCrowdsale","inputs":[{"type":"address","name":"proxyAddress"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"_newOwner"}],"constant":false},{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"address","name":"_abstractStorage"},{"type":"address","name":"_mintedCappedIdx"},{"type":"address","name":"_dutchIdx"}]},{"type":"event","name":"Added","inputs":[{"type":"address","name":"sender","indexed":true},{"type":"address","name":"proxyAddress","indexed":true},{"type":"bytes32","name":"appExecID","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipRenounced","inputs":[{"type":"address","name":"previousOwner","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false}]', }, menus: { token: { @@ -46,6 +47,28 @@ module.exports = { }, }, screens: { + chooseContractExecutor: { + title: By.className('flex-center send-header'), + titleText: 'Choose contract executor', + buttonNext: By.css('.choose-contract-next-button'), + account: By.className('account-data-subsection flex-row flex-grow'), + selectedAccount: By.className('executor-cell-container-selected'), + + }, + executeMethod: { + title: By.className('flex-center send-header'), + titleText: 'Execute Method', + selectArrow: By.className('Select-arrow-zone'), + item0: By.css('.Select-input > input:nth-child(1)'), + item1: By.className('Select-option'), + item11: By.css('#react-select-2--option-11'), + buttonCall: By.css('.section > button:nth-child(1)'), + fieldOutput: By.css('.input'), + fieldParametr1: By.css('.input'), + buttonNext: By.css('.section > button:nth-child(1)'), + buttonArrow: By.className('fa fa-arrow-left fa-lg cursor-pointer'), + }, + eventsEmitter: { button: By.className('btn btn-default'), event: By.className('Toastify__toast-body'), @@ -59,9 +82,9 @@ module.exports = { error: By.className('error'), accountName: By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(3) > div.identity-panel.flex-row.flex-space-between > div.identity-data.flex-column.flex-justify-center.flex-grow.select-none > h2'), message: By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(3) > div.tx-data.flex-column.flex-justify-center.flex-grow.select-none > div > span'), - }, + }, sendTokens: { - error: By.className('error flex-center'), + error: By.className('error'), errorText: { invalidAmount: 'Invalid token\'s amount', address: 'Recipient address is invalid', @@ -159,11 +182,13 @@ module.exports = { titleText: 'Delete Custom RPC', }, confirmTransaction: { + titleText: 'Confirm Transaction', title: By.className('flex-row flex-center'), amount: By.css('#pending-tx-form > div:nth-child(1) > div.table-box > div:nth-child(2) > div.ether-balance.ether-balance-amount > div > div > div > div:nth-child(1)'), symbol: By.css('#pending-tx-form > div:nth-child(1) > div.table-box > div:nth-child(2) > div.ether-balance.ether-balance-amount > div > div > div > div:nth-child(2)'), button: { submit: By.css('#pending-tx-form > div.flex-row.flex-space-around.conf-buttons > input'), + reject: By.css('.cancel'), }, fields: { gasLimit: By.css('#pending-tx-form > div:nth-child(1) > div.table-box > div:nth-child(3) > div.cell.value > div > div > input'), @@ -196,6 +221,13 @@ module.exports = { }, }, importAccounts: { + warning: By.className('error'), + error: By.css('span.error'), + selectArrow: By.className('Select-arrow-zone'), + selectType: By.name('import-type-select'), + itemContract: By.id('react-select-2--option-2'), + contractAddress: By.id('address-box'), + contractABI: By.id('abi-box'), title: By.css('#app-content > div > div.app-primary.from-right > div > div:nth-child(2) > div.flex-row.flex-center > h2'), textTitle: 'Import Accounts', fieldPrivateKey: By.id('private-key-box'), @@ -241,8 +273,8 @@ module.exports = { menu: By.className('wallet-view__tab-history'), tokens: By.className('activeForm right'), }, - // balance: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > div.ether-balance.ether-balance-amount > div > div > div:nth-child(1) > div:nth-child(1)'), - balance: By.xpath('//*[@id="app-content"]/div/div[2]/div/div/div[2]/div[1]/div/div/div[1]/div[1]'), + // balance: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > div.ether-balance.ether-balance-amount > div > div > div:nth-child(1) > div:nth-child(1)'), + balance: By.xpath('//*[@id="app-content"]/div/div[2]/div/div/div[2]/div[1]/div/div/div[1]/div[1]'), address: By.css('#app-content > div > div.app-primary.from-left > div > div > div:nth-child(1) > flex-column > div.flex-row > div'), tokens: { menu: By.id('wallet-view__tab-tokens'), diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index 3999ace07..cdce06ddd 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -62,7 +62,7 @@ describe('Metamask popup page', async function () { }) after(async function () { - await driver.quit() + // await driver.quit() }) describe('Setup', async function () { @@ -244,9 +244,252 @@ describe('Metamask popup page', async function () { }) }) + describe('Import Contract', async () => { + const poaContract = '0xc6468767214c577013a904900ada0a0dd6653bc3' + const wrongAddress = '0xB87b6077D59B01Ab9fa8cd5A1A21D02a4d60D35' + const notContractAddress = '0x56B2e3C3cFf7f3921Dc2e0F8B8e20d1eEc29216b' + + it('opens import account menu', async function () { + await setProvider(NETWORKS.ROPSTEN) + const menu = await waitUntilShowUp(menus.account.menu) + await menu.click() + const item = await waitUntilShowUp(menus.account.import) + await item.click() + const importAccountTitle = await waitUntilShowUp(screens.importAccounts.title) + assert.equal(await importAccountTitle.getText(), screens.importAccounts.textTitle) + }) + + it("Warning's text is correct", async function () { + const field = await waitUntilShowUp(screens.importAccounts.warning) + assert.equal(await field.getText(), 'Imported accounts will not be associated with your originally created Nifty Wallet account seedphrase.', "incorrect warning's text") + }) + + it("Select type 'Contract'", async function () { + const field = await waitUntilShowUp(screens.importAccounts.selectArrow) + await field.click() + const item = await waitUntilShowUp(screens.importAccounts.itemContract) + await item.click() + }) + + it("Field 'Address' is displayed", async function () { + await delay(2000) + const field = await waitUntilShowUp(screens.importAccounts.contractAddress) + assert.notEqual(field, false, "field 'Address' isn't displayed") + await field.sendKeys(wrongAddress) + }) + + it("Button 'Import' is displayed", async function () { + const button = await waitUntilShowUp(screens.importAccounts.buttonImport) + assert.notEqual(button, false, "button 'Import' isn't displayed") + await button.click() + }) + + it('Error message if incorrect address', async function () { + const field = await waitUntilShowUp(screens.importAccounts.error) + assert.notEqual(field, false, 'no error message') + assert.equal(await field.getText(), 'Invalid contract address', 'incorrect text') + }) + + it('No error if contract address is correct', async function () { + const field = await waitUntilShowUp(screens.importAccounts.contractAddress) + assert.notEqual(field, false, "field 'Address' isn't displayed") + await field.sendKeys(poaContract) + }) + + it("Click button 'Import' ", async function () { + const button = await waitUntilShowUp(screens.importAccounts.buttonImport) + await button.click() + assert.notEqual(button, false, "button 'Import' isn't displayed") + }) + + it("Field 'ABI' is displayed", async function () { + const field = await waitUntilShowUp(screens.importAccounts.contractABI) + assert.notEqual(field, false, "field 'ABI' isn't displayed") + }) + + it("Field 'ABI' is empty if contract isn't verified in current network", async function () { + const field = await waitUntilShowUp(screens.importAccounts.contractABI) + assert.equal(await field.getText(), '', "field 'ABI' isn't displayed") + }) + it("Fill 'Address' with not contract address , POA core", async function () { + await setProvider(NETWORKS.POA) + const field = await waitUntilShowUp(screens.importAccounts.contractAddress) + await clearField(field, 100) + await field.sendKeys(notContractAddress) + const button = await waitUntilShowUp(screens.importAccounts.buttonImport) + await button.click() + await waitUntilShowUp(elements.loader, 25) + await delay(2000) + await waitUntilDisappear(elements.loader, 25) + }) + + it.skip('Error message if not contract address', async function () { + const field = await waitUntilShowUp(screens.importAccounts.error) + assert.notEqual(field, false, 'no error message') + assert.equal(await field.getText(), 'This is not a contract address', 'incorrect text') + }) + + it("Fill 'Address' with valid contract , POA core", async function () { + const field = await waitUntilShowUp(screens.importAccounts.contractAddress) + await clearField(field, 100) + await field.sendKeys(poaContract) + const button = await waitUntilShowUp(screens.importAccounts.buttonImport) + await button.click() + }) + + it.skip('Correct ABI fetched ', async function () { + const field = await waitUntilShowUp(screens.importAccounts.contractABI) + assert.equal(await field.getText(), elements.poaABI, "ABI isn't fetched") + }) + + it("Click button 'Import', main screen opens", async function () { + const button = await waitUntilShowUp(screens.importAccounts.buttonImport) + await click(button) + const identicon = await waitUntilShowUp(screens.main.identicon) + assert.notEqual(identicon, false, "main screen isn't opened") + }) + + it("Click button 'Send', 'Execute Method' screen opens", async function () { + const button = await waitUntilShowUp(screens.main.buttons.send) + await click(button) + const identicon = await waitUntilShowUp(screens.main.identicon, 40) + assert.notEqual(identicon, false, "main screen isn't opened") + }) + }) + describe('Execute Method', () => { + const outputData = '0xd70befce3cf1cc88119c8f4eb583ccd4c39d06e2' + const notContractAddress = '0x56B2e3C3cFf7f3921Dc2e0F8B8e20d1eEc29216b' + it("Click button 'Send', 'Execute Method' screen opens", async function () { + await driver.navigate().refresh() + await delay(2000) + const button = await waitUntilShowUp(screens.main.buttons.send) + await click(button) + }) + + it('title is displayed and correct', async function () { + const title = await waitUntilShowUp(screens.executeMethod.title) + assert.notEqual(title, false, 'title isn\'t displayed') + assert.equal(await title.getText(), screens.executeMethod.titleText, 'incorrect text') + }) + + it("Select method 'abstractStorageAddr'", async function () { + const field = await waitUntilShowUp(screens.executeMethod.selectArrow) + await field.click() + const item = await waitUntilShowUp(screens.executeMethod.item0) + assert.notEqual(item, false, 'no drop down menu') + await click(item) + }) + + it("Button 'Call data' is displayed", async function () { + const button = await waitUntilShowUp(screens.executeMethod.buttonCall) + assert.notEqual(button, false, "button 'Call data' isn't displayed") + await button.click() + }) + + it('method returns correct value', async function () { + const field = await waitUntilShowUp(screens.executeMethod.fieldOutput) + assert.notEqual(field, false, "field 'Output' isn't displayed") + const text = await waitUntilHasText(field) + assert.equal(text, outputData, 'incorrect value was returned') + }) + + it("2nd call doesn't throw the error", async function () { + const button = await waitUntilShowUp(screens.executeMethod.buttonCall) + assert.notEqual(button, false, "button 'Call data' isn't displayed") + await button.click() + const field = await waitUntilShowUp(screens.executeMethod.fieldOutput) + assert.notEqual(field, false, "field 'Output' isn't displayed") + const text = await waitUntilHasText(field) + assert.equal(text, outputData, 'incorrect value was returned') + }) + it('Click arrow button leads to main screen', async function () { + const button = await waitUntilShowUp(screens.executeMethod.buttonArrow) + await click(button) + const identicon = await waitUntilShowUp(screens.main.identicon, 40) + assert.notEqual(identicon, false, "main screen isn't opened") + }) + it("Click button 'Send', 'Execute Method' screen opens", async function () { + await driver.navigate().refresh() + await delay(2000) + const button = await waitUntilShowUp(screens.main.buttons.send) + await click(button) + }) + it("Select method 'changeAbstractStorage'", async function () { + const field = await waitUntilShowUp(screens.executeMethod.selectArrow) + await field.click() + const items = await waitUntilShowUp(screens.executeMethod.item1) + assert.notEqual(items, false, 'no drop down menu') + const item = (await driver.findElements(screens.executeMethod.item1))[1] + // await click(item) + await item.click() + }) + + it("Fill out parameter '_newAbstractStorageAddr'", async function () { + const field = await waitUntilShowUp(screens.executeMethod.fieldParametr1) + await field.sendKeys(notContractAddress) + assert.notEqual(field, false, "field address isn't displayed") + }) + + it("Click button 'Next'", async function () { + const button = await waitUntilShowUp(screens.executeMethod.buttonNext) + assert.notEqual(button, false, "button 'Next' isn't displayed") + await button.click() + }) + + }) + describe('Choose Contract Executor', () => { + + it('title is displayed and correct', async function () { + const title = await waitUntilShowUp(screens.chooseContractExecutor.title) + assert.notEqual(title, false, 'title isn\'t displayed') + assert.equal(await title.getText(), screens.chooseContractExecutor.titleText, 'incorrect text') + }) + + it('two accounts displayed', async function () { + const accs = await waitUntilShowUp(screens.chooseContractExecutor.account) + assert.notEqual(accs, false, 'accounts aren\'t displayed') + const accounts = await driver.findElements(screens.chooseContractExecutor.account) + assert.equal(accounts.length, 3, "number of accounts isn't 2") + }) + it("Button 'Next' is disabled by default", async function () { + const button = await waitUntilShowUp(screens.chooseContractExecutor.buttonNext) + assert.notEqual(button, false, 'button isn\'t displayed') + assert.equal(await button.isEnabled(), false, 'button enabled by default') + }) + + it('User is able to select account', async function () { + await waitUntilShowUp(screens.chooseContractExecutor.account) + const accounts = await driver.findElements(screens.chooseContractExecutor.account) + const account = accounts[1] + await account.click() + const selected = await driver.findElements(screens.chooseContractExecutor.selectedAccount) + assert.equal(selected.length, 1, "account isn't selected") + }) + + it('User is able to select only one account', async function () { + const account = (await driver.findElements(screens.chooseContractExecutor.account))[2] + await account.click() + const selected = await driver.findElements(screens.chooseContractExecutor.selectedAccount) + assert.equal(selected.length, 1, 'more than one accounts are selected') + }) + + it("Click button 'Next' open 'Confirm transaction' screen", async function () { + const button = await waitUntilShowUp(screens.chooseContractExecutor.buttonNext) + await button.click() + await delay(5000) + const reject = await waitUntilShowUp(screens.confirmTransaction.button.reject) + assert.notEqual(reject, false, "button reject isn't displayed") + await click(reject) + const identicon = await waitUntilShowUp(screens.main.identicon) + assert.notEqual(identicon, false, 'main screen didn\'t opened') + }) + }) + + describe('Sign Data', () => { it('simulate sign request ', async function () { + await setProvider(NETWORKS.LOCALHOST) await driver.get('https://danfinlay.github.io/js-eth-personal-sign-examples/') const button = await waitUntilShowUp(By.id('ethSignButton')) await button.click() @@ -322,9 +565,9 @@ describe('Metamask popup page', async function () { assert.equal(await button.getText(), 'Import', 'button has incorrect name') const menu = await waitUntilShowUp(menus.account.menu) await menu.click() - const importedLabel = await waitUntilShowUp(menus.account.labelImported) - assert.equal(await importedLabel.getText(), 'IMPORTED') - + await waitUntilShowUp(menus.account.labelImported) + const label = (await driver.findElements(menus.account.labelImported))[1] + assert.equal(await label.getText(), 'IMPORTED') await menu.click() }) @@ -461,6 +704,7 @@ describe('Metamask popup page', async function () { await driver.navigate().refresh() }) }) + describe('Import Ganache seed phrase', function () { it('logs out', async function () { @@ -590,7 +834,7 @@ describe('Metamask popup page', async function () { describe('Add Token: Custom', function () { - describe('Add token to LOCALHOST', function () { + describe('Add token to LOCALHOST', function () { it('Create custom token in LOCALHOST', async function () { await setProvider(NETWORKS.LOCALHOST) @@ -1762,6 +2006,17 @@ describe('Metamask popup page', async function () { return false } + async function waitUntilHasText (element, Twait) { + if (Twait === undefined) Twait = 200 + let text + do { + await delay(100) + text = await element.getText() + if (text !== '') return text + } while (Twait-- > 0) + return false + } + async function isElementDisplayed (by) { try { return await driver.findElement(by).isDisplayed() @@ -2226,3 +2481,4 @@ describe('Metamask popup page', async function () { } }) +