diff --git a/test/e2e/fixtures/onboarding/state.json b/test/e2e/fixtures/onboarding/state.json new file mode 100644 index 000000000..b0fbccd9a --- /dev/null +++ b/test/e2e/fixtures/onboarding/state.json @@ -0,0 +1,40 @@ +{ + "data": { + "config": {}, + "PreferencesController": { + "frequentRpcListDetail": [ + { + "rpcUrl": "http://localhost:8545", + "chainId": "0x539", + "ticker": "ETH", + "nickname": "Localhost 8545", + "rpcPrefs": {} + } + ] + }, + "firstTimeInfo": { + "version": "9.3.0", + "date": 1617927806790 + }, + "NetworkController": { + "provider": { + "ticker": "ETH", + "type": "rpc", + "rpcUrl": "http://localhost:8545", + "chainId": "0x539", + "nickname": "Localhost 8545" + }, + "network": "1337" + }, + "CurrencyController": { + "conversionDate": 1617927806.941, + "conversionRate": 2084.64, + "currentCurrency": "usd", + "nativeCurrency": "ETH", + "usdConversionRate": 2084.64 + } + }, + "meta": { + "version": 57 + } +} diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 5daadbb0d..c8d1d7a59 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -22,6 +22,7 @@ async function withFixtures(options, testSuite) { driverOptions, mockSegment, title, + failOnConsoleError = true, } = options; const fixtureServer = new FixtureServer(); const ganacheServer = new Ganache(); @@ -77,7 +78,11 @@ async function withFixtures(options, testSuite) { const errorMessage = `Errors found in browser console:\n${errorReports.join( '\n', )}`; - throw new Error(errorMessage); + if (failOnConsoleError) { + throw new Error(errorMessage); + } else { + console.error(new Error(errorMessage)); + } } } } catch (error) { diff --git a/test/e2e/metamask-responsive-ui.spec.js b/test/e2e/metamask-responsive-ui.spec.js deleted file mode 100644 index c61176671..000000000 --- a/test/e2e/metamask-responsive-ui.spec.js +++ /dev/null @@ -1,267 +0,0 @@ -const assert = require('assert'); - -const enLocaleMessages = require('../../app/_locales/en/messages.json'); -const { tinyDelayMs, regularDelayMs, largeDelayMs } = require('./helpers'); -const { buildWebDriver } = require('./webdriver'); -const Ganache = require('./ganache'); - -const ganacheServer = new Ganache(); - -describe('MetaMask', function () { - let driver; - - const testSeedPhrase = - 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'; - - this.timeout(0); - this.bail(true); - - before(async function () { - await ganacheServer.start(); - const result = await buildWebDriver({ responsive: true }); - driver = result.driver; - await driver.navigate(); - }); - - afterEach(async function () { - if (process.env.SELENIUM_BROWSER === 'chrome') { - const errors = await driver.checkBrowserForConsoleErrors(driver); - if (errors.length) { - const errorReports = errors.map((err) => err.message); - const errorMessage = `Errors found in browser console:\n${errorReports.join( - '\n', - )}`; - console.error(new Error(errorMessage)); - } - } - if (this.currentTest.state === 'failed') { - await driver.verboseReportOnFailure(this.currentTest.title); - } - }); - - after(async function () { - await ganacheServer.quit(); - await driver.quit(); - }); - - describe('Going through the first time flow', function () { - it('clicks the continue button on the welcome screen', async function () { - await driver.findElement('.welcome-page__header'); - await driver.clickElement({ - text: enLocaleMessages.getStarted.message, - tag: 'button', - }); - await driver.delay(largeDelayMs); - }); - - it('clicks the "Create New Wallet" option', async function () { - await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); - await driver.delay(largeDelayMs); - }); - - it('clicks the "I Agree" option on the metametrics opt-in screen', async function () { - await driver.clickElement('.btn-primary'); - await driver.delay(largeDelayMs); - }); - - it('accepts a secure password', async function () { - await driver.fill( - '.first-time-flow__form #create-password', - 'correct horse battery staple', - ); - await driver.fill( - '.first-time-flow__form #confirm-password', - 'correct horse battery staple', - ); - - await driver.clickElement('.first-time-flow__checkbox'); - - await driver.clickElement('.first-time-flow__form button'); - await driver.delay(regularDelayMs); - }); - - it('renders the seed phrase intro screen', async function () { - await driver.clickElement('.seed-phrase-intro__left button'); - await driver.delay(regularDelayMs); - }); - - let seedPhrase; - - it('reveals the seed phrase', async function () { - await driver.clickElement( - '.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button', - ); - await driver.delay(regularDelayMs); - - const revealedSeedPhrase = await driver.findElement( - '.reveal-seed-phrase__secret-words', - ); - seedPhrase = await revealedSeedPhrase.getText(); - assert.equal(seedPhrase.split(' ').length, 12); - await driver.delay(regularDelayMs); - - await driver.clickElement({ - text: enLocaleMessages.next.message, - tag: 'button', - }); - await driver.delay(regularDelayMs); - }); - - async function clickWordAndWait(word) { - await driver.clickElement( - `[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`, - ); - await driver.delay(tinyDelayMs); - } - - it('can retype the seed phrase', async function () { - const words = seedPhrase.split(' '); - - for (const word of words) { - await clickWordAndWait(word); - } - - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - await driver.delay(regularDelayMs); - }); - - it('clicks through the success screen', async function () { - await driver.findElement({ text: 'Congratulations', tag: 'div' }); - await driver.clickElement({ - text: enLocaleMessages.endOfFlowMessage10.message, - tag: 'button', - }); - await driver.delay(regularDelayMs); - }); - }); - - describe('Show account information', function () { - it('show account details dropdown menu', async function () { - await driver.clickElement('[data-testid="account-options-menu-button"]'); - const options = await driver.findElements( - '.account-options-menu .menu-item', - ); - assert.equal(options.length, 3); // HD Wallet type does not have to show the Remove Account option - // click outside of menu to dismiss - // account menu button chosen because the menu never covers it. - await driver.clickPoint('.account-menu__icon', 0, 0); - await driver.delay(regularDelayMs); - }); - }); - - describe('Import seed phrase', function () { - it('logs out of the vault', async function () { - await driver.clickElement('.account-menu__icon'); - await driver.delay(regularDelayMs); - - const lockButton = await driver.findClickableElement( - '.account-menu__lock-button', - ); - assert.equal(await lockButton.getText(), 'Lock'); - await lockButton.click(); - await driver.delay(regularDelayMs); - }); - - it('imports seed phrase', async function () { - const restoreSeedLink = await driver.findClickableElement( - '.unlock-page__link--import', - ); - assert.equal( - await restoreSeedLink.getText(), - 'Import using account seed phrase', - ); - await restoreSeedLink.click(); - await driver.delay(regularDelayMs); - - await driver.clickElement('.import-account__checkbox-container'); - - await driver.fill('.import-account__secret-phrase', testSeedPhrase); - await driver.delay(regularDelayMs); - - await driver.fill('#password', 'correct horse battery staple'); - await driver.fill('#confirm-password', 'correct horse battery staple'); - await driver.clickElement({ - text: enLocaleMessages.restore.message, - tag: 'button', - }); - await driver.delay(regularDelayMs); - }); - - it('switches to localhost', async function () { - await driver.clickElement('.network-display'); - await driver.delay(regularDelayMs); - - await driver.clickElement({ - xpath: `//span[contains(@class, 'network-name-item') and contains(text(), 'Localhost 8545')]`, - }); - await driver.delay(largeDelayMs * 2); - }); - - it('balance renders', async function () { - await driver.waitForSelector({ - css: '[data-testid="eth-overview__primary-currency"]', - text: '100 ETH', - }); - await driver.delay(regularDelayMs); - }); - }); - - describe('Send ETH from inside MetaMask', function () { - it('starts to send a transaction', async function () { - await driver.clickElement('[data-testid="eth-overview-send"]'); - await driver.delay(regularDelayMs); - - await driver.fill( - 'input[placeholder="Search, public address (0x), or ENS"]', - '0x2f318C334780961FB129D2a6c30D0763d9a5C970', - ); - - const inputAmount = await driver.fill('.unit-input__input', '1'); - - const inputValue = await inputAmount.getAttribute('value'); - assert.equal(inputValue, '1'); - await driver.delay(regularDelayMs); - }); - - it('opens and closes the gas modal', async function () { - // Set the gas limit - await driver.clickElement('.advanced-gas-options-btn'); - await driver.delay(regularDelayMs); - - // wait for gas modal to be visible - const gasModal = await driver.findVisibleElement('span .modal'); - await driver.clickElement('.page-container__header-close-text'); - // wait for gas modal to be removed from dom - await gasModal.waitForElementState('hidden'); - await driver.delay(regularDelayMs); - }); - - it('clicks through to the confirm screen', async function () { - // Continue to next screen - await driver.clickElement({ text: 'Next', tag: 'button' }); - await driver.delay(regularDelayMs); - }); - - it('confirms the transaction', async function () { - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - }); - - it('finds the transaction in the transactions list', async function () { - await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.wait(async () => { - const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', - ); - return confirmedTxes.length === 1; - }, 10000); - - await driver.waitForSelector( - { - css: '.transaction-list-item__primary-currency', - text: '-1 ETH', - }, - { timeout: 10000 }, - ); - }); - }); -}); diff --git a/test/e2e/run-all.sh b/test/e2e/run-all.sh index 7879ddc4e..b0b0ca486 100755 --- a/test/e2e/run-all.sh +++ b/test/e2e/run-all.sh @@ -35,13 +35,6 @@ retry concurrently --kill-others \ 'yarn dapp' \ 'mocha test/e2e/metamask-ui.spec' -retry concurrently --kill-others \ - --names 'dapp,e2e' \ - --prefix '[{time}][{name}]' \ - --success first \ - 'yarn dapp' \ - 'mocha test/e2e/metamask-responsive-ui.spec' - retry concurrently --kill-others \ --names 'e2e' \ --prefix '[{time}][{name}]' \ @@ -54,4 +47,3 @@ retry concurrently --kill-others \ --success first \ 'yarn sendwithprivatedapp' \ 'mocha test/e2e/incremental-security.spec' - diff --git a/test/e2e/tests/metamask-responsive-ui.spec.js b/test/e2e/tests/metamask-responsive-ui.spec.js new file mode 100644 index 000000000..1e3c3e7ee --- /dev/null +++ b/test/e2e/tests/metamask-responsive-ui.spec.js @@ -0,0 +1,207 @@ +const { strict: assert } = require('assert'); +const { withFixtures, tinyDelayMs } = require('../helpers'); +const enLocaleMessages = require('../../../app/_locales/en/messages.json'); + +describe('Metamask Responsive UI', function () { + it('Creating a new wallet', async function () { + const driverOptions = { responsive: true }; + + await withFixtures( + { + fixtures: 'onboarding', + driverOptions, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + + // clicks the continue button on the welcome screen + await driver.findElement('.welcome-page__header'); + await driver.clickElement({ + text: enLocaleMessages.getStarted.message, + tag: 'button', + }); + await driver.delay(tinyDelayMs); + + // clicks the "Create New Wallet" option + await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); + + // clicks the "I Agree" option on the metametrics opt-in screen + await driver.clickElement('.btn-primary'); + + // accepts a secure password + await driver.fill( + '.first-time-flow__form #create-password', + 'correct horse battery staple', + ); + await driver.fill( + '.first-time-flow__form #confirm-password', + 'correct horse battery staple', + ); + await driver.clickElement('.first-time-flow__checkbox'); + await driver.clickElement('.first-time-flow__form button'); + + // renders the seed phrase intro screen + await driver.clickElement('.seed-phrase-intro__left button'); + + // reveals the seed phrase + await driver.clickElement( + '.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button', + ); + const revealedSeedPhrase = await driver.findElement( + '.reveal-seed-phrase__secret-words', + ); + const seedPhrase = await revealedSeedPhrase.getText(); + assert.equal(seedPhrase.split(' ').length, 12); + + await driver.clickElement({ + text: enLocaleMessages.next.message, + tag: 'button', + }); + + async function clickWordAndWait(word) { + await driver.clickElement( + `[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`, + ); + await driver.delay(tinyDelayMs); + } + + // can retype the seed phrase + const words = seedPhrase.split(' '); + for (const word of words) { + await clickWordAndWait(word); + } + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + + // clicks through the success screen + await driver.findElement({ text: 'Congratulations', tag: 'div' }); + await driver.clickElement({ + text: enLocaleMessages.endOfFlowMessage10.message, + tag: 'button', + }); + + // Show account information + // balance renders + await driver.waitForSelector({ + css: '[data-testid="eth-overview__primary-currency"]', + text: '0 ETH', + }); + }, + ); + }); + + it('Importing existing wallet from lock page', async function () { + const driverOptions = { responsive: true }; + const testSeedPhrase = + 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'; + + await withFixtures( + { + fixtures: 'imported-account', + driverOptions, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + + // Import seed phrase + const restoreSeedLink = await driver.findClickableElement( + '.unlock-page__link--import', + ); + assert.equal( + await restoreSeedLink.getText(), + 'Import using account seed phrase', + ); + await restoreSeedLink.click(); + + await driver.clickElement('.import-account__checkbox-container'); + + await driver.fill('.import-account__secret-phrase', testSeedPhrase); + + await driver.fill('#password', 'correct horse battery staple'); + await driver.fill('#confirm-password', 'correct horse battery staple'); + await driver.clickElement({ + text: enLocaleMessages.restore.message, + tag: 'button', + }); + + // balance renders + await driver.waitForSelector({ + css: '[data-testid="eth-overview__primary-currency"]', + text: '100 ETH', + }); + }, + ); + }); + + it('Send Transaction from responsive window', async function () { + const driverOptions = { responsive: true }; + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: 25000000000000000000, + }, + ], + }; + await withFixtures( + { + fixtures: 'imported-account', + driverOptions, + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // Send ETH from inside MetaMask + // starts to send a transaction + await driver.clickElement('[data-testid="eth-overview-send"]'); + + await driver.fill( + 'input[placeholder="Search, public address (0x), or ENS"]', + '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + ); + + const inputAmount = await driver.fill('.unit-input__input', '1'); + + const inputValue = await inputAmount.getAttribute('value'); + assert.equal(inputValue, '1'); + + // opens and closes the gas modal + await driver.clickElement('.advanced-gas-options-btn'); + // wait for gas modal to be visible + const gasModal = await driver.findVisibleElement('span .modal'); + await driver.clickElement('.page-container__header-close-text'); + // wait for gas modal to be removed from dom + await gasModal.waitForElementState('hidden'); + + // confirming transcation + await driver.clickElement({ text: 'Next', tag: 'button' }); + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + + // finds the transaction in the transactions list + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.wait(async () => { + const confirmedTxes = await driver.findElements( + '.transaction-list__completed-transactions .transaction-list-item', + ); + return confirmedTxes.length === 1; + }, 10000); + + await driver.waitForSelector( + { + css: '.transaction-list-item__primary-currency', + text: '-1 ETH', + }, + { timeout: 10000 }, + ); + }, + ); + }); +});