aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/e2e/chrome/metamask.spec.js314
-rw-r--r--test/e2e/func.js42
-rw-r--r--test/e2e/metamask.spec.js (renamed from test/e2e/firefox/metamask.spec.js)89
-rw-r--r--test/screens/new-ui.js225
-rw-r--r--test/unit/actions/save_account_label_test.js35
-rw-r--r--test/unit/actions/set_account_label_test.js34
-rw-r--r--test/unit/address-book-controller.js26
-rw-r--r--test/unit/metamask-controller-test.js2
-rw-r--r--test/unit/migrations/026-test.js41
-rw-r--r--test/unit/preferences-controller-test.js116
-rw-r--r--test/unit/tx-controller-test.js30
11 files changed, 415 insertions, 539 deletions
diff --git a/test/e2e/chrome/metamask.spec.js b/test/e2e/chrome/metamask.spec.js
deleted file mode 100644
index b17d4c818..000000000
--- a/test/e2e/chrome/metamask.spec.js
+++ /dev/null
@@ -1,314 +0,0 @@
-const fs = require('fs')
-const mkdirp = require('mkdirp')
-const path = require('path')
-const assert = require('assert')
-const pify = require('pify')
-const webdriver = require('selenium-webdriver')
-const until = require('selenium-webdriver/lib/until')
-const By = webdriver.By
-const { delay, buildChromeWebDriver } = require('../func')
-
-describe('Metamask popup page', function () {
- let driver, accountAddress, tokenAddress, extensionId
-
- this.timeout(0)
-
- before(async function () {
- const extPath = path.resolve('dist/chrome')
- driver = buildChromeWebDriver(extPath)
- await driver.get('chrome://extensions')
- await delay(500)
- })
-
- afterEach(async function () {
- if (this.currentTest.state === 'failed') {
- await verboseReportOnFailure(this.currentTest)
- }
- })
-
- after(async function () {
- await driver.quit()
- })
-
- describe('Setup', function () {
-
- it('switches to Chrome extensions list', async function () {
- const tabs = await driver.getAllWindowHandles()
- await driver.switchTo().window(tabs[0])
- await delay(300)
- })
-
- it(`selects MetaMask's extension id and opens it in the current tab`, async function () {
- extensionId = await getExtensionId()
- await driver.get(`chrome-extension://${extensionId}/popup.html`)
- await delay(500)
- })
-
- it('sets provider type to localhost', async function () {
- await driver.wait(until.elementLocated(By.css('#app-content')), 300)
- await setProviderType('localhost')
- })
- })
-
- describe('Account Creation', () => {
-
- it('matches MetaMask title', async () => {
- const title = await driver.getTitle()
- assert.equal(title, 'MetaMask', 'title matches MetaMask')
- })
-
- it('shows privacy notice', async () => {
- await driver.wait(async () => {
- const privacyHeader = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-column.flex-center.flex-grow > h3')).getText()
- assert.equal(privacyHeader, 'PRIVACY NOTICE', 'shows privacy notice')
- return privacyHeader === 'PRIVACY NOTICE'
- }, 300)
- await driver.findElement(By.css('button')).click()
- })
-
- it('show terms of use', async () => {
- await driver.wait(async () => {
- const terms = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-column.flex-center.flex-grow > h3')).getText()
- assert.equal(terms, 'TERMS OF USE', 'shows terms of use')
- return terms === 'TERMS OF USE'
- })
- })
-
- it('checks if the TOU button is disabled', async () => {
- const button = await driver.findElement(By.css('button')).isEnabled()
- assert.equal(button, false, 'disabled continue button')
- const element = await driver.findElement(By.linkText('Attributions'))
- await driver.executeScript('arguments[0].scrollIntoView(true)', element)
- await delay(300)
- })
-
- it('allows the button to be clicked when scrolled to the bottom of TOU', async () => {
- const button = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-column.flex-center.flex-grow > button'))
- const buttonEnabled = await button.isEnabled()
- assert.equal(buttonEnabled, true, 'enabled continue button')
- await button.click()
- })
-
- it('accepts password with length of eight', async () => {
- const passwordBox = await driver.findElement(By.id('password-box'))
- const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm'))
- const button = await driver.findElements(By.css('button'))
-
- await passwordBox.sendKeys('123456789')
- await passwordBoxConfirm.sendKeys('123456789')
- await button[0].click()
- await delay(500)
- })
-
- it('shows value was created and seed phrase', async () => {
- await delay(300)
- const seedPhrase = await driver.findElement(By.css('.twelve-word-phrase')).getText()
- assert.equal(seedPhrase.split(' ').length, 12)
- const continueAfterSeedPhrase = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > button:nth-child(4)'))
- assert.equal(await continueAfterSeedPhrase.getText(), `I'VE COPIED IT SOMEWHERE SAFE`)
- await continueAfterSeedPhrase.click()
- await delay(300)
- })
-
- it('shows account address', async function () {
- accountAddress = await driver.findElement(By.css('#app-content > div > div.app-primary.from-left > div > div > div:nth-child(1) > flex-column > div.flex-row > div')).getText()
- })
-
- 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)'))
- assert.equal(await logoutButton.getText(), 'Log Out')
- await logoutButton.click()
- })
-
- it('accepts 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('shows 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('checks QR code address is the same as account details address', async () => {
- const QRaccountAddress = await driver.findElement(By.css('.ellip-address')).getText()
- assert.equal(accountAddress.toLowerCase(), QRaccountAddress)
- await driver.findElement(By.css('.fa-arrow-left')).click()
- await delay(500)
- })
- })
-
- describe('Import Ganache seed phrase', 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)'))
- assert.equal(await logOut.getText(), 'Log Out')
- await logOut.click()
- await delay(300)
- })
-
- it('restores from seed phrase', async function () {
- const restoreSeedLink = await driver.findElement(By.css('#app-content > div > div.app-primary.from-left > div > div.flex-row.flex-center.flex-grow > p'))
- assert.equal(await restoreSeedLink.getText(), 'Restore from seed phrase')
- await restoreSeedLink.click()
- await delay(100)
- })
-
- it('adds seed phrase', async function () {
- const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'
- const seedTextArea = await driver.findElement(By.css('#app-content > div > div.app-primary.from-left > div > textarea'))
- await seedTextArea.sendKeys(testSeedPhrase)
-
- await driver.findElement(By.id('password-box')).sendKeys('123456789')
- await driver.findElement(By.id('password-box-confirm')).sendKeys('123456789')
- await driver.findElement(By.css('#app-content > div > div.app-primary.from-left > div > div > button:nth-child(2)')).click()
- await delay(500)
- })
-
- it('balance renders', async function () {
- await delay(200)
- const balance = await driver.findElement(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)'))
- assert.equal(await balance.getText(), '100.000')
- await delay(200)
- })
-
- it('sends transaction', async function () {
- const sendButton = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > button:nth-child(4)'))
- assert.equal(await sendButton.getText(), 'SEND')
- await sendButton.click()
- await delay(200)
- })
-
- it('adds recipient address and amount', async function () {
- const sendTranscationScreen = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > h3:nth-child(2)')).getText()
- assert.equal(sendTranscationScreen, 'SEND TRANSACTION')
- const inputAddress = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > section:nth-child(3) > div > input'))
- const inputAmmount = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > section:nth-child(4) > input'))
- await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970')
- await inputAmmount.sendKeys('10')
- await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > section:nth-child(4) > button')).click()
- await delay(300)
- })
-
- 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)
- })
-
- it('finds the transaction in the transactions list', async function () {
- const tranasactionAmount = await driver.findElement(By.css('#app-content > div > div.app-primary.from-left > div > section > section > div > div > div > div.ether-balance.ether-balance-amount > div > div > div > div:nth-child(1)'))
- assert.equal(await tranasactionAmount.getText(), '10.0')
- })
- })
-
- describe('Token Factory', function () {
-
- it('navigates to token factory', async function () {
- await driver.get('http://tokenfactory.surge.sh/')
- })
-
- it('navigates to create token contract link', async function () {
- const createToken = await driver.findElement(By.css('#bs-example-navbar-collapse-1 > ul > li:nth-child(3) > a'))
- await createToken.click()
- })
-
- it('adds input for token', async function () {
- const totalSupply = await driver.findElement(By.css('#main > div > div > div > div:nth-child(2) > div > div:nth-child(5) > input'))
- const tokenName = await driver.findElement(By.css('#main > div > div > div > div:nth-child(2) > div > div:nth-child(6) > input'))
- const tokenDecimal = await driver.findElement(By.css('#main > div > div > div > div:nth-child(2) > div > div:nth-child(7) > input'))
- const tokenSymbol = await driver.findElement(By.css('#main > div > div > div > div:nth-child(2) > div > div:nth-child(8) > input'))
- const createToken = await driver.findElement(By.css('#main > div > div > div > div:nth-child(2) > div > button'))
-
- await totalSupply.sendKeys('100')
- await tokenName.sendKeys('Test')
- await tokenDecimal.sendKeys('0')
- await tokenSymbol.sendKeys('TST')
- await createToken.click()
- await delay(1000)
- })
-
- 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'))
- await metamaskSubmit.click()
- await delay(1000)
- })
-
- it('switches back to Token Factory to grab the token contract address', async function () {
- const windowHandles = await driver.getAllWindowHandles()
- await driver.switchTo().window(windowHandles[0])
- const tokenContactAddress = await driver.findElement(By.css('#main > div > div > div > div:nth-child(2) > span:nth-child(3)'))
- tokenAddress = await tokenContactAddress.getText()
- await delay(500)
- })
-
- it('navigates back to MetaMask popup in the tab', async function () {
- await driver.get(`chrome-extension://${extensionId}/popup.html`)
- await delay(700)
- })
- })
-
- describe('Add Token', function () {
- it('switches to the add token screen', async function () {
- const tokensTab = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > section > div > div.inactiveForm.pointer'))
- assert.equal(await tokensTab.getText(), 'TOKENS')
- await tokensTab.click()
- await delay(300)
- })
-
- it('navigates to the add token screen', async function () {
- const addTokenButton = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > section > div.full-flex-height > div > button'))
- assert.equal(await addTokenButton.getText(), 'ADD TOKEN')
- await addTokenButton.click()
- })
-
- it('checks add token screen rendered', async function () {
- const addTokenScreen = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.section-title.flex-row.flex-center > h2'))
- assert.equal(await addTokenScreen.getText(), 'ADD TOKEN')
- })
-
- it('adds token parameters', async function () {
- const tokenContractAddress = await driver.findElement(By.css('#token-address'))
- await tokenContractAddress.sendKeys(tokenAddress)
- await delay(300)
- await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-column.flex-justify-center.flex-grow.select-none > div > button')).click()
- await delay(100)
- })
-
- it('checks the token balance', async function () {
- const tokenBalance = await driver.findElement(By.css('#app-content > div > div.app-primary.from-left > div > section > div.full-flex-height > ol > li:nth-child(2) > h3'))
- assert.equal(await tokenBalance.getText(), '100 TST')
- })
- })
-
- async function getExtensionId () {
- const extension = await driver.executeScript('return document.querySelector("extensions-manager").shadowRoot.querySelector("extensions-view-manager extensions-item-list").shadowRoot.querySelector("extensions-item:nth-child(2)").getAttribute("id")')
- return extension
- }
-
- async function setProviderType (type) {
- await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
- }
-
- async function verboseReportOnFailure (test) {
- const artifactDir = `./test-artifacts/chrome/${test.title}`
- const filepathBase = `${artifactDir}/test-failure`
- await pify(mkdirp)(artifactDir)
- // capture screenshot
- const screenshot = await driver.takeScreenshot()
- await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' })
- // capture dom source
- const htmlSource = await driver.getPageSource()
- await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource)
- }
-
-})
diff --git a/test/e2e/func.js b/test/e2e/func.js
index 4ad0ea615..8b221ce47 100644
--- a/test/e2e/func.js
+++ b/test/e2e/func.js
@@ -1,13 +1,24 @@
require('chromedriver')
require('geckodriver')
+const path = require('path')
const webdriver = require('selenium-webdriver')
+const Command = require('selenium-webdriver/lib/command').Command
+const By = webdriver.By
-exports.delay = function delay (time) {
- return new Promise(resolve => setTimeout(resolve, time))
+module.exports = {
+ delay,
+ buildChromeWebDriver,
+ buildFirefoxWebdriver,
+ installWebExt,
+ getExtensionIdChrome,
+ getExtensionIdFirefox,
}
+function delay (time) {
+ return new Promise(resolve => setTimeout(resolve, time))
+}
-exports.buildChromeWebDriver = function buildChromeWebDriver (extPath) {
+function buildChromeWebDriver (extPath) {
return new webdriver.Builder()
.withCapabilities({
chromeOptions: {
@@ -17,6 +28,29 @@ exports.buildChromeWebDriver = function buildChromeWebDriver (extPath) {
.build()
}
-exports.buildFirefoxWebdriver = function buildFirefoxWebdriver (extPath) {
+function buildFirefoxWebdriver () {
return new webdriver.Builder().build()
}
+
+async function getExtensionIdChrome (driver) {
+ await driver.get('chrome://extensions')
+ const extensionId = await driver.executeScript('return document.querySelector("extensions-manager").shadowRoot.querySelector("extensions-view-manager extensions-item-list").shadowRoot.querySelector("extensions-item:nth-child(2)").getAttribute("id")')
+ return extensionId
+}
+
+async function getExtensionIdFirefox (driver) {
+ await driver.get('about:debugging#addons')
+ const extensionId = await driver.findElement(By.css('dd.addon-target-info-content:nth-child(6) > span:nth-child(1)')).getText()
+ return extensionId
+}
+
+async function installWebExt (driver, extension) {
+ const cmd = await new Command('moz-install-web-ext')
+ .setParameter('path', path.resolve(extension))
+ .setParameter('temporary', true)
+
+ await driver.getExecutor()
+ .defineCommand(cmd.getName(), 'POST', '/session/:sessionId/moz/addon/install')
+
+ return await driver.schedule(cmd, 'installWebExt(' + extension + ')')
+} \ No newline at end of file
diff --git a/test/e2e/firefox/metamask.spec.js b/test/e2e/metamask.spec.js
index c75b1a9b5..707ca2560 100644
--- a/test/e2e/firefox/metamask.spec.js
+++ b/test/e2e/metamask.spec.js
@@ -4,20 +4,29 @@ const path = require('path')
const assert = require('assert')
const pify = require('pify')
const webdriver = require('selenium-webdriver')
-const Command = require('selenium-webdriver/lib/command').Command
-const By = webdriver.By
-const { delay, buildFirefoxWebdriver } = require('../func')
+const { By, Key } = webdriver
+const { delay, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, getExtensionIdChrome, getExtensionIdFirefox } = require('./func')
-describe('', function () {
+describe('Metamask popup page', function () {
let driver, accountAddress, tokenAddress, extensionId
this.timeout(0)
before(async function () {
- const extPath = path.resolve('dist/firefox')
- driver = buildFirefoxWebdriver()
- installWebExt(driver, extPath)
- await delay(700)
+ if (process.env.SELENIUM_BROWSER === 'chrome') {
+ const extPath = path.resolve('dist/chrome')
+ driver = buildChromeWebDriver(extPath)
+ extensionId = await getExtensionIdChrome(driver)
+ await driver.get(`chrome-extension://${extensionId}/popup.html`)
+
+ } else if (process.env.SELENIUM_BROWSER === 'firefox') {
+ const extPath = path.resolve('dist/firefox')
+ driver = buildFirefoxWebdriver()
+ await installWebExt(driver, extPath)
+ await delay(700)
+ extensionId = await getExtensionIdFirefox(driver)
+ await driver.get(`moz-extension://${extensionId}/popup.html`)
+ }
})
afterEach(async function () {
@@ -32,23 +41,17 @@ describe('', function () {
describe('Setup', function () {
- it('switches to Firefox addon list', async function () {
- await driver.get('about:debugging#addons')
- await delay(1000)
- })
-
- it(`selects MetaMask's extension id and opens it in the current tab`, async function () {
- const tabs = await driver.getAllWindowHandles()
- await driver.switchTo().window(tabs[0])
- extensionId = await driver.findElement(By.css('dd.addon-target-info-content:nth-child(6) > span:nth-child(1)')).getText()
- await driver.get(`moz-extension://${extensionId}/popup.html`)
- await delay(500)
+ it('switches to Chrome extensions list', async function () {
+ await delay(300)
+ const windowHandles = await driver.getAllWindowHandles()
+ await driver.switchTo().window(windowHandles[0])
})
it('sets provider type to localhost', async function () {
- await setProviderType('localhost')
await delay(300)
+ await setProviderType('localhost')
})
+
})
describe('Account Creation', () => {
@@ -67,10 +70,9 @@ describe('', function () {
})
it('show terms of use', async () => {
- await delay(300)
const terms = await driver.findElement(By.css('.terms-header')).getText()
assert.equal(terms, 'TERMS OF USE', 'shows terms of use')
- await delay(300)
+ delay(300)
})
it('checks if the TOU button is disabled', async () => {
@@ -78,15 +80,11 @@ describe('', function () {
assert.equal(button, false, 'disabled continue button')
const element = await driver.findElement(By.linkText('Attributions'))
await driver.executeScript('arguments[0].scrollIntoView(true)', element)
- await delay(300)
+ await delay(700)
})
it('allows the button to be clicked when scrolled to the bottom of TOU', async () => {
const button = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-column.flex-center.flex-grow > button'))
- await delay(300)
- const buttonEnabled = await button.isEnabled()
- assert.equal(buttonEnabled, true, 'enabled continue button')
- await delay(200)
await button.click()
})
@@ -126,7 +124,7 @@ describe('', function () {
it('accepts account password after lock', async () => {
await delay(500)
await driver.findElement(By.id('password-box')).sendKeys('123456789')
- await driver.findElement(By.id('password-box')).sendKeys(webdriver.Key.ENTER)
+ await driver.findElement(By.id('password-box')).sendKeys(Key.ENTER)
await delay(500)
})
@@ -146,6 +144,7 @@ describe('', function () {
})
describe('Import Ganache seed phrase', function () {
+
it('logs out', async function () {
await driver.findElement(By.css('.sandwich-expando')).click()
await delay(200)
@@ -236,7 +235,7 @@ describe('', function () {
await delay(1000)
})
- // There is an issue with blank confirmation window, but the button is still there and the driver is able to clicked (?.?)
+ // There is an issue with blank confirmation window in Firefox, but the button is still there and the driver is able to clicked (?.?)
it('confirms transaction in MetaMask popup', async function () {
const windowHandles = await driver.getAllWindowHandles()
await driver.switchTo().window(windowHandles[windowHandles.length - 1])
@@ -254,12 +253,17 @@ describe('', function () {
})
it('navigates back to MetaMask popup in the tab', async function () {
- await driver.get(`moz-extension://${extensionId}/popup.html`)
+ if (process.env.SELENIUM_BROWSER === 'chrome') {
+ await driver.get(`chrome-extension://${extensionId}/popup.html`)
+ } else if (process.env.SELENIUM_BROWSER === 'firefox') {
+ await driver.get(`moz-extension://${extensionId}/popup.html`)
+ }
await delay(700)
})
})
describe('Add Token', function () {
+
it('switches to the add token screen', async function () {
const tokensTab = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > section > div > div.inactiveForm.pointer'))
assert.equal(await tokensTab.getText(), 'TOKENS')
@@ -283,7 +287,7 @@ describe('', function () {
await tokenContractAddress.sendKeys(tokenAddress)
await delay(300)
await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-column.flex-justify-center.flex-grow.select-none > div > button')).click()
- await delay(100)
+ await delay(200)
})
it('checks the token balance', async function () {
@@ -292,12 +296,17 @@ describe('', function () {
})
})
- async function setProviderType(type) {
+ async function setProviderType (type) {
await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
}
- async function verboseReportOnFailure(test) {
- const artifactDir = `./test-artifacts/firefox/${test.title}`
+ 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
@@ -309,15 +318,3 @@ describe('', function () {
}
})
-
-async function installWebExt (driver, extension) {
- const cmd = await new Command('moz-install-web-ext')
- .setParameter('path', path.resolve(extension))
- .setParameter('temporary', true)
-
- await driver.getExecutor()
- .defineCommand(cmd.getName(), 'POST', '/session/:sessionId/moz/addon/install')
-
- return await driver.schedule(cmd, 'installWebExt(' + extension + ')')
-}
-
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' })
+}
diff --git a/test/unit/actions/save_account_label_test.js b/test/unit/actions/save_account_label_test.js
deleted file mode 100644
index c5ffd6cbf..000000000
--- a/test/unit/actions/save_account_label_test.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// var jsdom = require('mocha-jsdom')
-var assert = require('assert')
-var freeze = require('deep-freeze-strict')
-var path = require('path')
-
-var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
-var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
-
-describe('SAVE_ACCOUNT_LABEL', function () {
- it('updates the state.metamask.identities[:i].name property of the state to the action.value.label', function () {
- var initialState = {
- metamask: {
- identities: {
- foo: {
- name: 'bar',
- },
- },
- },
- }
- freeze(initialState)
-
- const action = {
- type: actions.SAVE_ACCOUNT_LABEL,
- value: {
- account: 'foo',
- label: 'baz',
- },
- }
- freeze(action)
-
- var resultingState = reducers(initialState, action)
- assert.equal(resultingState.metamask.identities.foo.name, action.value.label)
- })
-})
-
diff --git a/test/unit/actions/set_account_label_test.js b/test/unit/actions/set_account_label_test.js
new file mode 100644
index 000000000..53ea1d130
--- /dev/null
+++ b/test/unit/actions/set_account_label_test.js
@@ -0,0 +1,34 @@
+const assert = require('assert')
+const freeze = require('deep-freeze-strict')
+const path = require('path')
+
+const actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
+const reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
+
+describe('SET_ACCOUNT_LABEL', function () {
+ it('updates the state.metamask.identities[:i].name property of the state to the action.value.label', function () {
+ const initialState = {
+ metamask: {
+ identities: {
+ foo: {
+ name: 'bar',
+ },
+ },
+ },
+ }
+ freeze(initialState)
+
+ const action = {
+ type: actions.SET_ACCOUNT_LABEL,
+ value: {
+ account: 'foo',
+ label: 'baz',
+ },
+ }
+ freeze(action)
+
+ const resultingState = reducers(initialState, action)
+ assert.equal(resultingState.metamask.identities.foo.name, action.value.label)
+ })
+})
+
diff --git a/test/unit/address-book-controller.js b/test/unit/address-book-controller.js
index 655c9022c..e48e69d98 100644
--- a/test/unit/address-book-controller.js
+++ b/test/unit/address-book-controller.js
@@ -1,26 +1,26 @@
const assert = require('assert')
const AddressBookController = require('../../app/scripts/controllers/address-book')
-const mockKeyringController = {
- memStore: {
- getState: function () {
- return {
- identities: {
- '0x0aaa': {
- address: '0x0aaa',
- name: 'owned',
- },
+const stubPreferencesStore = {
+ getState: function () {
+ return {
+ identities: {
+ '0x0aaa': {
+ address: '0x0aaa',
+ name: 'owned',
},
- }
- },
+ },
+ }
},
-}
+};
describe('address-book-controller', function () {
var addressBookController
beforeEach(function () {
- addressBookController = new AddressBookController({}, mockKeyringController)
+ addressBookController = new AddressBookController({
+ preferencesStore: stubPreferencesStore,
+ })
})
describe('addres book management', function () {
diff --git a/test/unit/metamask-controller-test.js b/test/unit/metamask-controller-test.js
index 18c3f9ab9..649b26e1e 100644
--- a/test/unit/metamask-controller-test.js
+++ b/test/unit/metamask-controller-test.js
@@ -106,7 +106,7 @@ describe('MetaMaskController', function () {
[TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL },
})
- await metamaskController.keyringController.saveAccountLabel(TEST_ADDRESS, 'Account Foo')
+ await metamaskController.preferencesController.setAccountLabel(TEST_ADDRESS, 'Account Foo')
assert.deepEqual(metamaskController.getState().identities, {
[TEST_ADDRESS]: { address: TEST_ADDRESS, name: 'Account Foo' },
})
diff --git a/test/unit/migrations/026-test.js b/test/unit/migrations/026-test.js
new file mode 100644
index 000000000..b3f5470cf
--- /dev/null
+++ b/test/unit/migrations/026-test.js
@@ -0,0 +1,41 @@
+const assert = require('assert')
+const migration26 = require('../../../app/scripts/migrations/026')
+const oldStorage = {
+ 'meta': {'version': 25},
+ 'data': {
+ 'PreferencesController': {},
+ 'KeyringController': {
+ 'walletNicknames': {
+ '0x1e77e2': 'Test Account 1',
+ '0x7e57e2': 'Test Account 2',
+ },
+ },
+ },
+}
+
+describe('migration #26', () => {
+ it('should move the identities from KeyringController', (done) => {
+ migration26.migrate(oldStorage)
+ .then((newStorage) => {
+ const identities = newStorage.data.PreferencesController.identities
+ assert.deepEqual(identities, {
+ '0x1e77e2': {name: 'Test Account 1', address: '0x1e77e2'},
+ '0x7e57e2': {name: 'Test Account 2', address: '0x7e57e2'},
+ })
+ assert.strictEqual(newStorage.data.KeyringController.walletNicknames, undefined)
+ done()
+ })
+ .catch(done)
+ })
+
+ it('should successfully migrate first time state', (done) => {
+ migration26.migrate({
+ meta: {},
+ data: require('../../../app/scripts/first-time-state'),
+ })
+ .then((migratedData) => {
+ assert.equal(migratedData.meta.version, migration26.version)
+ done()
+ }).catch(done)
+ })
+})
diff --git a/test/unit/preferences-controller-test.js b/test/unit/preferences-controller-test.js
index 9fb5e4251..c613c68f9 100644
--- a/test/unit/preferences-controller-test.js
+++ b/test/unit/preferences-controller-test.js
@@ -4,16 +4,91 @@ const PreferencesController = require('../../app/scripts/controllers/preferences
describe('preferences controller', function () {
let preferencesController
- before(() => {
+ beforeEach(() => {
preferencesController = new PreferencesController()
})
+ describe('setAddresses', function () {
+ it('should keep a map of addresses to names and addresses in the store', function () {
+ preferencesController.setAddresses([
+ '0xda22le',
+ '0x7e57e2',
+ ])
+
+ const {identities} = preferencesController.store.getState()
+ assert.deepEqual(identities, {
+ '0xda22le': {
+ name: 'Account 1',
+ address: '0xda22le',
+ },
+ '0x7e57e2': {
+ name: 'Account 2',
+ address: '0x7e57e2',
+ },
+ })
+ })
+
+ it('should replace its list of addresses', function () {
+ preferencesController.setAddresses([
+ '0xda22le',
+ '0x7e57e2',
+ ])
+ preferencesController.setAddresses([
+ '0xda22le77',
+ '0x7e57e277',
+ ])
+
+ const {identities} = preferencesController.store.getState()
+ assert.deepEqual(identities, {
+ '0xda22le77': {
+ name: 'Account 1',
+ address: '0xda22le77',
+ },
+ '0x7e57e277': {
+ name: 'Account 2',
+ address: '0x7e57e277',
+ },
+ })
+ })
+ })
+
+ describe('setAccountLabel', function () {
+ it('should update a label for the given account', function () {
+ preferencesController.setAddresses([
+ '0xda22le',
+ '0x7e57e2',
+ ])
+
+ assert.deepEqual(preferencesController.store.getState().identities['0xda22le'], {
+ name: 'Account 1',
+ address: '0xda22le',
+ })
+
+
+ preferencesController.setAccountLabel('0xda22le', 'Dazzle')
+ assert.deepEqual(preferencesController.store.getState().identities['0xda22le'], {
+ name: 'Dazzle',
+ address: '0xda22le',
+ })
+ })
+ })
+
+ describe('getTokens', function () {
+ it('should return an empty list initially', async function () {
+ await preferencesController.setSelectedAddress('0x7e57e2')
+
+ const tokens = preferencesController.getTokens()
+ assert.equal(tokens.length, 0, 'empty list of tokens')
+ })
+ })
+
describe('addToken', function () {
it('should add that token to its state', async function () {
const address = '0xabcdef1234567'
const symbol = 'ABBR'
const decimals = 5
+ await preferencesController.setSelectedAddress('0x7e57e2')
await preferencesController.addToken(address, symbol, decimals)
const tokens = preferencesController.getTokens()
@@ -30,6 +105,7 @@ describe('preferences controller', function () {
const symbol = 'ABBR'
const decimals = 5
+ await preferencesController.setSelectedAddress('0x7e57e2')
await preferencesController.addToken(address, symbol, decimals)
const newDecimals = 6
@@ -43,6 +119,44 @@ describe('preferences controller', function () {
assert.equal(added.symbol, symbol, 'set symbol correctly')
assert.equal(added.decimals, newDecimals, 'updated decimals correctly')
})
+
+ it('should allow adding tokens to two separate addresses', async function () {
+ const address = '0xabcdef1234567'
+ const symbol = 'ABBR'
+ const decimals = 5
+
+ await preferencesController.setSelectedAddress('0x7e57e2')
+ await preferencesController.addToken(address, symbol, decimals)
+ assert.equal(preferencesController.getTokens().length, 1, 'one token added for 1st address')
+
+ await preferencesController.setSelectedAddress('0xda22le')
+ await preferencesController.addToken(address, symbol, decimals)
+ assert.equal(preferencesController.getTokens().length, 1, 'one token added for 2nd address')
+ })
+ })
+
+ describe('removeToken', function () {
+ it('should remove the only token from its state', async function () {
+ await preferencesController.setSelectedAddress('0x7e57e2')
+ await preferencesController.addToken('0xa', 'A', 5)
+ await preferencesController.removeToken('0xa')
+
+ const tokens = preferencesController.getTokens()
+ assert.equal(tokens.length, 0, 'one token removed')
+ })
+
+ it('should remove a token from its state', async function () {
+ await preferencesController.setSelectedAddress('0x7e57e2')
+ await preferencesController.addToken('0xa', 'A', 4)
+ await preferencesController.addToken('0xb', 'B', 5)
+ await preferencesController.removeToken('0xa')
+
+ const tokens = preferencesController.getTokens()
+ assert.equal(tokens.length, 1, 'one token removed')
+
+ const [token1] = tokens
+ assert.deepEqual(token1, {address: '0xb', symbol: 'B', decimals: 5})
+ })
})
})
diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js
index ddd921652..0b5c7226a 100644
--- a/test/unit/tx-controller-test.js
+++ b/test/unit/tx-controller-test.js
@@ -40,36 +40,6 @@ describe('Transaction Controller', function () {
txController.nonceTracker.getNonceLock = () => Promise.resolve({ nextNonce: 0, releaseLock: noop })
})
- describe('#isNonceTaken', function () {
- it('should return true', function (done) {
- txController.txStateManager._saveTxList([
- { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {nonce: 0, from: '0x8ACCE2391C0d510a6C5E5D8f819A678F79B7E675'} },
- { id: 2, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {nonce: 0, from: '0x8ACCE2391C0d510a6C5E5D8f819A678F79B7E675'} },
- { id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {nonce: 0, from: '0x8ACCE2391C0d510a6C5E5D8f819A678F79B7E675'} },
- ])
- txController.isNonceTaken({txParams: {nonce:0, from:'0x8ACCE2391C0d510a6C5E5D8f819A678F79B7E675'}})
- .then((isNonceTaken) => {
- assert(isNonceTaken)
- done()
- }).catch(done)
-
- })
- it('should return false', function (done) {
- txController.txStateManager._saveTxList([
- { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {nonce: 0, from: '0x8ACCE2391C0d510a6C5E5D8f819A678F79B7E675'} },
- { id: 2, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {nonce: 0, from: '0x8ACCE2391C0d510a6C5E5D8f819A678F79B7E675'} },
- { id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {nonce: 0, from: '0x8ACCE2391C0d510a6C5E5D8f819A678F79B7E675'} },
- ])
-
- txController.isNonceTaken({txParams: {nonce:0, from:'0x8ACCE2391C0d510a6C5E5D8f819A678F79B7E675'}})
- .then((isNonceTaken) => {
- assert(!isNonceTaken)
- done()
- }).catch(done)
-
- })
- })
-
describe('#getState', function () {
it('should return a state object with the right keys and datat types', function () {
const exposedState = txController.getState()