Merge pull request #3805 from MetaMask/ci-screens
CI - capture screenshotsfeature/default_network_editable
commit
40c3edb754
@ -0,0 +1,52 @@ |
||||
#!/usr/bin/env node
|
||||
const request = require('request-promise') |
||||
const { version } = require('../dist/chrome/manifest.json') |
||||
|
||||
const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN |
||||
console.log('GITHUB_COMMENT_TOKEN', GITHUB_COMMENT_TOKEN) |
||||
const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST |
||||
console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST) |
||||
const CIRCLE_SHA1 = process.env.CIRCLE_SHA1 |
||||
console.log('CIRCLE_SHA1', CIRCLE_SHA1) |
||||
const CIRCLE_BUILD_NUM = process.env.CIRCLE_BUILD_NUM |
||||
console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM) |
||||
|
||||
const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop() |
||||
const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7) |
||||
const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0` |
||||
|
||||
const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html` |
||||
const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${version}.zip` |
||||
const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${version}.zip` |
||||
const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${version}.zip` |
||||
const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${version}.zip` |
||||
const WALKTHROUGH = `${BUILD_LINK_BASE}/test-artifacts/screens/walkthrough%20%28en%29.gif` |
||||
|
||||
const commentBody = ` |
||||
<details> |
||||
<summary> |
||||
Builds ready [${SHORT_SHA1}]: |
||||
<a href="${MASCARA}">mascara</a>, |
||||
<a href="${CHROME}">chrome</a>, |
||||
<a href="${FIREFOX}">firefox</a>, |
||||
<a href="${EDGE}">edge</a>, |
||||
<a href="${OPERA}">opera</a> |
||||
</summary> |
||||
<image src="${WALKTHROUGH}"> |
||||
</details> |
||||
` |
||||
|
||||
const JSON_PAYLOAD = JSON.stringify({ body: commentBody }) |
||||
const POST_COMMENT_URI = `https://api.github.com/repos/metamask/metamask-extension/issues/${CIRCLE_PR_NUMBER}/comments` |
||||
console.log(`Announcement:\n${commentBody}`) |
||||
console.log(`Posting to: ${POST_COMMENT_URI}`) |
||||
|
||||
request({ |
||||
method: 'POST', |
||||
uri: POST_COMMENT_URI, |
||||
body: JSON_PAYLOAD, |
||||
headers: { |
||||
'User-Agent': 'metamaskbot', |
||||
'Authorization': `token ${GITHUB_COMMENT_TOKEN}`, |
||||
}, |
||||
}) |
File diff suppressed because it is too large
Load Diff
@ -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() |
||||
} |
@ -0,0 +1,230 @@ |
||||
const path = require('path') |
||||
const fs = require('fs') |
||||
const pify = require('pify') |
||||
const mkdirp = require('mkdirp') |
||||
const rimraf = require('rimraf') |
||||
const webdriver = require('selenium-webdriver') |
||||
const endOfStream = require('end-of-stream') |
||||
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') |
||||
|
||||
let driver |
||||
|
||||
captureAllScreens().catch((err) => { |
||||
try { |
||||
console.error(err) |
||||
verboseReportOnFailure() |
||||
driver.quit() |
||||
} catch (err) { |
||||
console.error(err) |
||||
} |
||||
process.exit(1) |
||||
}) |
||||
|
||||
async function captureAllScreens() { |
||||
let screenshotCount = 0 |
||||
|
||||
// common names
|
||||
let button |
||||
let tabs |
||||
let element |
||||
|
||||
await cleanScreenShotDir() |
||||
|
||||
// setup selenium and install extension
|
||||
const extPath = path.resolve('dist/chrome') |
||||
driver = buildWebDriver(extPath) |
||||
await driver.get('chrome://extensions-frame') |
||||
const elems = await driver.findElements(By.css('.extension-list-item-wrapper')) |
||||
const extensionId = await elems[1].getAttribute('id') |
||||
await driver.get(`chrome-extension://${extensionId}/home.html`) |
||||
await delay(500) |
||||
tabs = await driver.getAllWindowHandles() |
||||
await driver.switchTo().window(tabs[0]) |
||||
await delay(1000) |
||||
await setProviderType('localhost') |
||||
await delay(300) |
||||
|
||||
// click try new ui
|
||||
await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-center.flex-grow > p')).click() |
||||
await delay(300) |
||||
|
||||
// close metamask homepage and extra home.html
|
||||
tabs = await driver.getAllWindowHandles() |
||||
// metamask homepage is opened on prod, not dev
|
||||
if (tabs.length > 2) { |
||||
await driver.switchTo().window(tabs[2]) |
||||
driver.close() |
||||
} |
||||
await driver.switchTo().window(tabs[1]) |
||||
driver.close() |
||||
await driver.switchTo().window(tabs[0]) |
||||
await delay(300) |
||||
await captureLanguageScreenShots('welcome-new-ui') |
||||
|
||||
// setup account
|
||||
await delay(1000) |
||||
await driver.findElement(By.css('body')).click() |
||||
await delay(300) |
||||
await captureLanguageScreenShots('welcome') |
||||
|
||||
await driver.findElement(By.css('button')).click() |
||||
await captureLanguageScreenShots('create password') |
||||
|
||||
const passwordBox = await driver.findElement(By.css('input[type=password]:nth-of-type(1)')) |
||||
const passwordBoxConfirm = await driver.findElement(By.css('input[type=password]:nth-of-type(2)')) |
||||
passwordBox.sendKeys('123456789') |
||||
passwordBoxConfirm.sendKeys('123456789') |
||||
await delay(500) |
||||
await captureLanguageScreenShots('choose-password-filled') |
||||
|
||||
await driver.findElement(By.css('button')).click() |
||||
await delay(500) |
||||
await captureLanguageScreenShots('unique account image') |
||||
|
||||
await driver.findElement(By.css('button')).click() |
||||
await delay(500) |
||||
await captureLanguageScreenShots('privacy note') |
||||
|
||||
await driver.findElement(By.css('button')).click() |
||||
await delay(300) |
||||
await captureLanguageScreenShots('terms') |
||||
|
||||
await delay(300) |
||||
element = driver.findElement(By.linkText('Attributions')) |
||||
await driver.executeScript('arguments[0].scrollIntoView(true)', element) |
||||
await delay(300) |
||||
await captureLanguageScreenShots('terms-scrolled') |
||||
|
||||
await driver.findElement(By.css('button')).click() |
||||
await delay(300) |
||||
await captureLanguageScreenShots('secret backup phrase') |
||||
|
||||
await driver.findElement(By.css('button')).click() |
||||
await delay(300) |
||||
await captureLanguageScreenShots('secret backup phrase') |
||||
|
||||
await driver.findElement(By.css('.backup-phrase__reveal-button')).click() |
||||
await delay(300) |
||||
await captureLanguageScreenShots('secret backup phrase - reveal') |
||||
|
||||
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) |
||||
} |
||||
|
||||
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) |
||||
} |
||||
|
||||
// cleanup
|
||||
await driver.quit() |
||||
|
||||
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) { |
||||
const artifactDir = `./test-artifacts/${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) |
||||
} |
Loading…
Reference in new issue