Merge pull request #2626 from ethereum/parallel-browser-tests

Parallel Browser Tests (Firefox & Chrome)
pull/1/head
yann300 5 years ago committed by GitHub
commit 9b988564bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      .circleci/config.yml
  2. 2
      ci/browser_tests.sh
  3. 143
      package-lock.json
  4. 3
      package.json
  5. 11
      seleniumConfig.js
  6. 3
      src/app/panels/terminal.js
  7. 2
      src/app/ui/multiParamManager.js
  8. 4
      test-browser/commands/checkTerminalFilter.js
  9. 10
      test-browser/commands/executeScript.js
  10. 36
      test-browser/commands/rightClick.js
  11. 2
      test-browser/tests/editor.js
  12. 34
      test-browser/tests/fileExplorer.js
  13. 2
      test-browser/tests/generalSettings.js
  14. 4
      test-browser/tests/gist.js
  15. 37
      test-browser/tests/remixd.js
  16. 1
      test-browser/tests/solidityUnittests.js
  17. 2
      test-browser/tests/terminal.js

@ -25,11 +25,17 @@ jobs:
- run: npm run lint && npm run test && npm run make-mock-compiler
- run:
name: Download Selenium
command: wget http://selenium-release.storage.googleapis.com/3.5/selenium-server-standalone-3.5.3.jar
command: ./node_modules/.bin/selenium-standalone install --config=../remix-ide/seleniumConfig.js
- run:
name: Start Selenium
command: java -jar selenium-server-standalone-3.5.3.jar
command: ./node_modules/.bin/selenium-standalone start --config=../remix-ide/seleniumConfig.js
background: true
- run:
name: Download Latest Firefox
command: sudo apt-get purge -y firefox && wget https://sourceforge.net/projects/ubuntuzilla/files/mozilla/apt/pool/main/f/firefox-mozilla-build/firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb
- run:
name: Install Firefox
command: sudo dpkg -i firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb
- run: ./ci/browser_tests.sh
- run:
name: Deploy
@ -50,4 +56,4 @@ workflows:
version: 2
build_all:
jobs:
- remix-ide
- remix-ide

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

143
package-lock.json generated

@ -2020,6 +2020,12 @@
"resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz",
"integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo="
},
"adm-zip": {
"version": "0.4.11",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.11.tgz",
"integrity": "sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA==",
"dev": true
},
"aes-js": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz",
@ -5082,6 +5088,21 @@
"event-emitter": "~0.3.5"
}
},
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
"dev": true
},
"es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
"dev": true,
"requires": {
"es6-promise": "^4.0.3"
}
},
"es6-set": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
@ -7922,6 +7943,112 @@
}
}
},
"geckodriver": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-1.19.1.tgz",
"integrity": "sha512-xWL/+eEhQ6+t98rc1c+xVM3hshDJibXtZf9WJA3sshxq4k5L1PBwfmswyBmmlKUfBr4xuC256gLVC2RxFhiCsQ==",
"dev": true,
"requires": {
"adm-zip": "0.4.11",
"bluebird": "3.4.6",
"got": "5.6.0",
"https-proxy-agent": "3.0.0",
"tar": "4.4.2"
},
"dependencies": {
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"dev": true,
"requires": {
"es6-promisify": "^5.0.0"
}
},
"bluebird": {
"version": "3.4.6",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz",
"integrity": "sha1-AdqNgh2HgT0ViWfnQ9X+bGLPjA8=",
"dev": true
},
"got": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/got/-/got-5.6.0.tgz",
"integrity": "sha1-ux1+4WO3gIK7yOuDbz85UATqb78=",
"dev": true,
"requires": {
"create-error-class": "^3.0.1",
"duplexer2": "^0.1.4",
"is-plain-obj": "^1.0.0",
"is-redirect": "^1.0.0",
"is-retry-allowed": "^1.0.0",
"is-stream": "^1.0.0",
"lowercase-keys": "^1.0.0",
"node-status-codes": "^1.0.0",
"object-assign": "^4.0.1",
"parse-json": "^2.1.0",
"pinkie-promise": "^2.0.0",
"read-all-stream": "^3.0.0",
"readable-stream": "^2.0.5",
"timed-out": "^2.0.0",
"unzip-response": "^1.0.0",
"url-parse-lax": "^1.0.0"
}
},
"https-proxy-agent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.0.tgz",
"integrity": "sha512-y4jAxNEihqvBI5F3SaO2rtsjIOnnNA8sEbuiP+UhJZJHeM2NRm6c09ax2tgqme+SgUUvjao2fJXF4h3D6Cb2HQ==",
"dev": true,
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
}
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
"dev": true,
"requires": {
"error-ex": "^1.2.0"
}
},
"tar": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.2.tgz",
"integrity": "sha512-BfkE9CciGGgDsATqkikUHrQrraBCO+ke/1f6SFAEMnxyyfN9lxC+nW1NFWMpqH865DhHIy9vQi682gk1X7friw==",
"dev": true,
"requires": {
"chownr": "^1.0.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.2.4",
"minizlib": "^1.1.0",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.2"
}
},
"timed-out": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz",
"integrity": "sha1-84sK6B03R9YoAB9B2vxlKs5nHAo=",
"dev": true
},
"unzip-response": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz",
"integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=",
"dev": true
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
}
}
},
"generate-function": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
@ -11031,6 +11158,12 @@
"semver": "^6.3.0"
}
},
"node-status-codes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz",
"integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=",
"dev": true
},
"nodent": {
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/nodent/-/nodent-3.2.11.tgz",
@ -13788,6 +13921,16 @@
"integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==",
"dev": true
},
"read-all-stream": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz",
"integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=",
"dev": true,
"requires": {
"pinkie-promise": "^2.0.0",
"readable-stream": "^2.0.0"
}
},
"read-cmd-shim": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz",

@ -65,7 +65,7 @@
"remixd": "0.1.8-alpha.10",
"request": "^2.83.0",
"rimraf": "^2.6.1",
"selenium-standalone": "^6.0.1",
"selenium-standalone": "^6.17.0",
"semver": "^6.1.2",
"solc": "^0.6.0",
"swarmgw": "^0.3.1",
@ -162,6 +162,7 @@
"lint": "standard | notify-error",
"make-mock-compiler": "node ci/makeMockCompiler.js",
"minify": "uglifyjs --in-source-map inline --source-map-inline -c warnings=false",
"nightwatch_parallel": "nightwatch -e chrome,firefox --config nightwatch.js",
"nightwatch_local_firefox": "nightwatch --config nightwatch.js --env firefox",
"nightwatch_local_chrome": "nightwatch --config nightwatch.js --env chrome",
"nightwatch_local_ballot": "nightwatch ./test-browser/tests/ballot.js --config nightwatch.js --env chrome ",

@ -0,0 +1,11 @@
module.exports = {
version: '3.8.1',
baseURL: 'https://selenium-release.storage.googleapis.com',
drivers: {
chrome: {
version: '2.39',
arch: process.arch,
baseURL: 'https://chromedriver.storage.googleapis.com'
}
}
}

@ -158,7 +158,8 @@ class Terminal extends Plugin {
class="border ${css.filter} form-control"
id="searchInput"
onkeydown=${filter}
placeholder="Filter with transaction hash or address">
placeholder="Search with transaction hash or address"
data-id="terminalInputSearch">
</input>`
self._view.bar = yo`
<div class="${css.bar}">

@ -119,7 +119,7 @@ class MultiParamManager {
this.basicInputField = yo`<input class="form-control"></input>`
this.basicInputField.setAttribute('placeholder', this.inputs)
this.basicInputField.setAttribute('title', this.inputs)
this.basicInputField.setAttribute('data-id', `multiParamManagerBasicInputField${this.inputs}`)
this.basicInputField.setAttribute('data-id', this.inputs)
var onClick = () => {
this.clickCallBack(this.funABI.inputs, this.basicInputField.value)

@ -17,10 +17,10 @@ function checkFilter (browser, filter, test, done) {
done()
return
}
const filterClass = '#main-panel div[class^="search"] input[class^="filter"]'
const filterClass = '[data-id="terminalInputSearch"]'
browser.setValue(filterClass, filter, function () {
browser.execute(function () {
return document.querySelector('#main-panel div[class^="journal"]').innerHTML === test
return document.querySelector('[data-id="terminalJournal"]').innerHTML === test
}, [], function (result) {
browser.clearValue(filterClass).setValue(filterClass, '', function () {
if (!result.value) {

@ -3,11 +3,11 @@ const EventEmitter = require('events')
class ExecuteScript extends EventEmitter {
command (script) {
this.api
.clearValue('span[data-id="terminalCliInput"]')
.click('div[data-id="terminalCli"]')
.keys(script)
.keys(this.api.Keys.ENTER)
.keys(this.api.Keys.ENTER) // that's a bug... sometimes we need to press 2 times to execute a command
.clearValue('*[data-id="terminalCliInput"]')
.click('*[data-id="terminalCli"]')
.sendKeys('*[data-id="terminalCliInput"]', script)
.sendKeys('*[data-id="terminalCliInput"]', this.api.Keys.ENTER)
.sendKeys('*[data-id="terminalCliInput"]', this.api.Keys.ENTER)
.perform(() => {
this.emit('complete')
})

@ -0,0 +1,36 @@
const EventEmitter = require('events')
class RightClick extends EventEmitter {
command (cssSelector) {
this.api.perform((done) => {
rightClick(this.api, cssSelector, () => {
done()
this.emit('complete')
})
})
return this
}
}
function rightClick (browser, cssSelector, callback) {
browser.execute(function (cssSelector) {
const element = document.querySelector(cssSelector)
const evt = element.ownerDocument.createEvent('MouseEvents')
const RIGHT_CLICK_BUTTON_CODE = 2
evt.initMouseEvent('contextmenu', true, true,
element.ownerDocument.defaultView, 1, 0, 0, 0, 0, false,
false, false, false, RIGHT_CLICK_BUTTON_CODE, null)
if (document.createEventObject) {
// dispatch for IE
return element.fireEvent('onclick', evt)
} else {
// dispatch for firefox + others
return !element.dispatchEvent(evt)
}
}, [cssSelector], function () {
callback()
})
}
module.exports = RightClick

@ -30,7 +30,7 @@ module.exports = {
browser.waitForElementVisible('*[data-id="editorInput"]')
.waitForElementVisible('*[class="ace_content"]')
.click('*[class="ace_content"]')
.keys('error')
.sendKeys('*[class="ace_text-input"]', 'error')
.pause(2000)
.waitForElementVisible('.ace_error')
},

@ -23,18 +23,18 @@ module.exports = {
'Should rename `5_New_contract.sol` to 5_Renamed_Contract.sol': function (browser) {
browser
.waitForElementVisible('*[data-id="treeViewLibrowser/5_New_contract.sol"]')
.moveToElement('*[data-id="treeViewLibrowser/5_New_contract.sol"]', 5, 5)
.mouseButtonClick('right')
.rightClick('[data-path="browser/5_New_contract.sol"]')
.click('*[id="menuitemrename"]')
.keys('5_Renamed_Contract.sol')
.keys(browser.Keys.ENTER)
.sendKeys('[data-path="browser/5_New_contract.sol"]', '5_Renamed_Contract.sol')
.sendKeys('[data-path="browser/5_New_contract.sol"]', browser.Keys.ENTER)
.keys()
.waitForElementVisible('*[data-id="treeViewLibrowser/5_Renamed_Contract.sol"]')
},
'Should delete file `5_Renamed_Contract.sol` from file explorer': function (browser) {
browser
.moveToElement('*[data-id="treeViewLibrowser/5_Renamed_Contract.sol"]', 5, 5)
.mouseButtonClick('right')
.waitForElementVisible('*[data-id="treeViewLibrowser/5_Renamed_Contract.sol"]')
.rightClick('[data-path="browser/5_Renamed_Contract.sol"]')
.click('*[id="menuitemdelete"]')
.waitForElementVisible('*[data-id="modalDialogContainer"]')
.modalFooterOKClick()
@ -44,8 +44,7 @@ module.exports = {
'Should create a new folder': function (browser) {
browser
.waitForElementVisible('*[data-id="treeViewLibrowser/1_Storage.sol"]')
.moveToElement('*[data-id="treeViewLibrowser/1_Storage.sol"]', 5, 5)
.mouseButtonClick('right')
.rightClick('[data-path="browser/1_Storage.sol"]')
.click('*[id="menuitemcreate folder"]')
.waitForElementVisible('*[data-id="modalDialogContainer"]')
.setValue('*[data-id="modalDialogCustomPromptText"]', 'Browser_Tests')
@ -56,19 +55,17 @@ module.exports = {
'Should rename Browser_Tests folder to Browser_E2E_Tests': function (browser) {
browser
.waitForElementVisible('*[data-id="treeViewLibrowser/Browser_Tests"]')
.moveToElement('*[data-id="treeViewLibrowser/Browser_Tests"]', 5, 5)
.mouseButtonClick('right')
.rightClick('[data-path="browser/Browser_Tests"]')
.click('*[id="menuitemrename"]')
.keys('Browser_E2E_Tests')
.keys(browser.Keys.ENTER)
.sendKeys('[data-path="browser/Browser_Tests"]', 'Browser_E2E_Tests')
.sendKeys('[data-path="browser/Browser_Tests"]', browser.Keys.ENTER)
.waitForElementVisible('*[data-id="treeViewLibrowser/Browser_E2E_Tests"]')
},
'Should delete Browser_E2E_Tests folder': function (browser) {
browser
.waitForElementVisible('*[data-id="treeViewLibrowser/Browser_E2E_Tests"]')
.moveToElement('*[data-id="treeViewLibrowser/Browser_E2E_Tests"]', 5, 5)
.mouseButtonClick('right')
.rightClick('[data-path="browser/Browser_E2E_Tests"]')
.click('*[id="menuitemdelete"]')
.waitForElementVisible('*[data-id="modalDialogContainer"]')
.modalFooterOKClick()
@ -76,6 +73,8 @@ module.exports = {
},
'Should publish all explorer files to github gist': function (browser) {
const runtimeBrowser = browser.capabilities.browserName
browser
.waitForElementVisible('*[data-id="fileExplorerNewFilepublishToGist"]')
.click('*[data-id="fileExplorerNewFilepublishToGist"]')
@ -86,7 +85,12 @@ module.exports = {
.modalFooterOKClick()
.pause(2000)
.switchBrowserTab(1)
.assert.urlContains('https://gist.github.com')
.perform((done) => {
if (runtimeBrowser === 'chrome') {
browser.assert.urlContains('https://gist.github.com')
}
done()
})
.end()
},

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

@ -19,6 +19,8 @@ module.exports = {
- switch to a file in the new gist
*/
console.log('token', process.env.gist_token)
const runtimeBrowser = browser.capabilities.browserName
browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('fileExplorers')
@ -35,7 +37,7 @@ module.exports = {
browser
.modalFooterCancelClick()
.executeScript(`remix.loadgist('${gistid}')`)
.switchFile('browser/gists')
.perform((done) => { if (runtimeBrowser === 'chrome') { browser.switchFile('browser/gists') } done() })
.switchFile(`browser/gists/${gistid}`)
.switchFile(`browser/gists/${gistid}/1_Storage.sol`)
.perform(done)

@ -52,24 +52,23 @@ module.exports = {
when a relative import is used (i.e import "openzeppelin-solidity/contracts/math/SafeMath.sol")
remix (as well as truffle) try to resolve it against the node_modules and installed_contracts folder.
*/
browser
.waitForElementVisible('#icon-panel', 2000)
.clickLaunchIcon('fileExplorers')
.addFile('test_import_node_modules.sol', sources[3]['browser/test_import_node_modules.sol'])
.clickLaunchIcon('solidity')
.testContracts('test_import_node_modules.sol', sources[3]['browser/test_import_node_modules.sol'], ['SafeMath'])
browser.waitForElementVisible('#icon-panel', 2000)
.clickLaunchIcon('fileExplorers')
.addFile('test_import_node_modules.sol', sources[3]['browser/test_import_node_modules.sol'])
.clickLaunchIcon('solidity')
.testContracts('test_import_node_modules.sol', sources[3]['browser/test_import_node_modules.sol'], ['SafeMath'])
},
'Import from node_modules and reference a github import': function (browser) {
browser
.waitForElementVisible('#icon-panel', 2000)
.clickLaunchIcon('fileExplorers')
.addFile('test_import_node_modules_with_github_import.sol', sources[4]['browser/test_import_node_modules_with_github_import.sol'])
.clickLaunchIcon('solidity')
.setSolidityCompilerVersion('soljson-v0.6.2+commit.bacdbe57.js') // open-zeppelin moved to pragma ^0.6.0
.testContracts('test_import_node_modules_with_github_import.sol', sources[4]['browser/test_import_node_modules_with_github_import.sol'], ['ERC20', 'test11'])
.clickLaunchIcon('pluginManager')
.scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_remixd"] button')
.end()
browser.waitForElementVisible('#icon-panel', 2000)
.clickLaunchIcon('fileExplorers')
.addFile('test_import_node_modules_with_github_import.sol', sources[4]['browser/test_import_node_modules_with_github_import.sol'])
.clickLaunchIcon('solidity')
.setSolidityCompilerVersion('soljson-v0.6.2+commit.bacdbe57.js') // open-zeppelin moved to pragma ^0.6.0
.testContracts('test_import_node_modules_with_github_import.sol', sources[4]['browser/test_import_node_modules_with_github_import.sol'], ['ERC20', 'test11'])
.clickLaunchIcon('pluginManager')
.scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_remixd"] button')
.end()
},
tearDown: sauce
}
@ -81,11 +80,7 @@ function runTests (browser, testData) {
browser.end()
return
}
if (browserName === 'firefox') {
console.log('do not run remixd test for ' + browserName + ': TODO to reenable later')
browser.end()
return
}
browser
.waitForElementVisible('#icon-panel', 2000)
.clickLaunchIcon('fileExplorers')

@ -26,6 +26,7 @@ function runTests (browser) {
.switchFile('browser/3_Ballot.sol')
.clickLaunchIcon('solidityUnitTesting')
.scrollAndClick('#runTestsTabRunAction')
.pause(5000)
.waitForElementPresent('#solidityUnittestsOutput div[class^="testPass"]')
.pause(10000)
.assert.containsText('#solidityUnittestsOutput', 'browser/4_Ballot_test.sol (BallotTest)')

@ -26,7 +26,7 @@ module.exports = {
browser
.waitForElementVisible('*[data-id="terminalCli"]')
.click('*[data-id="terminalCli"]')
.keys('remix.')
.sendKeys('*[data-id="terminalCliInput"]', 'remix.')
.assert.visible('*[data-id="autoCompletePopUpAutoCompleteItem"]')
},

Loading…
Cancel
Save