aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml58
-rw-r--r--development/genStates.js31
-rw-r--r--development/mock-dev.js (renamed from mock-dev.js)22
-rw-r--r--development/ui-dev.js (renamed from ui-dev.js)10
-rw-r--r--mascara/src/app/first-time/create-password-screen.js17
-rw-r--r--mascara/src/app/first-time/index.css128
-rw-r--r--package.json6
-rw-r--r--test/base.conf.js4
-rw-r--r--test/integration/index.js2
-rw-r--r--test/integration/lib/add-token.js73
-rw-r--r--test/integration/lib/confirm-sig-requests.js44
-rw-r--r--test/integration/lib/first-time.js80
-rw-r--r--test/integration/lib/mascara-first-time.js94
-rw-r--r--test/integration/lib/send-new-ui.js129
-rw-r--r--test/lib/util.js53
-rw-r--r--ui/app/actions.js10
-rw-r--r--ui/app/app.js23
-rw-r--r--ui/app/components/tx-view.js10
-rw-r--r--ui/app/css/itcss/components/hero-balance.scss3
-rw-r--r--ui/app/css/itcss/components/index.scss3
-rw-r--r--ui/app/css/itcss/components/newui-sections.scss23
-rw-r--r--ui/app/css/itcss/components/welcome-screen.scss59
-rw-r--r--ui/app/main-container.js14
-rw-r--r--ui/app/reducers/metamask.js6
-rw-r--r--ui/app/unlock.js143
-rw-r--r--ui/app/welcome-screen.js56
26 files changed, 646 insertions, 455 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 9cd0a24ec..c14909783 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -15,12 +15,20 @@ workflows:
- test-unit:
requires:
- prep-deps-npm
- - test-integration-mascara:
+ - test-integration-mascara-chrome:
+ requires:
+ - prep-deps-npm
+ - prep-scss
+ - test-integration-mascara-firefox:
requires:
- prep-deps-npm
- prep-deps-firefox
- prep-scss
- - test-integration-flat:
+ - test-integration-flat-chrome:
+ requires:
+ - prep-deps-npm
+ - prep-scss
+ - test-integration-flat-firefox:
requires:
- prep-deps-npm
- prep-deps-firefox
@@ -99,7 +107,9 @@ jobs:
name: test:coverage
command: npm run test:coverage
- test-integration-flat:
+ test-integration-flat-firefox:
+ environment:
+ browsers: '["Firefox"]'
docker:
- image: circleci/node:8-browsers
steps:
@@ -125,7 +135,28 @@ jobs:
name: test:integration:flat
command: npm run test:flat
- test-integration-mascara:
+ test-integration-flat-chrome:
+ environment:
+ browsers: '["Chrome"]'
+ docker:
+ - image: circleci/node:8-browsers
+ steps:
+ - checkout
+ - restore_cache:
+ key: dependency-cache-{{ checksum "package-lock.json" }}
+ - run:
+ name: Get Scss Cache key
+ # this allows us to checksum against a whole directory
+ command: find ui/app/css -type f -exec md5sum {} \; | sort -k 2 > scss_checksum
+ - restore_cache:
+ key: scss-cache-{{ checksum "scss_checksum" }}
+ - run:
+ name: test:integration:flat
+ command: npm run test:flat
+
+ test-integration-mascara-firefox:
+ environment:
+ browsers: '["Firefox"]'
docker:
- image: circleci/node:8-browsers
steps:
@@ -150,3 +181,22 @@ jobs:
- run:
name: test:integration:mascara
command: npm run test:mascara
+
+ test-integration-mascara-chrome:
+ environment:
+ browsers: '["Chrome"]'
+ docker:
+ - image: circleci/node:8-browsers
+ steps:
+ - checkout
+ - restore_cache:
+ key: dependency-cache-{{ checksum "package-lock.json" }}
+ - run:
+ name: Get Scss Cache key
+ # this allows us to checksum against a whole directory
+ command: find ui/app/css -type f -exec md5sum {} \; | sort -k 2 > scss_checksum
+ - restore_cache:
+ key: scss-cache-{{ checksum "scss_checksum" }}
+ - run:
+ name: test:integration:mascara
+ command: npm run test:mascara
diff --git a/development/genStates.js b/development/genStates.js
index 39a672ee0..d92e2bc2e 100644
--- a/development/genStates.js
+++ b/development/genStates.js
@@ -1,18 +1,21 @@
const fs = require('fs')
const path = require('path')
+const { promisify } = require('util')
-const statesPath = path.join(__dirname, 'states')
-const stateNames = fs.readdirSync(statesPath)
+start().catch(console.error)
-const states = stateNames.reduce((result, stateFileName) => {
- const statePath = path.join(__dirname, 'states', stateFileName)
- const stateFile = fs.readFileSync(statePath).toString()
- const state = JSON.parse(stateFile)
- result[stateFileName.split('.')[0].replace(/-/g, ' ', 'g')] = state
- return result
-}, {})
-
-const result = `module.exports = ${JSON.stringify(states)}`
-
-const statesJsonPath = path.join(__dirname, 'states.js')
-fs.writeFileSync(statesJsonPath, result)
+async function start () {
+ const statesPath = path.join(__dirname, 'states')
+ const stateFilesNames = await promisify(fs.readdir)(statesPath)
+ const states = {}
+ await Promise.all(stateFilesNames.map(async (stateFileName) => {
+ const stateFilePath = path.join(__dirname, 'states', stateFileName)
+ const stateFileContent = await promisify(fs.readFile)(stateFilePath, 'utf8')
+ const state = JSON.parse(stateFileContent)
+ const stateName = stateFileName.split('.')[0].replace(/-/g, ' ', 'g')
+ states[stateName] = state
+ }))
+ const generatedFileContent = `module.exports = ${JSON.stringify(states)}`
+ const generatedFilePath = path.join(__dirname, 'states.js')
+ await promisify(fs.writeFile)(generatedFilePath, generatedFileContent)
+}
diff --git a/mock-dev.js b/development/mock-dev.js
index 6627c1153..a1fb3a86d 100644
--- a/mock-dev.js
+++ b/development/mock-dev.js
@@ -15,16 +15,16 @@
const extend = require('xtend')
const render = require('react-dom').render
const h = require('react-hyperscript')
-const Root = require('./ui/app/root')
-const configureStore = require('./ui/app/store')
-const actions = require('./ui/app/actions')
-const states = require('./development/states')
-const backGroundConnectionModifiers = require('./development/backGroundConnectionModifiers')
-const Selector = require('./development/selector')
-const MetamaskController = require('./app/scripts/metamask-controller')
-const firstTimeState = require('./app/scripts/first-time-state')
-const ExtensionPlatform = require('./app/scripts/platforms/extension')
-const extension = require('./development/mockExtension')
+const Root = require('../ui/app/root')
+const configureStore = require('../ui/app/store')
+const actions = require('../ui/app/actions')
+const states = require('./states')
+const backGroundConnectionModifiers = require('./backGroundConnectionModifiers')
+const Selector = require('./selector')
+const MetamaskController = require('../app/scripts/metamask-controller')
+const firstTimeState = require('../app/scripts/first-time-state')
+const ExtensionPlatform = require('../app/scripts/platforms/extension')
+const extension = require('./mockExtension')
const noop = function () {}
const log = require('loglevel')
@@ -51,7 +51,7 @@ function updateQueryParams(newView) {
// CSS
//
-const MetaMaskUiCss = require('./ui/css')
+const MetaMaskUiCss = require('../ui/css')
const injectCss = require('inject-css')
//
diff --git a/ui-dev.js b/development/ui-dev.js
index 620d81667..cac433909 100644
--- a/ui-dev.js
+++ b/development/ui-dev.js
@@ -17,10 +17,10 @@
const render = require('react-dom').render
const h = require('react-hyperscript')
-const Root = require('./ui/app/root')
-const configureStore = require('./development/uiStore')
-const states = require('./development/states')
-const Selector = require('./development/selector')
+const Root = require('../ui/app/root')
+const configureStore = require('./uiStore')
+const states = require('./states')
+const Selector = require('./selector')
// logger
const log = require('loglevel')
@@ -35,7 +35,7 @@ const firstState = states[selectedView]
updateQueryParams(selectedView)
// CSS
-const MetaMaskUiCss = require('./ui/css')
+const MetaMaskUiCss = require('../ui/css')
const injectCss = require('inject-css')
diff --git a/mascara/src/app/first-time/create-password-screen.js b/mascara/src/app/first-time/create-password-screen.js
index 450d6a479..192da3399 100644
--- a/mascara/src/app/first-time/create-password-screen.js
+++ b/mascara/src/app/first-time/create-password-screen.js
@@ -2,6 +2,7 @@ import EventEmitter from 'events'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
+import classnames from 'classnames'
import {createNewVaultAndKeychain} from '../../../../ui/app/actions'
import LoadingScreen from './loading-screen'
import Breadcrumbs from './breadcrumbs'
@@ -14,6 +15,7 @@ class CreatePasswordScreen extends Component {
goToImportWithSeedPhrase: PropTypes.func.isRequired,
goToImportAccount: PropTypes.func.isRequired,
next: PropTypes.func.isRequired,
+ isMascara: PropTypes.bool.isRequired,
}
state = {
@@ -53,14 +55,17 @@ class CreatePasswordScreen extends Component {
}
render () {
- const { isLoading, goToImportWithSeedPhrase } = this.props
+ const { isLoading, goToImportWithSeedPhrase, isMascara } = this.props
return isLoading
? <LoadingScreen loadingMessage="Creating your new account" />
: (
- <div>
- <div className="first-view-main">
- <div className="mascara-info">
+ <div className={classnames({ 'first-view-main-wrapper': !isMascara })}>
+ <div className={classnames({
+ 'first-view-main': !isMascara,
+ 'first-view-main__mascara': isMascara,
+ })}>
+ {isMascara && <div className="mascara-info first-view-phone-invisible">
<Mascot
animationEventEmitter={this.animationEventEmitter}
width="225"
@@ -72,7 +77,7 @@ class CreatePasswordScreen extends Component {
<div className="info">
It allows you to hold ether & tokens, and interact with decentralized applications.
</div>
- </div>
+ </div>}
<div className="create-password">
<div className="create-password__title">
Create Password
@@ -127,7 +132,7 @@ class CreatePasswordScreen extends Component {
}
export default connect(
- ({ appState: { isLoading } }) => ({ isLoading }),
+ ({ appState: { isLoading }, metamask: { isMascara } }) => ({ isLoading, isMascara }),
dispatch => ({
createAccount: password => dispatch(createNewVaultAndKeychain(password)),
})
diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css
index f59eb4ce1..6c45816bd 100644
--- a/mascara/src/app/first-time/index.css
+++ b/mascara/src/app/first-time/index.css
@@ -1,3 +1,10 @@
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Roboto'), local('Roboto-Regular'), url('/fonts/Roboto/Roboto-Regular.ttf') format('truetype');
+ unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
+}
.first-time-flow {
width: 100vw;
@@ -6,21 +13,52 @@
display: flex;
justify-content: center;
flex: 1 0 auto;
+ font-weight: 400;
+ font-family: Roboto;
}
-.alpha-warning {
+.alpha-warning,
+.alpha-warning-welcome-screen {
background: #f7861c;
color: #fff;
line-height: 2em;
padding-left: 10vw;
}
-.first-view-main {
+.alpha-warning-welcome-screen {
+ padding-left: 0;
+ text-align: center;
+}
+
+.first-view-main-wrapper {
+ display: flex;
+ width: 100%;
+ padding-left: 10vw;
+}
+
+.first-view-main,
+.first-view-main__mascara {
display: flex;
flex-direction: row-reverse;
+ justify-content: center;
+}
+
+.first-view-main__mascara {
justify-content: space-between;
}
+@media screen and (max-width: 575px) {
+ .first-view-main-wrapper {
+ padding: 0;
+ }
+}
+
+@media screen and (min-width: 1281px) {
+ .first-view-main {
+ width: 62vw;
+ }
+}
+
.mascara-info {
display: flex;
flex-flow: column;
@@ -81,6 +119,45 @@
width: initial !important;
}
+ .alpha-warning,
+ .alpha-warning-welcome-screen {
+ line-height: 1em;
+ padding: 8px 12px;
+ }
+
+ .first-view-main {
+ height: 100%;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-evenly;
+ margin-top: 12px;
+ }
+
+ .first-view-main .create-password {
+ margin-top: 0px;
+ }
+
+ .mascara-info {
+ margin-top: 0px;
+ width: 100%;
+ align-items: center;
+ }
+
+ .mascara-info .info {
+ text-align: center;
+ font-size: 16px;
+ margin: 0 10px;
+ padding-left: 0px;
+ }
+
+ .mascara-info :first-child {
+ align-self: center;
+ }
+
+ .first-view-phone-invisible {
+ display: none;
+ }
+
.first-time-flow__input {
width: initial !important;
font-size: 14px !important;
@@ -180,11 +257,11 @@
color: #1B344D;
font-size: 16px;
line-height: 23px;
- font-family: Montserrat UltraLight;
+ font-family: Roboto;
}
.buy-ether__small-body-text {
- font-family: Montserrat UltraLight;
+ font-family: Roboto;
height: 14px;
color: #757575;
font-size: 12px;
@@ -212,7 +289,7 @@
height: 334px;
overflow-y: auto;
color: #757575;
- font-family: Montserrat UltraLight;
+ font-family: Roboto;
font-size: 12px;
line-height: 15px;
text-align: justify;
@@ -237,7 +314,7 @@
color: #5B5D67;
font-size: 16px;
line-height: 23px;
- font-family: Montserrat UltraLight;
+ font-family: Roboto;
}
.backup-phrase__secret {
@@ -255,7 +332,7 @@
.backup-phrase__secret-words {
width: 310px;
color: #5B5D67;
- font-family: Montserrat Light;
+ font-family: Roboto;
font-size: 20px;
line-height: 26px;
text-align: center;
@@ -284,7 +361,7 @@
background: none;
box-shadow: none;
color: #FFFFFF;
- font-family: Montserrat Regular;
+ font-family: Roboto;
font-size: 12px;
font-weight: bold;
line-height: 15px;
@@ -338,7 +415,7 @@ button.backup-phrase__reveal-button:hover {
.backup-phrase__confirm-seed-option {
color: #5B5D67;
- font-family: Montserrat Light;
+ font-family: Roboto;
font-size: 16px;
line-height: 21px;
background-color: #E7E7E7;
@@ -360,7 +437,7 @@ button.backup-phrase__confirm-seed-option:hover {
.import-account__faq-link {
font-size: 18px;
line-height: 23px;
- font-family: Montserrat Light;
+ font-family: Roboto;
}
.import-account__selector-label {
@@ -375,7 +452,7 @@ button.backup-phrase__confirm-seed-option:hover {
background-color: #FFFFFF;
margin-top: 14px;
color: #5B5D67;
- font-family: Montserrat Light;
+ font-family: Roboto;
font-size: 18px;
line-height: 23px;
padding: 14px 21px;
@@ -390,7 +467,7 @@ button.backup-phrase__confirm-seed-option:hover {
font-size: 18px;
line-height: 23px;
margin-top: 21px;
- font-family: Montserrat UltraLight;
+ font-family: Roboto;
}
.import-account__input-wrapper {
@@ -436,7 +513,7 @@ button.backup-phrase__confirm-seed-option:hover {
border: 1px solid #1B344D;
border-radius: 4px;
color: #1B344D;
- font-family: Montserrat Light;
+ font-family: Roboto;
font-size: 18px;
display: flex;
flex-flow: column nowrap;
@@ -453,7 +530,7 @@ button.backup-phrase__confirm-seed-option:hover {
.import-account__file-name {
color: #000000;
- font-family: Montserrat Light;
+ font-family: Roboto;
font-size: 18px;
line-height: 23px;
margin-left: 22px;
@@ -474,7 +551,7 @@ button.backup-phrase__confirm-seed-option:hover {
.buy-ether__content-headline {
color: #1B344D;
- font-family: Montserrat Light;
+ font-family: Roboto;
font-size: 18px;
line-height: 23px;
}
@@ -503,7 +580,7 @@ button.backup-phrase__confirm-seed-option:hover {
align-items: center;
padding: 20px 0;
color: #9B9B9B;
- font-family: Montserrat Light;
+ font-family: Roboto;
font-size: 14px;
line-height: 18px;
cursor: pointer;
@@ -538,7 +615,7 @@ button.backup-phrase__confirm-seed-option:hover {
.buy-ether__button-separator-text {
font-size: 20px;
line-height: 26px;
- font-family: Montserrat Light;
+ font-family: Roboto;
margin: 35px 0 14px 30px;
display: flex;
flex-flow: column nowrap;
@@ -550,7 +627,7 @@ button.backup-phrase__confirm-seed-option:hover {
color: #1B344D !important;
font-size: 14px !important;
line-height: 18px !important;
- font-family: Montserrat UltraLight !important;
+ font-family: Roboto;
}
.buy-ether__action-content-wrapper {
@@ -584,6 +661,7 @@ button.backup-phrase__confirm-seed-option:hover {
color: #FFFFFF;
font-size: 20px;
font-weight: 500;
+ font-family: Roboto;
line-height: 26px;
text-align: center;
text-transform: uppercase;
@@ -608,7 +686,7 @@ button.first-time-flow__button:hover {
color: #1B344D;
font-size: 20px;
line-height: 26px;
- font-family: Montserrat Light;
+ font-family: Roboto;
text-align: center;
margin: 35px 0 14px;
background-color: transparent;
@@ -660,7 +738,7 @@ button.first-time-flow__button--tertiary:hover {
font-size: 20px;
line-height: 26px;
text-align: center;
- font-family: Montserrat UltraLight;
+ font-family: Roboto;
}
.icon {
@@ -708,7 +786,7 @@ button.first-time-flow__button--tertiary:hover {
.shapeshift-form__deposit-instruction {
color: #757575;
color: rgba(0, 0, 0, 0.45);
- font-family: Montserrat Light;
+ font-family: Roboto;
font-weight: 300;
line-height: 19px;
padding-bottom: 6px;
@@ -725,7 +803,7 @@ button.first-time-flow__button--tertiary:hover {
width: 100%;
height: 45px;
line-height: 44px;
- font-family: Montserrat Light;
+ font-family: Roboto;
}
.shapeshift-form__address-input-label {
@@ -734,7 +812,7 @@ button.first-time-flow__button--tertiary:hover {
font-weight: 500;
line-height: 18px;
padding-bottom: 6px;
- font-family: Montserrat Light;
+ font-family: Roboto;
}
.shapeshift-form__address-input {
@@ -753,7 +831,7 @@ button.first-time-flow__button--tertiary:hover {
.shapeshift-form__address-input-error-message {
color: #FF001F;
- font-family: Montserrat Light;
+ font-family: Roboto;
font-size: 12px;
height: 24px;
line-height: 18px;
@@ -763,7 +841,7 @@ button.first-time-flow__button--tertiary:hover {
display: flex;
flex-flow: row wrap;
color: #9B9B9B;
- font-family: Montserrat Light;
+ font-family: Roboto;
font-size: 10px;
line-height: 16px;
}
diff --git a/package.json b/package.json
index c5d9d3c45..8921cc1b4 100644
--- a/package.json
+++ b/package.json
@@ -6,8 +6,8 @@
"scripts": {
"start": "npm run dev",
"dev": "gulp dev --debug",
- "ui": "npm run test:flat:build:states && beefy ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
- "mock": "beefy mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
+ "ui": "npm run test:flat:build:states && beefy development/ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
+ "mock": "beefy development/mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
"watch": "mocha watch --recursive \"test/unit/**/*.js\"",
"mascara": "gulp build && METAMASK_DEBUG=true node ./mascara/example/server",
"dist": "npm run dist:clear && npm install && gulp dist",
@@ -23,7 +23,7 @@
"test:flat:build": "npm run test:flat:build:ui && npm run test:flat:build:tests",
"test:flat:build:tests": "node test/integration/index.js",
"test:flat:build:states": "node development/genStates.js",
- "test:flat:build:ui": "npm run test:flat:build:states && browserify ./mock-dev.js -o ./development/bundle.js",
+ "test:flat:build:ui": "npm run test:flat:build:states && browserify ./development/mock-dev.js -o ./development/bundle.js",
"test:mascara": "npm run test:mascara:build && karma start test/mascara.conf.js",
"test:mascara:build": "mkdir -p dist/mascara && npm run test:mascara:build:ui && npm run test:mascara:build:background && npm run test:mascara:build:tests",
"test:mascara:build:ui": "browserify mascara/test/test-ui.js -o dist/mascara/ui.js",
diff --git a/test/base.conf.js b/test/base.conf.js
index 82b9d8eec..adb5357e8 100644
--- a/test/base.conf.js
+++ b/test/base.conf.js
@@ -46,7 +46,9 @@ module.exports = function(config) {
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
- browsers: ['Chrome', 'Firefox'],
+ browsers: process.env.browsers ?
+ JSON.parse(process.env.browsers)
+ : ['Chrome', 'Firefox'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
diff --git a/test/integration/index.js b/test/integration/index.js
index 144303dbb..b266ddf37 100644
--- a/test/integration/index.js
+++ b/test/integration/index.js
@@ -23,4 +23,4 @@ pump(
console.log(`Integration test build completed: "${bundlePath}"`)
process.exit(0)
}
-) \ No newline at end of file
+)
diff --git a/test/integration/lib/add-token.js b/test/integration/lib/add-token.js
index dd4251cc4..42ed28dca 100644
--- a/test/integration/lib/add-token.js
+++ b/test/integration/lib/add-token.js
@@ -1,4 +1,9 @@
const reactTriggerChange = require('react-trigger-change')
+const {
+ timeout,
+ queryAsync,
+ findAsync,
+} = require('../../lib/util')
QUnit.module('Add token flow')
@@ -13,74 +18,60 @@ QUnit.test('successful add token flow', (assert) => {
})
async function runAddTokenFlowTest (assert, done) {
- const selectState = $('select')
+ const selectState = await queryAsync($, 'select')
selectState.val('add token')
reactTriggerChange(selectState[0])
- await timeout(2000)
-
// Check that no tokens have been added
assert.ok($('.token-list-item').length === 0, 'no tokens added')
// Go to Add Token screen
- let addTokenButton = $('button.btn-clear.wallet-view__add-token-button')
+ let addTokenButton = await queryAsync($, 'button.btn-clear.wallet-view__add-token-button')
assert.ok(addTokenButton[0], 'add token button present')
addTokenButton[0].click()
- await timeout(1000)
-
// Verify Add Token screen
- let addTokenWrapper = $('.add-token__wrapper')
+ let addTokenWrapper = await queryAsync($, '.add-token__wrapper')
assert.ok(addTokenWrapper[0], 'add token wrapper renders')
- let addTokenTitle = $('.add-token__title')
+ let addTokenTitle = await queryAsync($, '.add-token__title')
assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct')
// Cancel Add Token
- const cancelAddTokenButton = $('button.btn-cancel.add-token__button')
+ const cancelAddTokenButton = await queryAsync($, 'button.btn-cancel.add-token__button')
assert.ok(cancelAddTokenButton[0], 'cancel add token button present')
cancelAddTokenButton.click()
- await timeout(1000)
-
assert.ok($('.wallet-view')[0], 'cancelled and returned to account detail wallet view')
// Return to Add Token Screen
- addTokenButton = $('button.btn-clear.wallet-view__add-token-button')
+ addTokenButton = await queryAsync($, 'button.btn-clear.wallet-view__add-token-button')
assert.ok(addTokenButton[0], 'add token button present')
addTokenButton[0].click()
- await timeout(1000)
-
// Verify Add Token Screen
- addTokenWrapper = $('.add-token__wrapper')
- addTokenTitle = $('.add-token__title')
+ addTokenWrapper = await queryAsync($, '.add-token__wrapper')
+ addTokenTitle = await queryAsync($, '.add-token__title')
assert.ok(addTokenWrapper[0], 'add token wrapper renders')
assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct')
// Search for token
- const searchInput = $('input.add-token__input')
+ const searchInput = await queryAsync($, 'input.add-token__input')
searchInput.val('a')
reactTriggerChange(searchInput[0])
- await timeout()
-
// Click token to add
- const tokenWrapper = $('div.add-token__token-wrapper')
+ const tokenWrapper = await queryAsync($, 'div.add-token__token-wrapper')
assert.ok(tokenWrapper[0], 'token found')
const tokenImageProp = tokenWrapper.find('.add-token__token-icon').css('background-image')
const tokenImageUrl = tokenImageProp.slice(5, -2)
tokenWrapper[0].click()
- await timeout()
-
// Click Next button
- let nextButton = $('button.btn-clear.add-token__button')
+ let nextButton = await queryAsync($, 'button.btn-clear.add-token__button')
assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
nextButton[0].click()
- await timeout()
-
// Confirm Add token
assert.equal(
$('.add-token__description')[0].textContent,
@@ -90,47 +81,35 @@ async function runAddTokenFlowTest (assert, done) {
assert.ok($('button.btn-clear.add-token__button')[0], 'confirm add token button found')
$('button.btn-clear.add-token__button')[0].click()
- await timeout(2000)
-
// Verify added token image
- let heroBalance = $('.hero-balance')
+ let heroBalance = await queryAsync($, '.hero-balance')
assert.ok(heroBalance, 'rendered hero balance')
assert.ok(tokenImageUrl.indexOf(heroBalance.find('img').attr('src')) > -1, 'token added')
// Return to Add Token Screen
- addTokenButton = $('button.btn-clear.wallet-view__add-token-button')
+ addTokenButton = await queryAsync($, 'button.btn-clear.wallet-view__add-token-button')
assert.ok(addTokenButton[0], 'add token button present')
addTokenButton[0].click()
- await timeout(1000)
-
- const addCustom = $('.add-token__add-custom')
+ const addCustom = await queryAsync($, '.add-token__add-custom')
assert.ok(addCustom[0], 'add custom token button present')
addCustom[0].click()
- await timeout()
-
// Input token contract address
- const customInput = $('input.add-token__add-custom-input')
+ const customInput = await queryAsync($, 'input.add-token__add-custom-input')
customInput.val('0x177af043D3A1Aed7cc5f2397C70248Fc6cDC056c')
reactTriggerChange(customInput[0])
- await timeout(1000)
-
// Click Next button
- nextButton = $('button.btn-clear.add-token__button')
+ nextButton = await queryAsync($, 'button.btn-clear.add-token__button')
assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
nextButton[0].click()
- await timeout(1000)
-
// Verify symbol length error since contract address won't return symbol
- const errorMessage = $('.add-token__add-custom-error-message')
+ const errorMessage = await queryAsync($, '.add-token__add-custom-error-message')
assert.ok(errorMessage[0], 'error rendered')
$('button.btn-cancel.add-token__button')[0].click()
- await timeout(2000)
-
// // Confirm Add token
// assert.equal(
// $('.add-token__description')[0].textContent,
@@ -141,13 +120,7 @@ async function runAddTokenFlowTest (assert, done) {
// $('button.btn-clear.add-token__button')[0].click()
// // Verify added token image
- // heroBalance = $('.hero-balance')
+ // heroBalance = await queryAsync($, '.hero-balance')
// assert.ok(heroBalance, 'rendered hero balance')
// assert.ok(heroBalance.find('.identicon')[0], 'token added')
}
-
-function timeout (time) {
- return new Promise((resolve, reject) => {
- setTimeout(resolve, time || 1500)
- })
-}
diff --git a/test/integration/lib/confirm-sig-requests.js b/test/integration/lib/confirm-sig-requests.js
index e49424c37..9737a2283 100644
--- a/test/integration/lib/confirm-sig-requests.js
+++ b/test/integration/lib/confirm-sig-requests.js
@@ -1,5 +1,9 @@
const reactTriggerChange = require('react-trigger-change')
-
+const {
+ timeout,
+ queryAsync,
+ findAsync,
+} = require('../../lib/util')
const PASSWORD = 'password123'
QUnit.module('confirm sig requests')
@@ -13,55 +17,41 @@ QUnit.test('successful confirmation of sig requests', (assert) => {
})
async function runConfirmSigRequestsTest(assert, done) {
- let selectState = $('select')
+ let selectState = await queryAsync($, 'select')
selectState.val('confirm sig requests')
reactTriggerChange(selectState[0])
- await timeout(2000)
-
- let confirmSigHeadline = $('.request-signature__headline')
+ let confirmSigHeadline = await queryAsync($, '.request-signature__headline')
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
- let confirmSigRowValue = $('.request-signature__row-value')
+ let confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/))
- let confirmSigSignButton = $('.request-signature__footer__sign-button')
+ let confirmSigSignButton = await queryAsync($, '.request-signature__footer__sign-button')
confirmSigSignButton[0].click()
- await timeout(2000)
-
- confirmSigHeadline = $('.request-signature__headline')
+ confirmSigHeadline = await queryAsync($, '.request-signature__headline')
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
- let confirmSigMessage = $('.request-signature__notice')
+ let confirmSigMessage = await queryAsync($, '.request-signature__notice')
assert.ok(confirmSigMessage[0].textContent.match(/^Signing\sthis\smessage/))
- confirmSigRowValue = $('.request-signature__row-value')
+ confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0')
- confirmSigSignButton = $('.request-signature__footer__sign-button')
+ confirmSigSignButton = await queryAsync($, '.request-signature__footer__sign-button')
confirmSigSignButton[0].click()
- await timeout(2000)
-
- confirmSigHeadline = $('.request-signature__headline')
+ confirmSigHeadline = await queryAsync($, '.request-signature__headline')
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
- confirmSigRowValue = $('.request-signature__row-value')
+ confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
assert.equal(confirmSigRowValue[0].textContent, 'Hi, Alice!')
assert.equal(confirmSigRowValue[1].textContent, '1337')
- confirmSigSignButton = $('.request-signature__footer__sign-button')
+ confirmSigSignButton = await queryAsync($, '.request-signature__footer__sign-button')
confirmSigSignButton[0].click()
- await timeout(2000)
-
- const txView = $('.tx-view')
+ const txView = await queryAsync($, '.tx-view')
assert.ok(txView[0], 'Should return to the account details screen after confirming')
}
-
-function timeout (time) {
- return new Promise((resolve, reject) => {
- setTimeout(resolve, time || 1500)
- })
-} \ No newline at end of file
diff --git a/test/integration/lib/first-time.js b/test/integration/lib/first-time.js
index 764eae47c..052d89518 100644
--- a/test/integration/lib/first-time.js
+++ b/test/integration/lib/first-time.js
@@ -1,6 +1,10 @@
const reactTriggerChange = require('react-trigger-change')
const PASSWORD = 'password123'
const runMascaraFirstTimeTest = require('./mascara-first-time')
+const {
+ timeout,
+ findAsync,
+} = require('../../lib/util')
QUnit.module('first time usage')
@@ -21,20 +25,19 @@ async function runFirstTimeUsageTest(assert, done) {
selectState.val('first time')
reactTriggerChange(selectState[0])
- await timeout(2000)
const app = $('#app-content')
// recurse notices
while (true) {
- const button = app.find('button')
+ const button = await findAsync(app, 'button')
if (button.html() === 'Accept') {
// still notices to accept
- const termsPage = app.find('.markdown')[0]
+ const termsPageRaw = await findAsync(app, '.markdown')
+ const termsPage = (await findAsync(app, '.markdown'))[0]
+ console.log('termsPageRaw', termsPageRaw)
termsPage.scrollTop = termsPage.scrollHeight
- await timeout()
console.log('Clearing notice')
button.click()
- await timeout()
} else {
// exit loop
console.log('No more notices...')
@@ -42,97 +45,68 @@ async function runFirstTimeUsageTest(assert, done) {
}
}
- await timeout()
-
// Scroll through terms
- const title = app.find('h1')[0]
+ const title = (await findAsync(app, 'h1'))[0]
assert.equal(title.textContent, 'MetaMask', 'title screen')
// enter password
- const pwBox = app.find('#password-box')[0]
- const confBox = app.find('#password-box-confirm')[0]
+ const pwBox = (await findAsync(app, '#password-box'))[0]
+ const confBox = (await findAsync(app, '#password-box-confirm'))[0]
pwBox.value = PASSWORD
confBox.value = PASSWORD
- await timeout()
-
// create vault
- const createButton = app.find('button.primary')[0]
+ const createButton = (await findAsync(app, 'button.primary'))[0]
createButton.click()
- await timeout(3000)
-
- const created = app.find('h3')[0]
+ await timeout()
+ const created = (await findAsync(app, 'h3'))[0]
assert.equal(created.textContent, 'Vault Created', 'Vault created screen')
// Agree button
- const button = app.find('button')[0]
+ const button = (await findAsync(app, 'button'))[0]
assert.ok(button, 'button present')
button.click()
- await timeout(1000)
-
- const detail = app.find('.account-detail-section')[0]
+ const detail = (await findAsync(app, '.account-detail-section'))[0]
assert.ok(detail, 'Account detail section loaded.')
- const sandwich = app.find('.sandwich-expando')[0]
+ const sandwich = (await findAsync(app, '.sandwich-expando'))[0]
sandwich.click()
- await timeout()
-
- const menu = app.find('.menu-droppo')[0]
+ const menu = (await findAsync(app, '.menu-droppo'))[0]
const children = menu.children
const logout = children[2]
assert.ok(logout, 'Lock menu item found')
logout.click()
- await timeout(1000)
-
- const pwBox2 = app.find('#password-box')[0]
+ const pwBox2 = (await findAsync(app, '#password-box'))[0]
pwBox2.value = PASSWORD
- const createButton2 = app.find('button.primary')[0]
+ const createButton2 = (await findAsync(app, 'button.primary'))[0]
createButton2.click()
- await timeout(1000)
-
- const detail2 = app.find('.account-detail-section')[0]
+ const detail2 = (await findAsync(app, '.account-detail-section'))[0]
assert.ok(detail2, 'Account detail section loaded again.')
- await timeout()
-
// open account settings dropdown
- const qrButton = app.find('.fa.fa-ellipsis-h')[0]
+ const qrButton = (await findAsync(app, '.fa.fa-ellipsis-h'))[0]
qrButton.click()
- await timeout(1000)
-
// qr code item
- const qrButton2 = app.find('.dropdown-menu-item')[1]
+ const qrButton2 = (await findAsync(app, '.dropdown-menu-item'))[1]
qrButton2.click()
- await timeout(1000)
-
- const qrHeader = app.find('.qr-header')[0]
- const qrContainer = app.find('#qr-container')[0]
+ const qrHeader = (await findAsync(app, '.qr-header'))[0]
+ const qrContainer = (await findAsync(app, '#qr-container'))[0]
assert.equal(qrHeader.textContent, 'Account 1', 'Should show account label.')
assert.ok(qrContainer, 'QR Container found')
- await timeout()
-
- const networkMenu = app.find('.network-indicator')[0]
+ const networkMenu = (await findAsync(app, '.network-indicator'))[0]
networkMenu.click()
- await timeout()
-
- const networkMenu2 = app.find('.network-indicator')[0]
+ const networkMenu2 = (await findAsync(app, '.network-indicator'))[0]
const children2 = networkMenu2.children
children2.length[3]
assert.ok(children2, 'All network options present')
}
-
-function timeout (time) {
- return new Promise((resolve, reject) => {
- setTimeout(resolve, time || 1500)
- })
-} \ No newline at end of file
diff --git a/test/integration/lib/mascara-first-time.js b/test/integration/lib/mascara-first-time.js
index 515c7f383..bcbc94ff6 100644
--- a/test/integration/lib/mascara-first-time.js
+++ b/test/integration/lib/mascara-first-time.js
@@ -1,119 +1,95 @@
const PASSWORD = 'password123'
const reactTriggerChange = require('react-trigger-change')
+const {
+ timeout,
+ findAsync,
+ queryAsync,
+} = require('../../lib/util')
async function runFirstTimeUsageTest (assert, done) {
await timeout(4000)
- const app = $('#app-content')
+ const app = await queryAsync($, '#app-content')
await skipNotices(app)
- await timeout()
-
// Scroll through terms
- const title = app.find('.create-password__title').text()
+ const title = (await findAsync(app, '.create-password__title')).text()
assert.equal(title, 'Create Password', 'create password screen')
// enter password
- const pwBox = app.find('.first-time-flow__input')[0]
- const confBox = app.find('.first-time-flow__input')[1]
+ const pwBox = (await findAsync(app, '.first-time-flow__input'))[0]
+ const confBox = (await findAsync(app, '.first-time-flow__input'))[1]
pwBox.value = PASSWORD
confBox.value = PASSWORD
reactTriggerChange(pwBox)
reactTriggerChange(confBox)
-
- await timeout()
-
// Create Password
- const createButton = app.find('button.first-time-flow__button')[0]
+ const createButton = (await findAsync(app, 'button.first-time-flow__button'))[0]
createButton.click()
- await timeout(3000)
-
- const created = app.find('.unique-image__title')[0]
+ const created = (await findAsync(app, '.unique-image__title'))[0]
assert.equal(created.textContent, 'Your unique account image', 'unique image screen')
// Agree button
- let button = app.find('button')[0]
+ let button = (await findAsync(app, 'button'))[0]
assert.ok(button, 'button present')
button.click()
- await timeout(1000)
-
await skipNotices(app)
// secret backup phrase
- const seedTitle = app.find('.backup-phrase__title')[0]
+ const seedTitle = (await findAsync(app, '.backup-phrase__title'))[0]
assert.equal(seedTitle.textContent, 'Secret Backup Phrase', 'seed phrase screen')
- app.find('.backup-phrase__reveal-button').click()
-
- await timeout(1000)
- const seedPhrase = app.find('.backup-phrase__secret-words').text().split(' ')
- app.find('.first-time-flow__button').click()
+ ;(await findAsync(app, '.backup-phrase__reveal-button')).click()
+ const seedPhrase = (await findAsync(app, '.backup-phrase__secret-words')).text().split(' ')
+ ;(await findAsync(app, '.first-time-flow__button')).click()
+ await timeout()
const selectPhrase = text => {
const option = $('.backup-phrase__confirm-seed-option')
.filter((i, d) => d.textContent === text)[0]
-
$(option).click()
}
- await timeout(1000)
-
seedPhrase.forEach(sp => selectPhrase(sp))
- app.find('.first-time-flow__button').click()
- await timeout(1000)
+ ;(await findAsync(app, '.first-time-flow__button')).click()
// Deposit Ether Screen
- const buyEthTitle = app.find('.buy-ether__title')[0]
+ const buyEthTitle = (await findAsync(app, '.buy-ether__title'))[0]
assert.equal(buyEthTitle.textContent, 'Deposit Ether', 'deposit ether screen')
- app.find('.buy-ether__do-it-later').click()
- await timeout(1000)
+ ;(await findAsync(app, '.buy-ether__do-it-later')).click()
- const menu = app.find('.account-menu__icon')[0]
+ const menu = (await findAsync(app, '.account-menu__icon'))[0]
menu.click()
- await timeout()
-
- const lock = app.find('.account-menu__logout-button')[0]
+ const lock = (await findAsync(app, '.account-menu__logout-button'))[0]
assert.ok(lock, 'Lock menu item found')
lock.click()
- await timeout(1000)
-
- const pwBox2 = app.find('#password-box')[0]
+ const pwBox2 = (await findAsync(app, '#password-box'))[0]
pwBox2.value = PASSWORD
- const createButton2 = app.find('button.primary')[0]
+ const createButton2 = (await findAsync(app, 'button.primary'))[0]
createButton2.click()
- await timeout(1000)
-
- const detail2 = app.find('.wallet-view')[0]
+ const detail2 = (await findAsync(app, '.wallet-view'))[0]
assert.ok(detail2, 'Account detail section loaded again.')
- await timeout()
-
// open account settings dropdown
- const qrButton = app.find('.wallet-view__details-button')[0]
+ const qrButton = (await findAsync(app, '.wallet-view__details-button'))[0]
qrButton.click()
- await timeout(1000)
-
- const qrHeader = app.find('.editable-label__value')[0]
- const qrContainer = app.find('.qr-wrapper')[0]
+ const qrHeader = (await findAsync(app, '.editable-label__value'))[0]
+ const qrContainer = (await findAsync(app, '.qr-wrapper'))[0]
assert.equal(qrHeader.textContent, 'Account 1', 'Should show account label.')
assert.ok(qrContainer, 'QR Container found')
- await timeout()
-
- const networkMenu = app.find('.network-component')[0]
+ const networkMenu = (await findAsync(app, '.network-component'))[0]
networkMenu.click()
- await timeout()
-
- const networkMenu2 = app.find('.network-indicator')[0]
+ const networkMenu2 = (await findAsync(app, '.network-indicator'))[0]
const children2 = networkMenu2.children
children2.length[3]
assert.ok(children2, 'All network options present')
@@ -121,18 +97,12 @@ async function runFirstTimeUsageTest (assert, done) {
module.exports = runFirstTimeUsageTest
-function timeout (time) {
- return new Promise((resolve, reject) => {
- setTimeout(resolve, time || 1500)
- })
-}
-
async function skipNotices (app) {
while (true) {
- const button = app.find('button')
+ const button = await findAsync(app, 'button')
if (button && button.html() === 'Accept') {
// still notices to accept
- const termsPage = app.find('.markdown')[0]
+ const termsPage = (await findAsync(app, '.markdown'))[0]
if (!termsPage) {
break
}
diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js
index 3456f2367..faab10fdf 100644
--- a/test/integration/lib/send-new-ui.js
+++ b/test/integration/lib/send-new-ui.js
@@ -1,4 +1,9 @@
const reactTriggerChange = require('react-trigger-change')
+const {
+ timeout,
+ queryAsync,
+ findAsync,
+} = require('../../lib/util')
const PASSWORD = 'password123'
@@ -18,83 +23,65 @@ global.ethQuery = {
async function runSendFlowTest(assert, done) {
console.log('*** start runSendFlowTest')
- const selectState = $('select')
+ const selectState = await queryAsync($, 'select')
selectState.val('send new ui')
reactTriggerChange(selectState[0])
- await timeout(2000)
-
- const sendScreenButton = $('button.btn-clear.hero-balance-button')
+ const sendScreenButton = await queryAsync($, 'button.btn-clear.hero-balance-button')
assert.ok(sendScreenButton[1], 'send screen button present')
sendScreenButton[1].click()
- await timeout(1000)
-
- const sendTitle = $('.page-container__title')
+ const sendTitle = await queryAsync($, '.page-container__title')
assert.equal(sendTitle[0].textContent, 'Send ETH', 'Send screen title is correct')
- const sendCopy = $('.page-container__subtitle')
+ const sendCopy = await queryAsync($, '.page-container__subtitle')
assert.equal(sendCopy[0].textContent, 'Only send ETH to an Ethereum address.', 'Send screen has copy')
- const sendFromField = $('.send-v2__form-field')
+ const sendFromField = await queryAsync($, '.send-v2__form-field')
assert.ok(sendFromField[0], 'send screen has a from field')
- let sendFromFieldItemAddress = $('.account-list-item__account-name')
+ let sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 4', 'send from field shows correct account name')
- const sendFromFieldItem = $('.account-list-item')
+ const sendFromFieldItem = await queryAsync($, '.account-list-item')
sendFromFieldItem[0].click()
- await timeout()
-
- const sendFromDropdownList = $('.send-v2__from-dropdown__list')
+ // this seems to fail if the firefox window is not in focus...
+ const sendFromDropdownList = await queryAsync($, '.send-v2__from-dropdown__list')
assert.equal(sendFromDropdownList.children().length, 4, 'send from dropdown shows all accounts')
- console.log(`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sendFromDropdownList.children()[1]`, sendFromDropdownList.children()[1]);
sendFromDropdownList.children()[1].click()
- await timeout()
-
- sendFromFieldItemAddress = $('.account-list-item__account-name')
- console.log(`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sendFromFieldItemAddress[0]`, sendFromFieldItemAddress[0]);
+ sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 2', 'send from field dropdown changes account name')
- let sendToFieldInput = $('.send-v2__to-autocomplete__input')
+ let sendToFieldInput = await queryAsync($, '.send-v2__to-autocomplete__input')
sendToFieldInput[0].focus()
- await timeout()
-
- const sendToDropdownList = $('.send-v2__from-dropdown__list')
+ const sendToDropdownList = await queryAsync($, '.send-v2__from-dropdown__list')
assert.equal(sendToDropdownList.children().length, 5, 'send to dropdown shows all accounts and address book accounts')
sendToDropdownList.children()[2].click()
- await timeout()
-
const sendToAccountAddress = sendToFieldInput.val()
assert.equal(sendToAccountAddress, '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', 'send to dropdown selects the correct address')
- const sendAmountField = $('.send-v2__form-row:eq(2)')
+ const sendAmountField = await queryAsync($, '.send-v2__form-row:eq(2)')
sendAmountField.find('.currency-display')[0].click()
- await timeout()
-
- const sendAmountFieldInput = sendAmountField.find('input:text')
+ const sendAmountFieldInput = await findAsync(sendAmountField, 'input:text')
sendAmountFieldInput.val('5.1')
reactTriggerChange(sendAmountField.find('input')[0])
- await timeout()
-
- let errorMessage = $('.send-v2__error')
+ let errorMessage = await queryAsync($, '.send-v2__error')
assert.equal(errorMessage[0].textContent, 'Insufficient funds.', 'send should render an insufficient fund error message')
sendAmountFieldInput.val('2.0')
reactTriggerChange(sendAmountFieldInput[0])
-
await timeout()
errorMessage = $('.send-v2__error')
assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected')
- const sendGasField = $('.send-v2__gas-fee-display')
+ const sendGasField = await queryAsync($, '.send-v2__gas-fee-display')
assert.equal(
sendGasField.find('.currency-display__input-wrapper > input').val(),
'0.000198',
@@ -106,120 +93,86 @@ async function runSendFlowTest(assert, done) {
'send gas field should show estimated gas total converted to USD'
)
- const sendGasOpenCustomizeModalButton = $('.send-v2__sliders-icon-container'
- )
+ const sendGasOpenCustomizeModalButton = await queryAsync($, '.send-v2__sliders-icon-container')
sendGasOpenCustomizeModalButton[0].click()
- await timeout(1000)
-
- const customizeGasModal = $('.send-v2__customize-gas')
+ const customizeGasModal = await queryAsync($, '.send-v2__customize-gas')
assert.ok(customizeGasModal[0], 'should render the customize gas modal')
- const customizeGasPriceInput = $('.send-v2__gas-modal-card').first().find('input')
+ const customizeGasPriceInput = (await queryAsync($, '.send-v2__gas-modal-card')).first().find('input')
customizeGasPriceInput.val(50)
reactTriggerChange(customizeGasPriceInput[0])
- const customizeGasLimitInput = $('.send-v2__gas-modal-card').last().find('input')
+ const customizeGasLimitInput = (await queryAsync($, '.send-v2__gas-modal-card')).last().find('input')
customizeGasLimitInput.val(60000)
reactTriggerChange(customizeGasLimitInput[0])
- await timeout()
-
- const customizeGasSaveButton = $('.send-v2__customize-gas__save')
+ const customizeGasSaveButton = await queryAsync($, '.send-v2__customize-gas__save')
customizeGasSaveButton[0].click()
- await timeout()
-
assert.equal(
- sendGasField.find('.currency-display__input-wrapper > input').val(),
+ (await findAsync(sendGasField, '.currency-display__input-wrapper > input')).val(),
'0.003',
'send gas field should show customized gas total'
)
assert.equal(
- sendGasField.find('.currency-display__converted-value')[0].textContent,
+ (await findAsync(sendGasField, '.currency-display__converted-value'))[0].textContent,
'3.60 USD',
'send gas field should show customized gas total converted to USD'
)
- const sendButton = $('button.btn-clear.page-container__footer-button')
+ const sendButton = await queryAsync($, 'button.btn-clear.page-container__footer-button')
assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
sendButton[0].click()
-
- await timeout(2000)
+ await timeout()
selectState.val('send edit')
reactTriggerChange(selectState[0])
- await timeout(2000)
-
- const confirmFromName = $('.confirm-screen-account-name').first()
+ const confirmFromName = (await queryAsync($, '.confirm-screen-account-name')).first()
assert.equal(confirmFromName[0].textContent, 'Send Account 2', 'confirm screen should show correct from name')
- const confirmToName = $('.confirm-screen-account-name').last()
+ const confirmToName = (await queryAsync($, '.confirm-screen-account-name')).last()
assert.equal(confirmToName[0].textContent, 'Send Account 3', 'confirm screen should show correct to name')
- const confirmScreenRows = $('.confirm-screen-rows')
+ const confirmScreenRows = await queryAsync($, '.confirm-screen-rows')
const confirmScreenGas = confirmScreenRows.find('.confirm-screen-row-info')[2]
assert.equal(confirmScreenGas.textContent, '3.6 USD', 'confirm screen should show correct gas')
const confirmScreenTotal = confirmScreenRows.find('.confirm-screen-row-info')[3]
assert.equal(confirmScreenTotal.textContent, '2405.36 USD', 'confirm screen should show correct total')
- const confirmScreenBackButton = $('.confirm-screen-back-button')
+ const confirmScreenBackButton = await queryAsync($, '.confirm-screen-back-button')
confirmScreenBackButton[0].click()
- await timeout(1000)
-
- const sendFromFieldItemInEdit = $('.account-list-item')
+ const sendFromFieldItemInEdit = await queryAsync($, '.account-list-item')
sendFromFieldItemInEdit[0].click()
- await timeout()
-
- const sendFromDropdownListInEdit = $('.send-v2__from-dropdown__list')
+ const sendFromDropdownListInEdit = await queryAsync($, '.send-v2__from-dropdown__list')
sendFromDropdownListInEdit.children()[2].click()
- await timeout()
-
- const sendToFieldInputInEdit = $('.send-v2__to-autocomplete__input')
+ const sendToFieldInputInEdit = await queryAsync($, '.send-v2__to-autocomplete__input')
sendToFieldInputInEdit[0].focus()
sendToFieldInputInEdit.val('0xd85a4b6a394794842887b8284293d69163007bbb')
- await timeout()
-
- const sendAmountFieldInEdit = $('.send-v2__form-row:eq(2)')
+ const sendAmountFieldInEdit = await queryAsync($, '.send-v2__form-row:eq(2)')
sendAmountFieldInEdit.find('.currency-display')[0].click()
- await timeout()
-
const sendAmountFieldInputInEdit = sendAmountFieldInEdit.find('input:text')
sendAmountFieldInputInEdit.val('1.0')
reactTriggerChange(sendAmountFieldInputInEdit[0])
- await timeout()
-
- const sendButtonInEdit = $('.btn-clear.page-container__footer-button')
+ const sendButtonInEdit = await queryAsync($, '.btn-clear.page-container__footer-button')
assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered')
sendButtonInEdit[0].click()
- await timeout()
-
// TODO: Need a way to mock background so that we can test correct transition from editing to confirm
selectState.val('confirm new ui')
reactTriggerChange(selectState[0])
-
- await timeout(2000)
- const confirmScreenConfirmButton = $('.confirm-screen-confirm-button')
+ const confirmScreenConfirmButton = await queryAsync($, '.confirm-screen-confirm-button')
console.log(`+++++++++++++++++++++++++++++++= confirmScreenConfirmButton[0]`, confirmScreenConfirmButton[0]);
confirmScreenConfirmButton[0].click()
- await timeout(2000)
-
- const txView = $('.tx-view')
+ const txView = await queryAsync($, '.tx-view')
console.log(`++++++++++++++++++++++++++++++++ txView[0]`, txView[0]);
assert.ok(txView[0], 'Should return to the account details screen after confirming')
}
-
-function timeout (time) {
- return new Promise((resolve, reject) => {
- setTimeout(resolve, time || 1500)
- })
-} \ No newline at end of file
diff --git a/test/lib/util.js b/test/lib/util.js
new file mode 100644
index 000000000..626280745
--- /dev/null
+++ b/test/lib/util.js
@@ -0,0 +1,53 @@
+module.exports = {
+ timeout,
+ queryAsync,
+ findAsync,
+ pollUntilTruthy,
+}
+
+function timeout (time) {
+ return new Promise((resolve, reject) => {
+ setTimeout(resolve, time || 1500)
+ })
+}
+
+async function findAsync(container, selector, opts) {
+ try {
+ return await pollUntilTruthy(() => {
+ const result = container.find(selector)
+ if (result.length > 0) return result
+ }, opts)
+ } catch (err) {
+ throw new Error(`Failed to find element within interval: "${selector}"`)
+ }
+}
+
+async function queryAsync(jQuery, selector, opts) {
+ try {
+ return await pollUntilTruthy(() => {
+ const result = jQuery(selector)
+ if (result.length > 0) return result
+ }, opts)
+ } catch (err) {
+ throw new Error(`Failed to find element within interval: "${selector}"`)
+ }
+}
+
+async function pollUntilTruthy(fn, opts = {}){
+ const pollingInterval = opts.pollingInterval || 100
+ const timeoutInterval = opts.timeoutInterval || 5000
+ const start = Date.now()
+ let result
+ while (!result) {
+ // check if timedout
+ const now = Date.now()
+ if ((now - start) > timeoutInterval) {
+ throw new Error(`pollUntilTruthy - failed to return truthy within interval`)
+ }
+ // check for result
+ result = fn()
+ // run again after timeout
+ await timeout(pollingInterval, timeoutInterval)
+ }
+ return result
+}
diff --git a/ui/app/actions.js b/ui/app/actions.js
index b56265edc..092af080b 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -75,6 +75,8 @@ var actions = {
resetAccount,
showNewVaultSeed: showNewVaultSeed,
showInfoPage: showInfoPage,
+ CLOSE_WELCOME_SCREEN: 'CLOSE_WELCOME_SCREEN',
+ closeWelcomeScreen,
// seed recovery actions
REVEAL_SEED_CONFIRMATION: 'REVEAL_SEED_CONFIRMATION',
revealSeedConfirmation: revealSeedConfirmation,
@@ -788,7 +790,7 @@ function updateTransaction (txData) {
function updateAndApproveTx (txData) {
log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData))
return (dispatch) => {
- log.debug(`actions calling background.updateAndApproveTx`)
+ log.debug(`actions calling background.updateAndApproveTx.`)
background.updateAndApproveTransaction(txData, (err) => {
dispatch(actions.hideLoadingIndication())
dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
@@ -947,6 +949,12 @@ function showNewVaultSeed (seed) {
}
}
+function closeWelcomeScreen () {
+ return {
+ type: actions.CLOSE_WELCOME_SCREEN,
+ }
+}
+
function backToUnlockView () {
return {
type: actions.BACK_TO_UNLOCK_VIEW,
diff --git a/ui/app/app.js b/ui/app/app.js
index 8511ee396..9708a2485 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -13,6 +13,8 @@ const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ethe
const OldUIInitializeMenuScreen = require('./first-time/init-menu')
const InitializeMenuScreen = MascaraFirstTime
const NewKeyChainScreen = require('./new-keychain')
+const WelcomeScreen = require('./welcome-screen').default
+
// accounts
const MainContainer = require('./main-container')
const SendTransactionScreen2 = require('./components/send/send-v2-container')
@@ -92,6 +94,7 @@ function mapStateToProps (state) {
betaUI: state.metamask.featureFlags.betaUI,
isRevealingSeedWords: state.metamask.isRevealingSeedWords,
Qr: state.appState.Qr,
+ welcomeScreenSeen: state.metamask.welcomeScreenSeen,
// state needed to get account dropdown temporarily rendering from app bar
identities,
@@ -245,6 +248,7 @@ App.prototype.renderAppBar = function () {
isInitialized,
betaUI,
isPopup,
+ welcomeScreenSeen,
} = this.props
if (window.METAMASK_UI_TYPE === 'notification') {
@@ -270,7 +274,7 @@ App.prototype.renderAppBar = function () {
style: {},
}, [
- h('.app-header.flex-row.flex-space-between', {
+ (isInitialized || welcomeScreenSeen || isPopup || !betaUI) && h('.app-header.flex-row.flex-space-between', {
className: classnames({
'app-header--initialized': !isOnboarding,
}),
@@ -295,7 +299,7 @@ App.prototype.renderAppBar = function () {
]),
]),
- h('div.header__right-actions', [
+ betaUI && isInitialized && h('div.header__right-actions', [
h('div.network-component-wrapper', {
style: {},
}, [
@@ -325,8 +329,12 @@ App.prototype.renderAppBar = function () {
]),
]),
- !isInitialized && !isPopup && betaUI && h('h2.alpha-warning',
- 'Please be aware that this version is still under development'),
+ !isInitialized && !isPopup && betaUI && h('h2', {
+ className: classnames({
+ 'alpha-warning': welcomeScreenSeen,
+ 'alpha-warning-welcome-screen': !welcomeScreenSeen,
+ }),
+ }, 'Please be aware that this version is still under development'),
])
)
@@ -370,11 +378,18 @@ App.prototype.renderPrimary = function () {
isOnboarding,
betaUI,
isRevealingSeedWords,
+ welcomeScreenSeen,
Qr,
+ isInitialized,
+ isUnlocked,
} = props
const isMascaraOnboarding = isMascara && isOnboarding
const isBetaUIOnboarding = betaUI && isOnboarding && !props.isPopup && !isRevealingSeedWords
+ if (!welcomeScreenSeen && betaUI && !isInitialized && !isUnlocked) {
+ return h(WelcomeScreen)
+ }
+
if (isMascaraOnboarding || isBetaUIOnboarding) {
return h(MascaraFirstTime)
}
diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js
index 85892b93b..96d776270 100644
--- a/ui/app/components/tx-view.js
+++ b/ui/app/components/tx-view.js
@@ -101,9 +101,10 @@ TxView.prototype.render = function () {
h('div.flex-row.phone-visible', {
style: {
- margin: '1.5em 1.2em 0',
justifyContent: 'space-between',
alignItems: 'center',
+ flex: '0 0 auto',
+ margin: '10px',
},
}, [
@@ -111,11 +112,10 @@ TxView.prototype.render = function () {
style: {
fontSize: '1.3em',
cursor: 'pointer',
+ padding: '10px',
},
- onClick: () => {
- this.props.sidebarOpen ? this.props.hideSidebar() : this.props.showSidebar()
- },
- }, []),
+ onClick: () => this.props.sidebarOpen ? this.props.hideSidebar() : this.props.showSidebar(),
+ }),
h('.identicon-wrapper.select-none', {
style: {
diff --git a/ui/app/css/itcss/components/hero-balance.scss b/ui/app/css/itcss/components/hero-balance.scss
index 4af0c2c55..a3f051361 100644
--- a/ui/app/css/itcss/components/hero-balance.scss
+++ b/ui/app/css/itcss/components/hero-balance.scss
@@ -5,9 +5,6 @@
flex-direction: column;
justify-content: flex-start;
align-items: center;
- margin: .3em .9em 0;
- // height: 80vh;
- // max-height: 225px;
flex: 0 0 auto;
}
diff --git a/ui/app/css/itcss/components/index.scss b/ui/app/css/itcss/components/index.scss
index 0219f9fb2..f107b7aca 100644
--- a/ui/app/css/itcss/components/index.scss
+++ b/ui/app/css/itcss/components/index.scss
@@ -55,3 +55,6 @@
@import './new-account.scss';
@import './tooltip.scss';
+
+@import './welcome-screen.scss';
+
diff --git a/ui/app/css/itcss/components/newui-sections.scss b/ui/app/css/itcss/components/newui-sections.scss
index ecf5e1036..5cdda5e6c 100644
--- a/ui/app/css/itcss/components/newui-sections.scss
+++ b/ui/app/css/itcss/components/newui-sections.scss
@@ -51,6 +51,7 @@ $wallet-view-bg: $alabaster;
cursor: pointer;
display: flex;
justify-content: center;
+ padding: 10px;
}
// wallet view and sidebar
@@ -291,7 +292,6 @@ $wallet-view-bg: $alabaster;
padding-right: 6px;
}
-
// first time
.first-view-main {
display: flex;
@@ -313,4 +313,23 @@ $wallet-view-bg: $alabaster;
@media screen and (min-width: 1281px) {
width: 62vw;
}
-} \ No newline at end of file
+}
+
+.unlock-screen-container {
+ z-index: $main-container-z-index;
+ font-family: Roboto;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex: 1 0 auto;
+ background: #f7f7f7;
+ width: 100%;
+}
+
+.unlock-screen {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ flex: 1 0 auto;
+}
diff --git a/ui/app/css/itcss/components/welcome-screen.scss b/ui/app/css/itcss/components/welcome-screen.scss
new file mode 100644
index 000000000..bfd174ad9
--- /dev/null
+++ b/ui/app/css/itcss/components/welcome-screen.scss
@@ -0,0 +1,59 @@
+.welcome-screen {
+ display: flex;
+ flex-flow: column;
+ justify-content: center;
+ align-items: center;
+ font-family: Roboto;
+ font-weight: 400;
+ width: 100%;
+ flex: 1 0 auto;
+ padding: 70px 0;
+ background: $white;
+
+ @media screen and (max-width: 575px) {
+ padding: 0;
+ }
+
+ &__info {
+ display: flex;
+ flex-flow: column;
+ width: 100%;
+ height: 100%;
+ align-items: center;
+
+ &__header {
+ font-size: 1.65em;
+ margin-bottom: 14px;
+
+ @media screen and (max-width: 575px) {
+ font-size: 1.5em;
+ }
+ }
+
+ &__copy {
+ font-size: 1em;
+ width: 400px;
+ max-width: 90vw;
+ text-align: center;
+
+ @media screen and (max-width: 575px) {
+ font-size: 0.9em;
+ }
+ }
+ }
+
+ &__button {
+ height: 54px;
+ width: 198px;
+ box-shadow: 0 2px 4px 0 rgba(0,0,0,0.14);
+ color: #FFFFFF;
+ font-size: 20px;
+ font-weight: 500;
+ line-height: 26px;
+ text-align: center;
+ text-transform: uppercase;
+ margin: 35px 0 14px;
+ transition: 200ms ease-in-out;
+ background-color: rgba(247, 134, 28, 0.9);
+ }
+}
diff --git a/ui/app/main-container.js b/ui/app/main-container.js
index 292abcc3d..eed4bd164 100644
--- a/ui/app/main-container.js
+++ b/ui/app/main-container.js
@@ -32,19 +32,7 @@ MainContainer.prototype.render = function () {
return h(Settings, {key: 'config'})
default:
log.debug('rendering locked screen')
- contents = {
- component: UnlockScreen,
- style: {
- boxShadow: 'none',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- background: '#F7F7F7',
- // must force 100%, because lock screen is full-width
- width: '100%',
- },
- key: 'locked',
- }
+ return h('.unlock-screen-container', {}, h(UnlockScreen, { key: 'locked' }))
}
}
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index 029d830ec..4ca7d221e 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -44,6 +44,7 @@ function reduceMetamask (state, action) {
featureFlags: {},
networkEndpointType: OLD_UI_NETWORK_TYPE,
isRevealingSeedWords: false,
+ welcomeScreenSeen: false,
}, state.metamask)
switch (action.type) {
@@ -347,6 +348,11 @@ function reduceMetamask (state, action) {
networkEndpointType: action.value,
})
+ case actions.CLOSE_WELCOME_SCREEN:
+ return extend(metamaskState, {
+ welcomeScreenSeen: true,
+ })
+
default:
return metamaskState
diff --git a/ui/app/unlock.js b/ui/app/unlock.js
index 185b0b527..bbaf55f21 100644
--- a/ui/app/unlock.js
+++ b/ui/app/unlock.js
@@ -29,83 +29,72 @@ UnlockScreen.prototype.render = function () {
const state = this.props
const warning = state.warning
return (
- h('.flex-column', {
- style: {
- width: 'inherit',
- },
- }, [
- h('.unlock-screen.flex-column.flex-center.flex-grow', [
-
- h(Mascot, {
- animationEventEmitter: this.animationEventEmitter,
- }),
-
- h('h1', {
- style: {
- fontSize: '1.4em',
- textTransform: 'uppercase',
- color: '#7F8082',
- },
- }, t('appName')),
-
- h('input.large-input', {
- type: 'password',
- id: 'password-box',
- placeholder: 'enter password',
- style: {
- background: 'white',
- },
- onKeyPress: this.onKeyPress.bind(this),
- onInput: this.inputChanged.bind(this),
- }),
-
- h('.error', {
- style: {
- display: warning ? 'block' : 'none',
- padding: '0 20px',
- textAlign: 'center',
- },
- }, warning),
-
- h('button.primary.cursor-pointer', {
- onClick: this.onSubmit.bind(this),
- style: {
- margin: 10,
- },
- }, 'Log In'),
- ]),
-
- h('.flex-row.flex-center.flex-grow', [
- h('p.pointer', {
- onClick: () => {
- this.props.dispatch(actions.markPasswordForgotten())
- if (environmentType() === 'popup') {
- global.platform.openExtensionInBrowser()
- }
- },
- style: {
- fontSize: '0.8em',
- color: 'rgb(247, 134, 28)',
- textDecoration: 'underline',
- },
- }, 'Restore from seed phrase'),
- ]),
-
- h('.flex-row.flex-center.flex-grow', [
- h('p.pointer', {
- onClick: () => {
- this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
- .then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
- },
- style: {
- fontSize: '0.8em',
- color: '#aeaeae',
- textDecoration: 'underline',
- marginTop: '32px',
- },
- }, 'Use classic interface'),
- ]),
-
+ h('.unlock-screen', [
+
+ h(Mascot, {
+ animationEventEmitter: this.animationEventEmitter,
+ }),
+
+ h('h1', {
+ style: {
+ fontSize: '1.4em',
+ textTransform: 'uppercase',
+ color: '#7F8082',
+ },
+ }, t('appName'),
+
+ h('input.large-input', {
+ type: 'password',
+ id: 'password-box',
+ placeholder: 'enter password',
+ style: {
+ background: 'white',
+ },
+ onKeyPress: this.onKeyPress.bind(this),
+ onInput: this.inputChanged.bind(this),
+ }),
+
+ h('.error', {
+ style: {
+ display: warning ? 'block' : 'none',
+ padding: '0 20px',
+ textAlign: 'center',
+ },
+ }, warning),
+
+ h('button.primary.cursor-pointer', {
+ onClick: this.onSubmit.bind(this),
+ style: {
+ margin: 10,
+ },
+ }, 'Log In'),
+
+ h('p.pointer', {
+ onClick: () => {
+ this.props.dispatch(actions.markPasswordForgotten())
+ if (environmentType() === 'popup') {
+ global.platform.openExtensionInBrowser()
+ }
+ },
+ style: {
+ fontSize: '0.8em',
+ color: 'rgb(247, 134, 28)',
+ textDecoration: 'underline',
+ },
+ }, 'Restore from seed phrase'),
+
+ h('p.pointer', {
+ onClick: () => {
+ this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
+ .then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
+ },
+ style: {
+ fontSize: '0.8em',
+ color: '#aeaeae',
+ textDecoration: 'underline',
+ marginTop: '32px',
+ },
+ }, 'Use classic interface'),
])
)
}
diff --git a/ui/app/welcome-screen.js b/ui/app/welcome-screen.js
new file mode 100644
index 000000000..cdbb6dba8
--- /dev/null
+++ b/ui/app/welcome-screen.js
@@ -0,0 +1,56 @@
+import EventEmitter from 'events'
+import h from 'react-hyperscript'
+import { Component } from 'react'
+import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
+import {closeWelcomeScreen} from './actions'
+import Mascot from './components/mascot'
+
+class WelcomeScreen extends Component {
+ static propTypes = {
+ closeWelcomeScreen: PropTypes.func.isRequired,
+ }
+
+ constructor(props) {
+ super(props)
+ this.animationEventEmitter = new EventEmitter()
+ }
+
+ initiateAccountCreation = () => {
+ this.props.closeWelcomeScreen()
+ }
+
+ render () {
+ return h('div.welcome-screen', [
+
+ h('div.welcome-screen__info', [
+
+ h(Mascot, {
+ animationEventEmitter: this.animationEventEmitter,
+ width: '225',
+ height: '225',
+ }),
+
+ h('div.welcome-screen__info__header', 'Welcome to MetaMask Beta'),
+
+ h('div.welcome-screen__info__copy', 'MetaMask is a secure identity vault for Ethereum.'),
+
+ h('div.welcome-screen__info__copy', `It allows you to hold ether & tokens,
+ and serves as your bridge to decentralized applications.`),
+
+ h('button.welcome-screen__button', {
+ onClick: this.initiateAccountCreation,
+ }, 'Continue'),
+
+ ]),
+
+ ])
+ }
+}
+
+export default connect(
+ null,
+ dispatch => ({
+ closeWelcomeScreen: () => dispatch(closeWelcomeScreen()),
+ })
+)(WelcomeScreen)