Merge pull request #2707 from ethereum/run-deploy-e2e-tests

Deploy And Run Transactions Browser Tests
pull/1/head
yann300 5 years ago committed by GitHub
commit 39952ce2b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .env
  2. 1
      ci/browser_tests.sh
  3. 20
      nightwatch.js
  4. 1
      package.json
  5. 3
      src/app.js
  6. 6
      src/app/tabs/runTab/settings.js
  7. 2
      src/app/ui/modal-dialog-custom.js
  8. 2
      src/app/ui/universal-dapp-ui.js
  9. 38
      test-browser/commands/setupMetamask.js
  10. 21
      test-browser/commands/switchBrowserWindow.js
  11. BIN
      test-browser/extensions/chrome/metamask.crx
  12. 2
      test-browser/helpers/init.js
  13. 4
      test-browser/tests/fileExplorer.js
  14. 3
      test-browser/tests/generalSettings.js
  15. 179
      test-browser/tests/runAndDeploy.js
  16. 2
      test-browser/tests/terminal.js

@ -1 +1,3 @@
gist_token = <token>
gist_token = <token>
account_passphrase = <passphrase>
account_password = <password>

@ -22,6 +22,7 @@ setupRemixd
sleep 5
npm run nightwatch_parallel || TEST_EXITCODE=1
npm run nightwatch_local_runAndDeploy || TEST_EXITCODE=1
echo "$TEST_EXITCODE"
if [ "$TEST_EXITCODE" -eq 1 ]

@ -1,6 +1,9 @@
'use strict'
require('@babel/register')()
const crxFile = require('fs').readFileSync('./test-browser/extensions/chrome/metamask.crx')
const metamaskExtension = new Buffer.from(crxFile).toString('base64') // eslint-disable-line
module.exports = {
'src_folders': ['test-browser/tests'],
'output_folder': 'reports',
@ -27,7 +30,8 @@ module.exports = {
'browserName': 'firefox',
'javascriptEnabled': true,
'acceptSslCerts': true
}
},
'exclude': ['./test-browser/tests/runAndDeploy.js']
},
'chrome': {
@ -35,12 +39,24 @@ module.exports = {
'browserName': 'chrome',
'javascriptEnabled': true,
'acceptSslCerts': true,
'chromeOptions': {
'goog:chromeOptions': {
'args': ['window-size=2560,1440', 'start-fullscreen']
}
}
},
'chrome-runAndDeploy': {
'desiredCapabilities': {
'browserName': 'chrome',
'javascriptEnabled': true,
'acceptSslCerts': true,
'goog:chromeOptions': {
'args': ['window-size=2560,1440', 'start-fullscreen'],
'extensions': [metamaskExtension]
}
}
},
'safari': {
'desiredCapabilities': {
'browserName': 'safari',

@ -185,6 +185,7 @@
"nightwatch_local_fileExplorer": "nightwatch ./test-browser/tests/fileExplorer.js --config nightwatch.js --env chrome ",
"nightwatch_local_debugger": "nightwatch ./test-browser/tests/debugger.js --config nightwatch.js --env chrome ",
"nightwatch_local_editor": "nightwatch ./test-browser/tests/editor.js --config nightwatch.js --env chrome ",
"nightwatch_local_runAndDeploy": "nightwatch ./test-browser/tests/runAndDeploy.js --config nightwatch.js --env chrome-runAndDeploy ",
"onchange": "onchange build/app.js -- npm-run-all lint",
"prepublish": "mkdirp build; npm-run-all -ls downloadsolc_root build",
"remixd": "remixd -s ./contracts --remix-ide http://127.0.0.1:8080",

@ -222,8 +222,9 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
toolTip('You are using an `https` connection. Please switch to `http` if you are using Remix against an `http Web3 provider` or allow Mixed Content in your browser.')
}
const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080']
// workaround for Electron support
if (!isElectron()) {
if (!isElectron() && !hosts.includes(window.location.host)) {
// Oops! Accidentally trigger refresh or bookmark.
window.onbeforeunload = function () {
return 'Are you sure you want to leave?'

@ -99,7 +99,7 @@ class SettingsUI {
<div class="${css.account}">
<select data-id="runTabSelectAccount" name="txorigin" class="form-control ${css.select} custom-select pr-4" id="txorigin"></select>
<div style="margin-left: -5px;">${copyToClipboard(() => document.querySelector('#runTabView #txorigin').value)}</div>
<i id="remixRunSignMsg" class="mx-1 fas fa-edit ${css.icon}" aria-hidden="true" onclick=${this.signMessage.bind(this)} title="Sign a message using this account key"></i>
<i id="remixRunSignMsg" data-id="settingsRemixRunSignMsg" class="mx-1 fas fa-edit ${css.icon}" aria-hidden="true" onclick=${this.signMessage.bind(this)} title="Sign a message using this account key"></i>
</div>
</div>
`
@ -301,9 +301,9 @@ class SettingsUI {
modalDialogCustom.alert(yo`
<div>
<b>hash:</b><br>
<span id="remixRunSignMsgHash">${msgHash}</span>
<span id="remixRunSignMsgHash" data-id="settingsRemixRunSignMsgHash">${msgHash}</span>
<br><b>signature:</b><br>
<span id="remixRunSignMsgSignature">${signedData}</span>
<span id="remixRunSignMsgSignature" data-id="settingsRemixRunSignMsgSignature">${signedData}</span>
</div>
`)
})

@ -42,7 +42,7 @@ module.exports = {
},
promptMulti: function ({ title, text, inputValue }, ok, cancel) {
if (!inputValue) inputValue = ''
var input = yo`<textarea id="prompt_text" class=${css.prompt_text} rows="4" cols="50"></textarea>`
var input = yo`<textarea id="prompt_text" data-id="modalDialogCustomPromptText" class=${css.prompt_text} rows="4" cols="50"></textarea>`
return modal(title, yo`<div>${text}<div>${input}</div></div>`,
{
fn: () => { if (typeof ok === 'function') ok(document.getElementById('prompt_text').value) }

@ -145,7 +145,7 @@ UniversalDAppUI.prototype.renderInstanceFromABI = function (contractABI, address
<label class="">CALLDATA</label>
<div class="d-flex justify-content-end w-100 align-items-center">
${calldataInput}
<button id="deployAndRunLLTxSendTransaction" class="${css.instanceButton} p-0 w-50 btn border-warning text-warning" title="Send data to contract." onclick=${() => sendData()}>Transact</button>
<button id="deployAndRunLLTxSendTransaction" data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction" class="${css.instanceButton} p-0 w-50 btn border-warning text-warning" title="Send data to contract." onclick=${() => sendData()}>Transact</button>
</div>
</div>
<div>

@ -0,0 +1,38 @@
const EventEmitter = require('events')
class MetaMask extends EventEmitter {
command (passphrase, password) {
this.api.perform((done) => {
setupMetaMask(this.api, passphrase, password, () => {
done()
this.emit('complete')
})
})
return this
}
}
function setupMetaMask (browser, passphrase, password, done) {
browser
.switchBrowserWindow('chrome-extension://poemojpkcjbpmcccohjnomjffeinlafe/home.html#initialize/welcome', 'MetaMask', (browser) => {
browser.waitForElementPresent('.first-time-flow__button')
.click('.first-time-flow__button')
.waitForElementPresent('.select-action__select-button:nth-of-type(1) > .first-time-flow__button')
.click('.select-action__select-button:nth-of-type(1) > .first-time-flow__button')
.waitForElementPresent('.page-container__footer-button:nth-of-type(2)')
.click('.page-container__footer-button:nth-of-type(2)')
.waitForElementPresent('.first-time-flow__textarea')
.setValue('.first-time-flow__textarea', passphrase)
.setValue('*[autocomplete="new-password"]', password)
.setValue('*[autocomplete="confirm-password"]', password)
.click('.first-time-flow__checkbox')
.click('.first-time-flow__button')
.pause(5000)
.click('.first-time-flow__button')
.perform(() => {
done()
})
})
}
module.exports = MetaMask

@ -1,24 +1,25 @@
const EventEmitter = require('events')
class SwitchBrowserWindow extends EventEmitter {
command (url, windowName) {
command (url, windowName, cb) {
this.api.perform((done) => {
switchWindow(this.api, url, windowName, () => {
done()
this.emit('complete')
})
switchWindow(this.api, url, windowName, cb)
done()
this.emit('complete')
})
return this
}
}
function switchWindow (browser, url, windowName, callback) {
browser.execute(function (url, windowName) {
window.open(url, windowName, 'width=2560, height=1440')
}, [url, windowName], function () {
function switchWindow (browser, url, windowName, cb) {
browser.execute(function (windowName) {
return window.open('', windowName, 'width=2560, height=1440')
}, [windowName], (newWindow) => {
browser.switchWindow(windowName)
.url(url)
.pause(5000)
.assert.urlContains(url)
callback()
if (cb) cb(browser, newWindow)
})
}

@ -3,6 +3,8 @@ require('dotenv').config()
module.exports = function (browser, callback, url, preloadPlugins = true) {
browser
.url(url || 'http://127.0.0.1:8080')
.pause(5000)
.switchBrowserTab(0)
.injectScript('test-browser/helpers/applytestmode.js', function () {
browser.resizeWindow(2560, 1440, () => {
if (preloadPlugins) {

@ -84,10 +84,10 @@ module.exports = {
.waitForElementVisible('*[data-id="modalDialogContainer"]')
.modalFooterOKClick()
.pause(2000)
.switchBrowserTab(1)
.perform((done) => {
if (runtimeBrowser === 'chrome') {
browser.assert.urlContains('https://gist.github.com')
browser.switchBrowserTab(1)
.assert.urlContains('https://gist.github.com')
}
done()
})

@ -23,8 +23,7 @@ module.exports = {
.waitForElementVisible('*[data-id="settingsTabGitterChannelButton"]')
.click('*[data-id="settingsTabGitterChannelButton"]')
.pause(2000)
.switchBrowserTab(1)
.perform((done) => { if (runtimeBrowser === 'chrome') { browser.assert.urlContains('https://gitter.im/ethereum/remix') } done() })
.perform((done) => { if (runtimeBrowser === 'chrome') { browser.switchBrowserTab(1).assert.urlContains('https://gitter.im/ethereum/remix') } done() })
},
'Should activate `generate contract metadata`': function (browser) {

@ -0,0 +1,179 @@
'use strict'
var init = require('../helpers/init')
var sauce = require('./sauce')
const passphrase = process.env.account_passphrase
const password = process.env.account_password
module.exports = {
before: function (browser, done) {
init(browser, done)
},
'@sources': function () {
return sources
},
'Should load run and deploy tab': function (browser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.pause(3000)
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="sidePanelSwapitTitle"]')
.assert.containsText('*[data-id="sidePanelSwapitTitle"]', 'DEPLOY & RUN TRANSACTIONS')
},
'Should sign message using account key': function (browser) {
browser.waitForElementPresent('*[data-id="settingsRemixRunSignMsg"]')
.click('*[data-id="settingsRemixRunSignMsg"]')
.waitForElementPresent('*[data-id="modalDialogContainer"]')
.click('*[data-id="modalDialogCustomPromptText"]')
.setValue('*[data-id="modalDialogCustomPromptText"]', 'Remix is cool!')
.assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgHash"]')
.assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgSignature"]')
.modalFooterOKClick()
.pause(2000)
.waitForElementPresent('*[data-id="modalDialogContainer"]')
.assert.elementPresent('*[data-id="settingsRemixRunSignMsgHash"]')
.assert.elementPresent('*[data-id="settingsRemixRunSignMsgSignature"]')
.modalFooterOKClick()
},
'Should deploy contract on JavascriptVM': function (browser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.clickLaunchIcon('fileExplorers')
.addFile('Greet.sol', sources[0]['browser/Greet.sol'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c')
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="Deploy - transact (not payable)"]')
.pause(5000)
.testFunction('0xf887e3ac3143430b0c22d055eb25d234675e7f3246cb0824efc4c1437a1405d5', {
status: '0x1 Transaction mined and execution succeed',
'transaction hash': '0xf887e3ac3143430b0c22d055eb25d234675e7f3246cb0824efc4c1437a1405d5'
})
},
'Should run low level interaction (fallback function)': function (browser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.waitForElementPresent('*[data-id="universalDappUiTitleExpander"]')
.click('*[data-id="universalDappUiTitleExpander"]')
.waitForElementPresent('*[data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"]')
.click('*[data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"]')
.pause(5000)
.testFunction('0xfe718871ee0b4d03cdcac0e12e5b164efaf7e23ba952c07db76e62692867019b', {
status: '0x1 Transaction mined and execution succeed',
'transaction hash': '0xfe718871ee0b4d03cdcac0e12e5b164efaf7e23ba952c07db76e62692867019b'
})
},
'Should connect to Ropsten Test Network using MetaMask': function (browser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.setupMetamask(passphrase, password)
.click('.network-indicator__down-arrow')
.useXpath().click("//span[text()='Ropsten Test Network']")
.useCss().switchBrowserTab(0)
.refresh()
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.click('*[data-id="landingPageStartSolidity"]')
.pause(5000)
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="settingsSelectEnvOptions"]')
.click('*[data-id="settingsSelectEnvOptions"] option[id="injected-mode"]')
.waitForElementPresent('*[data-id="settingsNetworkEnv"]')
.assert.containsText('*[data-id="settingsNetworkEnv"]', 'Ropsten (3) network')
.switchBrowserTab(2)
.waitForElementPresent('.page-container__footer-button:nth-of-type(2)')
.click('.page-container__footer-button:nth-of-type(2)')
.switchBrowserTab(0)
},
'Should deploy contract on Ropsten Test Network using MetaMask': function (browser) {
browser.waitForElementPresent('*[data-id="runTabSelectAccount"] option')
.clickLaunchIcon('fileExplorers')
.switchFile('browser/Greet.sol')
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="Deploy - transact (not payable)"]')
.switchBrowserTab(2)
.waitForElementPresent('.transaction-status--unapproved')
.click('.transaction-status--unapproved')
.waitForElementPresent('.page-container__footer-button:nth-of-type(2)')
.click('.page-container__footer-button:nth-of-type(2)')
.waitForElementPresent('.transaction-status--submitted')
.pause(60000)
.switchBrowserTab(0)
},
'Should run low level interaction (fallback function) on Ropsten Test Network using MetaMask': function (browser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.waitForElementPresent('*[data-id="universalDappUiTitleExpander"]')
.click('*[data-id="universalDappUiTitleExpander"]')
.waitForElementPresent('*[data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"]')
.click('*[data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"]')
.switchBrowserTab(2)
.waitForElementPresent('.transaction-status--unapproved')
.click('.transaction-status--unapproved')
.waitForElementPresent('.page-container__footer-button:nth-of-type(2)')
.click('.page-container__footer-button:nth-of-type(2)')
.waitForElementPresent('.transaction-status--submitted')
.pause(60000)
.switchBrowserTab(0)
},
'Should connect to Ethereum Main Network using MetaMask': function (browser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.switchBrowserTab(2)
.waitForElementPresent('.network-indicator__down-arrow')
.click('.network-indicator__down-arrow')
.useXpath().click("//span[text()='Main Ethereum Network']")
.useCss().switchBrowserTab(0)
.refresh()
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.click('*[data-id="landingPageStartSolidity"]')
.pause(5000)
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="settingsSelectEnvOptions"]')
.click('*[data-id="settingsSelectEnvOptions"] option[id="injected-mode"]')
.waitForElementPresent('*[data-id="settingsNetworkEnv"]')
.assert.containsText('*[data-id="settingsNetworkEnv"]', 'Main (1) network')
},
'Should deploy contract on Ethereum Main Network using MetaMask': function (browser) {
browser.waitForElementPresent('*[data-id="runTabSelectAccount"] option')
.clickLaunchIcon('fileExplorers')
.switchFile('browser/Greet.sol')
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="Deploy - transact (not payable)"]')
.pause(2000)
.waitForElementPresent('*[data-id="modalDialogContainer"]')
.assert.containsText('*[data-id="modalDialogModalBody"]', 'You are creating a transaction on the main network. Click confirm if you are sure to continue.')
.modalFooterCancelClick()
.end()
},
tearDown: sauce
}
var sources = [
{
'browser/Greet.sol': {
content:
`
pragma solidity ^0.6.0;
contract helloWorld {
string public message;
fallback () external {
message = 'Hello World!';
}
function greet(string memory _message) public {
message = _message;
}
}`
}
}
]

@ -70,7 +70,7 @@ module.exports = {
.switchFile('browser/asyncAwaitWithFileManagerAccess.js')
.pause(5000)
.executeScript(`remix.execute('browser/asyncAwaitWithFileManagerAccess.js')`)
.pause(2000)
.pause(6000)
.journalLastChildIncludes('contract Ballot {')
.end()
},

Loading…
Cancel
Save