Merge pull request #3754 from MetaMask/selenium-e2e

test - e2e testing with selenium
This commit is contained in:
Thomas Huang 2018-03-27 14:03:47 -07:00 committed by GitHub
commit 246287ff1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 336 additions and 1 deletions

View File

@ -12,6 +12,9 @@ workflows:
- test-lint:
requires:
- prep-deps-npm
- test-e2e:
requires:
- prep-deps-npm
- test-unit:
requires:
- prep-deps-npm
@ -96,6 +99,20 @@ jobs:
name: Test
command: npm run lint
test-e2e:
docker:
- image: circleci/node:8-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Build
command: npm run dist
- run:
name: Test
command: npm run test:e2e
test-unit:
docker:
- image: circleci/node:8-browsers

175
package-lock.json generated
View File

@ -2994,6 +2994,19 @@
"readdirp": "2.1.0"
}
},
"chromedriver": {
"version": "2.36.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.36.0.tgz",
"integrity": "sha512-Lq2HrigCJ4RVdIdCmchenv1rVrejNSJ7EUCQojycQo12ww3FedQx4nb+GgTdqMhjbOMTqq5+ziaiZlrEN2z1gQ==",
"dev": true,
"requires": {
"del": "3.0.0",
"extract-zip": "1.6.6",
"kew": "0.7.0",
"mkdirp": "0.5.1",
"request": "2.83.0"
}
},
"cipher-base": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
@ -6382,6 +6395,35 @@
"is-extglob": "1.0.0"
}
},
"extract-zip": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz",
"integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=",
"dev": true,
"requires": {
"concat-stream": "1.6.0",
"debug": "2.6.9",
"mkdirp": "0.5.0",
"yauzl": "2.4.1"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
"mkdirp": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
"integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=",
"dev": true,
"requires": {
"minimist": "0.0.8"
}
}
}
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
@ -6490,6 +6532,15 @@
}
}
},
"fd-slicer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
"dev": true,
"requires": {
"pend": "1.2.0"
}
},
"fetch-ponyfill": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz",
@ -11159,6 +11210,53 @@
"array-includes": "3.0.3"
}
},
"jszip": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz",
"integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==",
"dev": true,
"requires": {
"core-js": "2.3.0",
"es6-promise": "3.0.2",
"lie": "3.1.1",
"pako": "1.0.6",
"readable-stream": "2.0.6"
},
"dependencies": {
"core-js": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz",
"integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=",
"dev": true
},
"es6-promise": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz",
"integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=",
"dev": true
},
"readable-stream": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
"integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
"dev": true,
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "1.0.7",
"string_decoder": "0.10.31",
"util-deprecate": "1.0.2"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"dev": true
}
}
},
"just-debounce": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
@ -11454,6 +11552,12 @@
"sha3": "1.2.0"
}
},
"kew": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz",
"integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=",
"dev": true
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
@ -11765,6 +11869,23 @@
"integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=",
"dev": true
},
"lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=",
"dev": true,
"requires": {
"immediate": "3.0.6"
},
"dependencies": {
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=",
"dev": true
}
}
},
"liftoff": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz",
@ -16369,6 +16490,12 @@
"sha.js": "2.4.9"
}
},
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
"dev": true
},
"percentile": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/percentile/-/percentile-1.2.0.tgz",
@ -18331,6 +18458,29 @@
"safe-buffer": "5.1.1"
}
},
"selenium-webdriver": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz",
"integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==",
"dev": true,
"requires": {
"jszip": "3.1.5",
"rimraf": "2.6.2",
"tmp": "0.0.30",
"xml2js": "0.4.19"
},
"dependencies": {
"tmp": {
"version": "0.0.30",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",
"integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=",
"dev": true,
"requires": {
"os-tmpdir": "1.0.2"
}
}
}
},
"semaphore": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz",
@ -22243,6 +22393,22 @@
"integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=",
"dev": true
},
"xml2js": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
"dev": true,
"requires": {
"sax": "1.2.4",
"xmlbuilder": "9.0.7"
}
},
"xmlbuilder": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
"dev": true
},
"xmldom": {
"version": "0.1.27",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz",
@ -22310,6 +22476,15 @@
"camelcase": "3.0.0"
}
},
"yauzl": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
"integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
"dev": true,
"requires": {
"fd-slicer": "1.0.1"
}
},
"yazl": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/yazl/-/yazl-2.4.3.tgz",

View File

@ -17,6 +17,7 @@
"test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js",
"test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara",
"test:integration:build": "gulp build:scss",
"test:e2e": "METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive",
"test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload",
"test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi",
"test:flat": "npm run test:flat:build && karma start test/flat.conf.js",
@ -201,6 +202,7 @@
"brfs": "^1.4.3",
"browserify": "^16.1.1",
"chai": "^4.1.0",
"chromedriver": "^2.34.1",
"compression": "^1.7.1",
"coveralls": "^3.0.0",
"cross-env": "^5.1.4",
@ -230,7 +232,7 @@
"gulp-watch": "^5.0.0",
"gulp-zip": "^4.0.0",
"isomorphic-fetch": "^2.2.1",
"jsdom": "^11.1.0",
"jsdom": "^11.2.0",
"jsdom-global": "^3.0.2",
"jshint-stylish": "~2.2.1",
"karma": "^2.0.0",
@ -253,6 +255,7 @@
"react-addons-test-utils": "^15.5.1",
"react-test-renderer": "^15.6.2",
"react-testutils-additions": "^15.2.0",
"selenium-webdriver": "^3.5.0",
"redux-test-utils": "^0.2.2",
"sinon": "^4.0.0",
"stylelint-config-standard": "^18.2.0",

18
test/e2e/func.js Normal file
View File

@ -0,0 +1,18 @@
require('chromedriver')
const webdriver = require('selenium-webdriver')
exports.delay = function delay (time) {
return new Promise(resolve => setTimeout(resolve, time))
}
exports.buildWebDriver = function buildWebDriver (extPath) {
return new webdriver.Builder()
.withCapabilities({
chromeOptions: {
args: [`load-extension=${extPath}`],
},
})
.forBrowser('chrome')
.build()
}

122
test/e2e/metamask.spec.js Normal file
View File

@ -0,0 +1,122 @@
const path = require('path')
const assert = require('assert')
const webdriver = require('selenium-webdriver')
const By = webdriver.By
const { delay, buildWebDriver } = require('./func')
describe('Metamask popup page', function () {
let driver
this.seedPhase
this.accountAddress
this.timeout(0)
before(async function () {
const extPath = path.resolve('dist/chrome')
driver = buildWebDriver(extPath)
await driver.get('chrome://extensions-frame')
const elems = await driver.findElements(By.className('extension-list-item-wrapper'))
const extensionId = await elems[1].getAttribute('id')
await driver.get(`chrome-extension://${extensionId}/popup.html`)
await delay(500)
})
after(async function () {
await driver.quit()
})
describe('#onboarding', () => {
it('should open Metamask.io', async function () {
const tabs = await driver.getAllWindowHandles()
await driver.switchTo().window(tabs[0])
await delay(300)
})
it('should match title', async () => {
const title = await driver.getTitle()
assert.equal(title, 'MetaMask Plugin', 'title matches MetaMask Plugin')
})
it('should show privacy notice', async () => {
const privacy = await driver.findElement(By.className(
'terms-header'
)).getText()
assert.equal(privacy, 'PRIVACY NOTICE', 'shows privacy notice')
driver.findElement(By.css(
'button'
)).click()
})
it('should show terms of use', async () => {
await delay(300)
const terms = await driver.findElement(By.className(
'terms-header'
)).getText()
assert.equal(terms, 'TERMS OF USE', 'shows terms of use')
})
it('should be unable to continue without scolling throught the terms of use', async () => {
const button = await driver.findElement(By.css(
'button'
)).isEnabled()
assert.equal(button, false, 'disabled continue button')
const element = driver.findElement(By.linkText(
'Attributions'
))
await driver.executeScript('arguments[0].scrollIntoView(true)', element)
})
it('should be able to continue when scrolled to the bottom of terms of use', async () => {
const button = await driver.findElement(By.css('button'))
const buttonEnabled = await button.isEnabled()
await delay(500)
assert.equal(buttonEnabled, true, 'enabled continue button')
await button.click()
})
it('should accept password with length of eight', async () => {
await delay(300)
const passwordBox = await driver.findElement(By.id('password-box'))
const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm'))
const button = driver.findElement(By.css('button'))
passwordBox.sendKeys('123456789')
passwordBoxConfirm.sendKeys('123456789')
await delay(500)
await button.click()
})
it('should show value was created and seed phrase', async () => {
await delay(700)
this.seedPhase = await driver.findElement(By.className('twelve-word-phrase')).getText()
const continueAfterSeedPhrase = await driver.findElement(By.css('button'))
await continueAfterSeedPhrase.click()
})
it('should show lock account', async () => {
await delay(300)
await driver.findElement(By.className('sandwich-expando')).click()
await delay(500)
await driver.findElement(By.xpath('//*[@id="app-content"]/div/div[3]/span/div/li[2]')).click()
})
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', async () => {
await delay(300)
await driver.findElement(By.className('fa-ellipsis-h')).click()
await driver.findElement(By.xpath('//*[@id="app-content"]/div/div[4]/div/div/div[1]/flex-column/div[1]/div/span/i/div/div/li[2]')).click()
await delay(300)
})
it('should show the account address', async () => {
this.accountAddress = await driver.findElement(By.className('ellip-address')).getText()
await driver.findElement(By.className('fa-arrow-left')).click()
await delay(500)
})
})
})