Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds and end to end test for typed signature requests #7420

Merged
merged 1 commit into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions test/e2e/contract-test/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ web3.currentProvider.enable().then(() => {
const approveTokens = document.getElementById('approveTokens')
const transferTokensWithoutGas = document.getElementById('transferTokensWithoutGas')
const approveTokensWithoutGas = document.getElementById('approveTokensWithoutGas')
const signTypedData = document.getElementById('signTypedData')

deployButton.addEventListener('click', async function () {
document.getElementById('contractStatus').innerHTML = 'Deploying'
Expand Down Expand Up @@ -184,4 +185,57 @@ web3.currentProvider.enable().then(() => {
ethereum.on('accountsChanged', (accounts) => {
accountsDiv.innerHTML = accounts
})

const signTypedDataResultsDiv = document.getElementById('signTypedDataResult')
signTypedData.addEventListener('click', function () {

const typedData = {
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
],
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 3,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
message: {
sender: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
recipient: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
}
web3.currentProvider.sendAsync({
method: 'eth_signTypedData_v3',
params: [ethereum.selectedAddress, JSON.stringify(typedData)],
from: ethereum.selectedAddress,
}, function (err, result) {
if (err) {
console.log(err)
} else {
signTypedDataResultsDiv.innerHTML = result
}
})
})
})
7 changes: 7 additions & 0 deletions test/e2e/contract-test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
<div>Accounts: <div id="accounts"></div></div>
<div style="display: flex;">
</div>
<div style="display: flex; flex-flow: column;">
<div style="display: flex; font-size: 1.25rem;">Sign Typed Data</div>
<div style="display: flex;">
<button id="signTypedData">Sign</button>
<div>Sign Typed Data Result: <div id="signTypedDataResult"></div></div>
</div>
</div>

<script src="contract.js"></script>
</body>
Expand Down
8 changes: 8 additions & 0 deletions test/e2e/run-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ concurrently --kill-others \
'yarn dapp' \
'sleep 5 && mocha test/e2e/metamask-responsive-ui.spec'

concurrently --kill-others \
--names 'ganache,dapp,e2e' \
--prefix '[{time}][{name}]' \
--success first \
'yarn ganache:start' \
'yarn dapp' \
'sleep 5 && mocha test/e2e/signature-request.spec'

export GANACHE_ARGS="${BASE_GANACHE_ARGS} --deterministic --account=0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9,25000000000000000000"
concurrently --kill-others \
--names 'ganache,e2e' \
Expand Down
191 changes: 191 additions & 0 deletions test/e2e/signature-request.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
const assert = require('assert')
const webdriver = require('selenium-webdriver')
const { By, until } = webdriver
const {
delay,
} = require('./func')
const {
checkBrowserForConsoleErrors,
findElement,
findElements,
openNewPage,
verboseReportOnFailure,
waitUntilXWindowHandles,
switchToWindowWithTitle,
setupFetchMocking,
prepareExtensionForTesting,
} = require('./helpers')
const enLocaleMessages = require('../../app/_locales/en/messages.json')

describe('MetaMask', function () {
let driver
let publicAddress

const tinyDelayMs = 200
const regularDelayMs = tinyDelayMs * 2
const largeDelayMs = regularDelayMs * 2

this.timeout(0)
this.bail(true)

before(async function () {
const result = await prepareExtensionForTesting()
driver = result.driver
await setupFetchMocking(driver)
})

afterEach(async function () {
if (process.env.SELENIUM_BROWSER === 'chrome') {
const errors = await checkBrowserForConsoleErrors(driver)
if (errors.length) {
const errorReports = errors.map(err => err.message)
const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}`
console.error(new Error(errorMessage))
}
}
if (this.currentTest.state === 'failed') {
await verboseReportOnFailure(driver, this.currentTest)
}
})

after(async function () {
await driver.quit()
})

describe('Going through the first time flow, but skipping the seed phrase challenge', () => {
it('clicks the continue button on the welcome screen', async () => {
await findElement(driver, By.css('.welcome-page__header'))
const welcomeScreenBtn = await findElement(driver, By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`))
welcomeScreenBtn.click()
await delay(largeDelayMs)
})

it('clicks the "Create New Wallet" option', async () => {
const customRpcButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Create a Wallet')]`))
customRpcButton.click()
await delay(largeDelayMs)
})

it('clicks the "No thanks" option on the metametrics opt-in screen', async () => {
const optOutButton = await findElement(driver, By.css('.btn-default'))
optOutButton.click()
await delay(largeDelayMs)
})

it('accepts a secure password', async () => {
const passwordBox = await findElement(driver, By.css('.first-time-flow__form #create-password'))
const passwordBoxConfirm = await findElement(driver, By.css('.first-time-flow__form #confirm-password'))
const button = await findElement(driver, By.css('.first-time-flow__form button'))

await passwordBox.sendKeys('correct horse battery staple')
await passwordBoxConfirm.sendKeys('correct horse battery staple')

const tosCheckBox = await findElement(driver, By.css('.first-time-flow__checkbox'))
await tosCheckBox.click()

await button.click()
await delay(largeDelayMs)
})

it('skips the seed phrase challenge', async () => {
const button = await findElement(driver, By.xpath(`//button[contains(text(), '${enLocaleMessages.remindMeLater.message}')]`))
await button.click()
await delay(regularDelayMs)

const detailsButton = await findElement(driver, By.css('.account-details__details-button'))
await detailsButton.click()
await delay(regularDelayMs)
})

it('gets the current accounts address', async () => {
const addressInput = await findElement(driver, By.css('.qr-ellip-address'))
publicAddress = (await addressInput.getAttribute('value')).toLowerCase()
const accountModal = await driver.findElement(By.css('span .modal'))

await driver.executeScript("document.querySelector('.account-modal-close').click()")

await driver.wait(until.stalenessOf(accountModal))
await delay(regularDelayMs)
})

it('changes the network', async () => {
const networkDropdown = await findElement(driver, By.css('.network-name'))
await networkDropdown.click()
await delay(regularDelayMs)

const ropstenButton = await findElement(driver, By.xpath(`//span[contains(text(), 'Ropsten')]`))
await ropstenButton.click()
await delay(largeDelayMs)
})
})

describe('provider listening for events', () => {
let extension
let popup
let dapp
let windowHandles
it('switches to a dapp', async () => {
await openNewPage(driver, 'http://127.0.0.1:8080/')
await delay(regularDelayMs)

await waitUntilXWindowHandles(driver, 3)
windowHandles = await driver.getAllWindowHandles()

extension = windowHandles[0]
popup = await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles)
dapp = windowHandles.find(handle => handle !== extension && handle !== popup)

await delay(regularDelayMs)
const approveButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`))
await approveButton.click()

await driver.switchTo().window(dapp)
await delay(regularDelayMs)
})

it('creates a sign typed data signature request', async () => {
const signTypedMessage = await findElement(driver, By.xpath(`//button[contains(text(), 'Sign')]`), 10000)
await signTypedMessage.click()
await delay(largeDelayMs)

windowHandles = await driver.getAllWindowHandles()
await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles)
await delay(regularDelayMs)

const title = await findElement(driver, By.css('.signature-request-content__title'))
const name = await findElement(driver, By.css('.signature-request-content__info--bolded'))
const content = await findElements(driver, By.css('.signature-request-content__info'))
const origin = content[0]
const address = content[1]
assert.equal(await title.getText(), 'Signature Request')
assert.equal(await name.getText(), 'Ether Mail')
assert.equal(await origin.getText(), '127.0.0.1')
assert.equal(await address.getText(), publicAddress.slice(0, 8) + '...' + publicAddress.slice(publicAddress.length - 8))
})

it('signs the transaction', async () => {
const signButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Sign')]`), 10000)
await signButton.click()
await delay(regularDelayMs)

extension = windowHandles[0]
await driver.switchTo().window(extension)
})

it('gets the current accounts address', async () => {
const detailsButton = await findElement(driver, By.css('.account-details__details-button'))
await detailsButton.click()
await delay(regularDelayMs)

const addressInput = await findElement(driver, By.css('.qr-ellip-address'))
const newPublicAddress = await addressInput.getAttribute('value')
const accountModal = await driver.findElement(By.css('span .modal'))

await driver.executeScript("document.querySelector('.account-modal-close').click()")

await driver.wait(until.stalenessOf(accountModal))
await delay(regularDelayMs)
assert.equal(newPublicAddress.toLowerCase(), publicAddress)
})
})
})