aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/base.conf.js3
-rw-r--r--test/e2e/metamask.spec.js34
-rw-r--r--test/integration/lib/add-token.js71
-rw-r--r--test/screens/new-ui.js225
4 files changed, 207 insertions, 126 deletions
diff --git a/test/base.conf.js b/test/base.conf.js
index e2e9d44ba..956dce011 100644
--- a/test/base.conf.js
+++ b/test/base.conf.js
@@ -6,6 +6,9 @@ module.exports = function(config) {
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: process.cwd(),
+ // Uncomment to allow for longer timeouts
+ // browserNoActivityTimeout: 100000000,
+
browserConsoleLogOptions: {
terminal: false,
},
diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js
index 707ca2560..8ec7de16c 100644
--- a/test/e2e/metamask.spec.js
+++ b/test/e2e/metamask.spec.js
@@ -30,6 +30,18 @@ describe('Metamask popup page', function () {
})
afterEach(async function () {
+ // logs command not supported in firefox
+ // https://github.com/SeleniumHQ/selenium/issues/2910
+ if (process.env.SELENIUM_BROWSER === 'chrome') {
+ // check for console errors
+ const errors = await checkBrowserForConsoleErrors()
+ if (errors.length) {
+ const errorReports = errors.map(err => err.message)
+ const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}`
+ this.test.error(new Error(errorMessage))
+ }
+ }
+ // gather extra data if test failed
if (this.currentTest.state === 'failed') {
await verboseReportOnFailure(this.currentTest)
}
@@ -300,13 +312,33 @@ describe('Metamask popup page', function () {
await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
}
+ async function checkBrowserForConsoleErrors() {
+ const ignoredLogTypes = ['WARNING']
+ const ignoredErrorMessages = [
+ // React throws error warnings on "dataset", but still sets the data-* properties correctly
+ 'Warning: Unknown prop `dataset` on ',
+ // Third-party Favicon 404s show up as errors
+ 'favicon.ico - Failed to load resource: the server responded with a status of 404 (Not Found)',
+ // React Development build - known issue blocked by test build sys
+ 'Warning: It looks like you\'re using a minified copy of the development build of React.',
+ // Redux Development build - known issue blocked by test build sys
+ 'This means that you are running a slower development build of Redux.',
+ ]
+ const browserLogs = await driver.manage().logs().get('browser')
+ const errorEntries = browserLogs.filter(entry => !ignoredLogTypes.includes(entry.level.toString()))
+ const errorObjects = errorEntries.map(entry => entry.toJSON())
+ // ignore all errors that contain a message in `ignoredErrorMessages`
+ const matchedErrorObjects = errorObjects.filter(entry => !ignoredErrorMessages.some(message => entry.message.includes(message)))
+ return matchedErrorObjects
+ }
+
async function verboseReportOnFailure (test) {
let artifactDir
if (process.env.SELENIUM_BROWSER === 'chrome') {
artifactDir = `./test-artifacts/chrome/${test.title}`
} else if (process.env.SELENIUM_BROWSER === 'firefox') {
artifactDir = `./test-artifacts/firefox/${test.title}`
- }
+ }
const filepathBase = `${artifactDir}/test-failure`
await pify(mkdirp)(artifactDir)
// capture screenshot
diff --git a/test/integration/lib/add-token.js b/test/integration/lib/add-token.js
index 1840bdd39..e51c854d2 100644
--- a/test/integration/lib/add-token.js
+++ b/test/integration/lib/add-token.js
@@ -22,6 +22,11 @@ async function runAddTokenFlowTest (assert, done) {
selectState.val('add token')
reactTriggerChange(selectState[0])
+ // Used to set values on TextField input component
+ const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
+ window.HTMLInputElement.prototype, 'value'
+ ).set
+
// Check that no tokens have been added
assert.ok($('.token-list-item').length === 0, 'no tokens added')
@@ -31,14 +36,14 @@ async function runAddTokenFlowTest (assert, done) {
addTokenButton[0].click()
// Verify Add Token screen
- let addTokenWrapper = await queryAsync($, '.add-token__wrapper')
+ let addTokenWrapper = await queryAsync($, '.page-container')
assert.ok(addTokenWrapper[0], 'add token wrapper renders')
- let addTokenTitle = await queryAsync($, '.add-token__header__title')
+ let addTokenTitle = await queryAsync($, '.page-container__title')
assert.equal(addTokenTitle[0].textContent, 'Add Tokens', 'add token title is correct')
// Cancel Add Token
- const cancelAddTokenButton = await queryAsync($, 'button.btn-secondary--lg.add-token__cancel-button')
+ const cancelAddTokenButton = await queryAsync($, 'button.btn-secondary--lg.page-container__footer-button')
assert.ok(cancelAddTokenButton[0], 'cancel add token button present')
cancelAddTokenButton.click()
@@ -50,20 +55,22 @@ async function runAddTokenFlowTest (assert, done) {
addTokenButton[0].click()
// Verify Add Token Screen
- addTokenWrapper = await queryAsync($, '.add-token__wrapper')
- addTokenTitle = await queryAsync($, '.add-token__header__title')
+ addTokenWrapper = await queryAsync($, '.page-container')
+ addTokenTitle = await queryAsync($, '.page-container__title')
assert.ok(addTokenWrapper[0], 'add token wrapper renders')
assert.equal(addTokenTitle[0].textContent, 'Add Tokens', 'add token title is correct')
// Search for token
- const searchInput = await queryAsync($, 'input.add-token__input')
- searchInput.val('a')
- reactTriggerChange(searchInput[0])
+ const searchInput = (await findAsync(addTokenWrapper, '#search-tokens'))[0]
+ searchInput.focus()
+ await timeout(1000)
+ nativeInputValueSetter.call(searchInput, 'a')
+ searchInput.dispatchEvent(new Event('input', { bubbles: true}))
// Click token to add
- const tokenWrapper = await queryAsync($, 'div.add-token__token-wrapper')
+ const tokenWrapper = await queryAsync($, 'div.token-list__token')
assert.ok(tokenWrapper[0], 'token found')
- const tokenImageProp = tokenWrapper.find('.add-token__token-icon').css('background-image')
+ const tokenImageProp = tokenWrapper.find('.token-list__token-icon').css('background-image')
const tokenImageUrl = tokenImageProp.slice(5, -2)
tokenWrapper[0].click()
@@ -73,11 +80,8 @@ async function runAddTokenFlowTest (assert, done) {
nextButton[0].click()
// Confirm Add token
- assert.equal(
- $('.add-token__description')[0].textContent,
- 'Token balance(s)',
- 'confirm add token rendered'
- )
+ const confirmAddToken = await queryAsync($, '.confirm-add-token')
+ assert.ok(confirmAddToken[0], 'confirm add token rendered')
assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found')
$('button.btn-primary--lg')[0].click()
@@ -91,39 +95,46 @@ async function runAddTokenFlowTest (assert, done) {
assert.ok(addTokenButton[0], 'add token button present')
addTokenButton[0].click()
- const addTokenTabs = await queryAsync($, '.add-token__header__tabs__tab')
+ addTokenWrapper = await queryAsync($, '.page-container')
+ const addTokenTabs = await queryAsync($, '.page-container__tab')
assert.equal(addTokenTabs.length, 2, 'expected number of tabs')
assert.equal(addTokenTabs[1].textContent, 'Custom Token', 'Custom Token tab present')
assert.ok(addTokenTabs[1], 'add custom token tab present')
addTokenTabs[1].click()
+ await timeout(1000)
// Input token contract address
- const customInput = await queryAsync($, 'input.add-token__add-custom-input')
- customInput.val('0x177af043D3A1Aed7cc5f2397C70248Fc6cDC056c')
- reactTriggerChange(customInput[0])
+ const customInput = (await findAsync(addTokenWrapper, '#custom-address'))[0]
+ customInput.focus()
+ await timeout(1000)
+ nativeInputValueSetter.call(customInput, '0x177af043D3A1Aed7cc5f2397C70248Fc6cDC056c')
+ customInput.dispatchEvent(new Event('input', { bubbles: true}))
+
// Click Next button
- nextButton = await queryAsync($, 'button.btn-primary--lg')
- assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
- nextButton[0].click()
+ // nextButton = await queryAsync($, 'button.btn-primary--lg')
+ // assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
+ // nextButton[0].click()
- // Verify symbol length error since contract address won't return symbol
- const errorMessage = await queryAsync($, '.add-token__add-custom-error-message')
+ // // Verify symbol length error since contract address won't return symbol
+ const errorMessage = await queryAsync($, '#custom-symbol-helper-text')
assert.ok(errorMessage[0], 'error rendered')
$('button.btn-secondary--lg')[0].click()
- // // Confirm Add token
+ // await timeout(100000)
+
+ // Confirm Add token
// assert.equal(
- // $('.add-token__description')[0].textContent,
+ // $('.page-container__subtitle')[0].textContent,
// 'Would you like to add these tokens?',
// 'confirm add token rendered'
// )
// assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found')
// $('button.btn-primary--lg')[0].click()
- // // Verify added token image
- // heroBalance = await queryAsync($, '.hero-balance')
- // assert.ok(heroBalance, 'rendered hero balance')
- // assert.ok(heroBalance.find('.identicon')[0], 'token added')
+ // Verify added token image
+ heroBalance = await queryAsync($, '.hero-balance')
+ assert.ok(heroBalance, 'rendered hero balance')
+ assert.ok(heroBalance.find('.identicon')[0], 'token added')
}
diff --git a/test/screens/new-ui.js b/test/screens/new-ui.js
index 6a8822eb3..6b873ac85 100644
--- a/test/screens/new-ui.js
+++ b/test/screens/new-ui.js
@@ -5,29 +5,44 @@ const mkdirp = require('mkdirp')
const rimraf = require('rimraf')
const webdriver = require('selenium-webdriver')
const endOfStream = require('end-of-stream')
+const clipboardy = require('clipboardy')
+const Ethjs = require('ethjs')
const GIFEncoder = require('gifencoder')
const pngFileStream = require('png-file-stream')
const sizeOfPng = require('image-size/lib/types/png')
const By = webdriver.By
const { delay, buildWebDriver } = require('./func')
const localesIndex = require('../../app/_locales/index.json')
+// const localesIndex = []
+
+const eth = new Ethjs(new Ethjs.HttpProvider('http://localhost:8545'))
let driver
+let screenshotCount = 0
+
+captureAllScreens()
+.then(async () => {
+ // build screenshots into gif
+ console.log('building gif...')
+ await generateGif()
-captureAllScreens().catch((err) => {
+ await driver.quit()
+ process.exit()
+})
+.catch(async (err) => {
try {
console.error(err)
- verboseReportOnFailure()
- driver.quit()
+ verboseReportOnFailure({ title: 'something broke' })
} catch (err) {
console.error(err)
}
+
+ await driver.quit()
process.exit(1)
})
-async function captureAllScreens() {
- let screenshotCount = 0
+async function captureAllScreens() {
// common names
let button
let tabs
@@ -74,10 +89,11 @@ async function captureAllScreens() {
await driver.findElement(By.css('button')).click()
await captureLanguageScreenShots('create password')
+ const password = '123456789'
const passwordBox = await driver.findElement(By.css('input#create-password'))
const passwordBoxConfirm = await driver.findElement(By.css('input#confirm-password'))
- passwordBox.sendKeys('123456789')
- passwordBoxConfirm.sendKeys('123456789')
+ passwordBox.sendKeys(password)
+ passwordBoxConfirm.sendKeys(password)
await delay(500)
await captureLanguageScreenShots('choose-password-filled')
@@ -111,109 +127,123 @@ async function captureAllScreens() {
await delay(300)
await captureLanguageScreenShots('secret backup phrase - reveal')
+ const seedPhrase = await driver.findElement(By.css('.backup-phrase__secret-words')).getText()
+ const seedPhraseWords = seedPhrase.split(' ')
await driver.findElement(By.css('button')).click()
await delay(300)
await captureLanguageScreenShots('confirm secret backup phrase')
- // finish up
- console.log('building gif...')
- await generateGif()
- await driver.quit()
- return
-
- //
- // await button.click()
- // await delay(700)
- // this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText()
- // await captureScreenShot('seed phrase')
- //
- // const continueAfterSeedPhrase = await driver.findElement(By.css('button'))
- // await continueAfterSeedPhrase.click()
- // await delay(300)
- // await captureScreenShot('main screen')
- //
- // await driver.findElement(By.css('.sandwich-expando')).click()
- // await delay(500)
- // await captureScreenShot('menu')
-
- // await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click()
- // await captureScreenShot('main screen')
- // it('should accept account password after lock', async () => {
- // await delay(500)
- // await driver.findElement(By.id('password-box')).sendKeys('123456789')
- // await driver.findElement(By.css('button')).click()
- // await delay(500)
- // })
- //
- // it('should show QR code option', async () => {
- // await delay(300)
- // await driver.findElement(By.css('.fa-ellipsis-h')).click()
- // await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(1) > flex-column > div.name-label > div > span > i > div > div > li:nth-child(3)')).click()
- // await delay(300)
- // })
- //
- // it('should show the account address', async () => {
- // this.accountAddress = await driver.findElement(By.css('.ellip-address')).getText()
- // await driver.findElement(By.css('.fa-arrow-left')).click()
- // await delay(500)
- // })
-
- async function captureLanguageScreenShots(label) {
- const nonEnglishLocales = localesIndex.filter(localeMeta => localeMeta.code !== 'en')
- // take english shot
- await captureScreenShot(`${label} (en)`)
- for (let localeMeta of nonEnglishLocales) {
- // set locale and take shot
- await setLocale(localeMeta.code)
- await delay(300)
- await captureScreenShot(`${label} (${localeMeta.code})`)
- }
- // return locale to english
- await setLocale('en')
- await delay(300)
+ // 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) {
+ 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 delay(100)
}
+ await captureLanguageScreenShots('confirm secret backup phrase - words selected correctly')
- async function setLocale(code) {
- await driver.executeScript('window.metamask.updateCurrentLocale(arguments[0])', code)
- }
+ await driver.findElement(By.css('.backup-phrase__content-wrapper .first-time-flow__button')).click()
+ await delay(300)
+ await captureLanguageScreenShots('metamask post-initialize greeter screen deposit ether')
- async function setProviderType(type) {
- await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
- }
+ await driver.findElement(By.css('.page-container__header-close')).click()
+ await delay(300)
+ await captureLanguageScreenShots('metamask account main screen')
- // cleanup
- await driver.quit()
+ // account details + export private key
+ await driver.findElement(By.css('.wallet-view__name-container > .wallet-view__details-button')).click()
+ await delay(300)
+ await captureLanguageScreenShots('metamask account detail screen')
- async function cleanScreenShotDir() {
- await pify(rimraf)(`./test-artifacts/screens/`)
- }
+ await driver.findElement(By.css('.account-modal__button:nth-of-type(2)')).click()
+ await delay(300)
+ await captureLanguageScreenShots('metamask account detail export private key screen - initial')
- async function captureScreenShot(label) {
- const shotIndex = screenshotCount.toString().padStart(4, '0')
- screenshotCount++
- const artifactDir = `./test-artifacts/screens/`
- await pify(mkdirp)(artifactDir)
- // capture screenshot
- const screenshot = await driver.takeScreenshot()
- await pify(fs.writeFile)(`${artifactDir}/${shotIndex} - ${label}.png`, screenshot, { encoding: 'base64' })
- }
+ await driver.findElement(By.css('.private-key-password > input')).sendKeys(password)
+ await delay(300)
+ await captureLanguageScreenShots('metamask account detail export private key screen - password entered')
- async function generateGif(){
- // calculate screenshot size
- const screenshot = await driver.takeScreenshot()
- const pngBuffer = Buffer.from(screenshot, 'base64')
- const size = sizeOfPng.calculate(pngBuffer)
+ await driver.findElement(By.css('.btn-primary--lg.export-private-key__button')).click()
+ await delay(300)
+ await captureLanguageScreenShots('metamask account detail export private key screen - reveal key')
- // read only the english pngs into gif
- const encoder = new GIFEncoder(size.width, size.height)
- const stream = pngFileStream('./test-artifacts/screens/* (en).png')
- .pipe(encoder.createWriteStream({ repeat: 0, delay: 1000, quality: 10 }))
- .pipe(fs.createWriteStream('./test-artifacts/screens/walkthrough (en).gif'))
+ await driver.findElement(By.css('.export-private-key__button')).click()
+ await delay(300)
+ await captureLanguageScreenShots('metamask account detail export private key screen - done')
- // wait for end
- await pify(endOfStream)(stream)
+ // get eth from Ganache
+ // const viewAddressButton = await driver.findElement(By.css('.wallet-view__address'))
+ // await driver.actions({ bridge: true }).move({ origin: viewAddressButton }).perform()
+ // console.log('driver.actions', driver.actions({ bridge: true }))
+ // await delay(300)
+ // await captureLanguageScreenShots('metamask home - hover copy address')
+
+ await driver.findElement(By.css('.wallet-view__address')).click()
+ await delay(100)
+ await captureLanguageScreenShots('metamask home - hover copy address')
+
+ const primaryAddress = clipboardy.readSync()
+ await requestEther(primaryAddress)
+ // wait for block polling
+ await delay(10000)
+ await captureLanguageScreenShots('metamask home - has ether')
+
+}
+
+
+async function captureLanguageScreenShots(label) {
+ const nonEnglishLocales = localesIndex.filter(localeMeta => localeMeta.code !== 'en')
+ // take english shot
+ await captureScreenShot(`${label} (en)`)
+ for (let localeMeta of nonEnglishLocales) {
+ // set locale and take shot
+ await setLocale(localeMeta.code)
+ await delay(300)
+ await captureScreenShot(`${label} (${localeMeta.code})`)
}
+ // return locale to english
+ await setLocale('en')
+ await delay(300)
+}
+
+async function setLocale(code) {
+ await driver.executeScript('window.metamask.updateCurrentLocale(arguments[0])', code)
+}
+
+async function setProviderType(type) {
+ await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
+}
+async function cleanScreenShotDir() {
+ await pify(rimraf)(`./test-artifacts/screens/`)
+}
+
+async function captureScreenShot(label) {
+ const shotIndex = screenshotCount.toString().padStart(4, '0')
+ screenshotCount++
+ const artifactDir = `./test-artifacts/screens/`
+ await pify(mkdirp)(artifactDir)
+ // capture screenshot
+ const screenshot = await driver.takeScreenshot()
+ await pify(fs.writeFile)(`${artifactDir}/${shotIndex} - ${label}.png`, screenshot, { encoding: 'base64' })
+}
+
+async function generateGif(){
+ // calculate screenshot size
+ const screenshot = await driver.takeScreenshot()
+ const pngBuffer = Buffer.from(screenshot, 'base64')
+ const size = sizeOfPng.calculate(pngBuffer)
+
+ // read only the english pngs into gif
+ const encoder = new GIFEncoder(size.width, size.height)
+ const stream = pngFileStream('./test-artifacts/screens/* (en).png')
+ .pipe(encoder.createWriteStream({ repeat: 0, delay: 1000, quality: 10 }))
+ .pipe(fs.createWriteStream('./test-artifacts/screens/walkthrough (en).gif'))
+
+ // wait for end
+ await pify(endOfStream)(stream)
}
async function verboseReportOnFailure(test) {
@@ -227,3 +257,8 @@ async function verboseReportOnFailure(test) {
const htmlSource = await driver.getPageSource()
await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource)
}
+
+async function requestEther(address) {
+ const accounts = await eth.accounts()
+ await eth.sendTransaction({ from: accounts[0], to: address, value: 1 * 1e18, data: '0x0' })
+}