Merge pull request #2662 from ethereum/debugger-e2e-tests

Debugger Browser Tests
pull/1/head
yann300 5 years ago committed by GitHub
commit 415b8c9398
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      package.json
  2. 2
      src/app/editor/editor.js
  3. 8
      src/app/tabs/debugger/debuggerUI/ButtonNavigator.js
  4. 2
      src/app/tabs/debugger/debuggerUI/Slider.js
  5. 2
      src/app/tabs/debugger/debuggerUI/vmDebugger/SolidityLocals.js
  6. 2
      src/app/tabs/debugger/debuggerUI/vmDebugger/StepDetail.js
  7. 5
      src/app/ui/multiParamManager.js
  8. 2
      src/app/ui/txLogger.js
  9. 2
      src/app/ui/universal-dapp-ui.js
  10. 25
      test-browser/commands/debugTransaction.js
  11. 115
      test-browser/tests/debugger.js

@ -182,6 +182,7 @@
"nightwatch_local_publishContract": "nightwatch ./test-browser/tests/publishContract.js --config nightwatch.js --env chrome ", "nightwatch_local_publishContract": "nightwatch ./test-browser/tests/publishContract.js --config nightwatch.js --env chrome ",
"nightwatch_local_generalSettings": "nightwatch ./test-browser/tests/generalSettings.js --config nightwatch.js --env chrome ", "nightwatch_local_generalSettings": "nightwatch ./test-browser/tests/generalSettings.js --config nightwatch.js --env chrome ",
"nightwatch_local_fileExplorer": "nightwatch ./test-browser/tests/fileExplorer.js --config nightwatch.js --env chrome ", "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 ",
"onchange": "onchange build/app.js -- npm-run-all lint", "onchange": "onchange build/app.js -- npm-run-all lint",
"prepublish": "mkdirp build; npm-run-all -ls downloadsolc_root build", "prepublish": "mkdirp build; npm-run-all -ls downloadsolc_root build",
"remixd": "remixd -s ./contracts --remix-ide http://127.0.0.1:8080", "remixd": "remixd -s ./contracts --remix-ide http://127.0.0.1:8080",

@ -91,7 +91,7 @@ class Editor extends Plugin {
} }
// Editor Setup // Editor Setup
const el = yo`<div id="input"></div>` const el = yo`<div id="input" data-id="editorInput"></div>`
this.editor = ace.edit(el) this.editor = ace.edit(el)
ace.acequire('ace/ext/language_tools') ace.acequire('ace/ext/language_tools')

@ -47,15 +47,15 @@ ButtonNavigator.prototype.render = function () {
var view = yo`<div class="${css.buttons}"> var view = yo`<div class="${css.buttons}">
<div class="${css.stepButtons} btn-group p-1"> <div class="${css.stepButtons} btn-group p-1">
<button id='overback' class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-reply' title='Step over back' onclick=${function () { self.event.trigger('stepOverBack') }} disabled=${this.overBackDisabled} ></button> <button id='overback' class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-reply' title='Step over back' onclick=${function () { self.event.trigger('stepOverBack') }} disabled=${this.overBackDisabled} ></button>
<button id='intoback' class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-level-up-alt' title='Step back' onclick=${function () { self.event.trigger('stepIntoBack') }} disabled=${this.intoBackDisabled} ></button> <button id='intoback' data-id="buttonNavigatorIntoBack" class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-level-up-alt' title='Step back' onclick=${function () { self.event.trigger('stepIntoBack') }} disabled=${this.intoBackDisabled} ></button>
<button id='intoforward' class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-level-down-alt' title='Step into' onclick=${function () { self.event.trigger('stepIntoForward') }} disabled=${this.intoForwardDisabled} ></button> <button id='intoforward' data-id="buttonNavigatorIntoForward" class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-level-down-alt' title='Step into' onclick=${function () { self.event.trigger('stepIntoForward') }} disabled=${this.intoForwardDisabled} ></button>
<button id='overforward' class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-share' title='Step over forward'onclick=${function () { self.event.trigger('stepOverForward') }} disabled=${this.overForwardDisabled} ></button> <button id='overforward' class='btn btn-primary btn-sm ${css.navigator} ${css.stepButton} fas fa-share' title='Step over forward'onclick=${function () { self.event.trigger('stepOverForward') }} disabled=${this.overForwardDisabled} ></button>
</div> </div>
<div class="${css.jumpButtons} btn-group p-1"> <div class="${css.jumpButtons} btn-group p-1">
<button class='btn btn-primary btn-sm ${css.navigator} ${css.jumpButton} fas fa-step-backward' id='jumppreviousbreakpoint' title='Jump to the previous breakpoint' onclick=${function () { self.event.trigger('jumpPreviousBreakpoint') }} disabled=${this.jumpPreviousBreakpointDisabled} ></button> <button class='btn btn-primary btn-sm ${css.navigator} ${css.jumpButton} fas fa-step-backward' id='jumppreviousbreakpoint' data-id="buttonNavigatorJumpPreviousBreakpoint" title='Jump to the previous breakpoint' onclick=${function () { self.event.trigger('jumpPreviousBreakpoint') }} disabled=${this.jumpPreviousBreakpointDisabled} ></button>
<button class='btn btn-primary btn-sm ${css.navigator} ${css.jumpButton} fas fa-eject' id='jumpout' title='Jump out' onclick=${function () { self.event.trigger('jumpOut') }} disabled=${this.jumpOutDisabled} ></button> <button class='btn btn-primary btn-sm ${css.navigator} ${css.jumpButton} fas fa-eject' id='jumpout' title='Jump out' onclick=${function () { self.event.trigger('jumpOut') }} disabled=${this.jumpOutDisabled} ></button>
<button class='btn btn-primary btn-sm ${css.navigator} ${css.jumpButton} fas fa-step-forward' id='jumpnextbreakpoint' title='Jump to the next breakpoint' onclick=${function () { self.event.trigger('jumpNextBreakpoint') }} disabled=${this.jumpNextBreakpointDisabled} ></button> <button class='btn btn-primary btn-sm ${css.navigator} ${css.jumpButton} fas fa-step-forward' id='jumpnextbreakpoint' data-id="buttonNavigatorJumpNextBreakpoint" title='Jump to the next breakpoint' onclick=${function () { self.event.trigger('jumpNextBreakpoint') }} disabled=${this.jumpNextBreakpointDisabled} ></button>
</div> </div>
<div id='reverted' style="display:none"> <div id='reverted' style="display:none">
<button class='btn btn-danger btn-sm' id='jumptoexception' title='Jump to exception' class='${css.navigator} ${css.button} fas fa-exclamation-triangle' onclick=${function () { self.event.trigger('jumpToException') }} disabled=${this.jumpOutDisabled} > <button class='btn btn-danger btn-sm' id='jumptoexception' title='Jump to exception' class='${css.navigator} ${css.button} fas fa-exclamation-triangle' onclick=${function () { self.event.trigger('jumpToException') }} disabled=${this.jumpOutDisabled} >

@ -43,7 +43,7 @@ class Slider {
render () { render () {
var self = this var self = this
var view = yo`<div> var view = yo`<div>
<input id='slider' style='width: 100%' type='range' min=0 max=${this.max} value=0 <input id='slider' data-id="slider" style='width: 100%' type='range' min=0 max=${this.max} value=0
onchange=${function () { self.onChange() }} oninput=${function () { self.onChange() }} disabled=${this.disabled} /> onchange=${function () { self.onChange() }} oninput=${function () { self.onChange() }} disabled=${this.disabled} />
</div>` </div>`
if (!this.view) { if (!this.view) {

@ -29,7 +29,7 @@ class SolidityLocals {
} }
render () { render () {
this.view = yo`<div id='soliditylocals'>${this.basicPanel.render()}</div>` this.view = yo`<div id='soliditylocals' data-id="solidityLocals">${this.basicPanel.render()}</div>`
return this.view return this.view
} }
} }

@ -17,7 +17,7 @@ StepDetail.prototype.updateField = function (key, value) {
} }
StepDetail.prototype.render = function () { StepDetail.prototype.render = function () {
return yo`<div id='stepdetail' >${this.basicPanel.render()}</div>` return yo`<div id='stepdetail' data-id="stepdetail">${this.basicPanel.render()}</div>`
} }
module.exports = StepDetail module.exports = StepDetail

@ -119,6 +119,7 @@ class MultiParamManager {
this.basicInputField = yo`<input class="form-control"></input>` this.basicInputField = yo`<input class="form-control"></input>`
this.basicInputField.setAttribute('placeholder', this.inputs) this.basicInputField.setAttribute('placeholder', this.inputs)
this.basicInputField.setAttribute('title', this.inputs) this.basicInputField.setAttribute('title', this.inputs)
this.basicInputField.setAttribute('data-id', this.inputs)
var onClick = () => { var onClick = () => {
this.clickCallBack(this.funABI.inputs, this.basicInputField.value) this.clickCallBack(this.funABI.inputs, this.basicInputField.value)
@ -185,6 +186,7 @@ class MultiParamManager {
expandedButton.classList.add('btn-info') expandedButton.classList.add('btn-info')
funcButton.setAttribute('title', (title + ' - call')) funcButton.setAttribute('title', (title + ' - call'))
funcButton.classList.add('btn-info') funcButton.classList.add('btn-info')
funcButton.setAttribute('data-id', (title + ' - call'))
} else if (this.funABI.stateMutability === 'payable' || this.funABI.payable) { } else if (this.funABI.stateMutability === 'payable' || this.funABI.payable) {
// transact. stateMutability = payable // transact. stateMutability = payable
expandedButton.setAttribute('title', (title + ' - transact (payable)')) expandedButton.setAttribute('title', (title + ' - transact (payable)'))
@ -192,6 +194,7 @@ class MultiParamManager {
expandedButton.classList.add('btn-danger') expandedButton.classList.add('btn-danger')
funcButton.setAttribute('title', (title + ' - transact (payable)')) funcButton.setAttribute('title', (title + ' - transact (payable)'))
funcButton.classList.add('btn-danger') funcButton.classList.add('btn-danger')
funcButton.setAttribute('data-id', (title + ' - transact (payable)'))
} else { } else {
// transact. stateMutability = nonpayable // transact. stateMutability = nonpayable
expandedButton.setAttribute('title', (title + ' - transact (not payable)')) expandedButton.setAttribute('title', (title + ' - transact (not payable)'))
@ -199,6 +202,7 @@ class MultiParamManager {
expandedButton.classList.add('btn-warning') expandedButton.classList.add('btn-warning')
funcButton.classList.add('btn-warning') funcButton.classList.add('btn-warning')
funcButton.setAttribute('title', (title + ' - transact (not payable)')) funcButton.setAttribute('title', (title + ' - transact (not payable)'))
funcButton.setAttribute('data-id', (title + ' - transact (not payable)'))
} }
if (this.funABI.inputs && this.funABI.inputs.length > 0) { if (this.funABI.inputs && this.funABI.inputs.length > 0) {
@ -207,6 +211,7 @@ class MultiParamManager {
contractProperty.classList.add(css.hasArgs) contractProperty.classList.add(css.hasArgs)
this.basicInputField.setAttribute('title', `'(${this.funABI.type}')`) // probably should pass name instead this.basicInputField.setAttribute('title', `'(${this.funABI.type}')`) // probably should pass name instead
this.contractActionsContainerSingle.querySelector('i').style.visibility = 'hidden' this.contractActionsContainerSingle.querySelector('i').style.visibility = 'hidden'
this.basicInputField.setAttribute('data-id', `'(${this.funABI.type}')`)
} else { } else {
this.contractActionsContainerSingle.querySelector('i').style.visibility = 'hidden' this.contractActionsContainerSingle.querySelector('i').style.visibility = 'hidden'
this.basicInputField.style.visibility = 'hidden' this.basicInputField.style.visibility = 'hidden'

@ -215,7 +215,7 @@ function renderKnownTransaction (self, data, blockchain) {
${checkTxStatus(data.receipt, txType)} ${checkTxStatus(data.receipt, txType)}
${context(self, {from, to, data}, blockchain)} ${context(self, {from, to, data}, blockchain)}
<div class=${css.buttons}> <div class=${css.buttons}>
<button class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div> <button data-shared="txLoggerDebugButton" class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div>
</div> </div>
<i class="${css.arrow} fas fa-angle-down"></i> <i class="${css.arrow} fas fa-angle-down"></i>
</div> </div>

@ -60,7 +60,7 @@ UniversalDAppUI.prototype.renderInstanceFromABI = function (contractABI, address
var shortAddress = helper.shortenAddress(address) var shortAddress = helper.shortenAddress(address)
var title = yo` var title = yo`
<div class="${css.title} alert alert-secondary"> <div class="${css.title} alert alert-secondary">
<button class="btn ${css.titleExpander}" onclick="${(e) => { toggleClass(e) }}"> <button data-id="universalDappUiTitleExpander" class="btn ${css.titleExpander}" onclick="${(e) => { toggleClass(e) }}">
<i class="fas fa-angle-right" aria-hidden="true"></i> <i class="fas fa-angle-right" aria-hidden="true"></i>
</button> </button>
<div class="input-group ${css.nameNbuts}"> <div class="input-group ${css.nameNbuts}">

@ -0,0 +1,25 @@
const EventEmitter = require('events')
class debugTransaction extends EventEmitter {
command (index = 0) {
this.api.perform((done) => {
checkStyle(this.api, index, () => {
done()
this.emit('complete')
})
})
return this
}
}
function checkStyle (browser, index, callback) {
browser.pause(2000).execute(function (index) {
const debugBtn = document.querySelectorAll('*[data-shared="txLoggerDebugButton"]')[index]
debugBtn.click()
}, [index], function () {
callback()
})
}
module.exports = debugTransaction

@ -0,0 +1,115 @@
'use strict'
var init = require('../helpers/init')
var sauce = require('./sauce')
module.exports = {
before: function (browser, done) {
init(browser, done)
},
'@sources': function () {
return sources
},
'Should launch debugger': function (browser) {
browser.addFile('blah.sol', sources[0]['browser/blah.sol'])
.clickLaunchIcon('udapp')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]')
.click('*[title="Deploy - transact (not payable)"]')
.debugTransaction(0)
.assert.containsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER')
},
'Should debug failing transaction': function (browser) {
browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]')
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="universalDappUiTitleExpander"]')
.click('*[data-id="universalDappUiTitleExpander"]')
.scrollAndClick('*[title="string name, uint256 goal"]')
.setValue('*[title="string name, uint256 goal"]', '"toast", 999')
.click('*[data-id="createProject - transact (not payable)"]')
.debugTransaction(1)
.pause(2000)
.scrollAndClick('*[data-id="solidityLocals"]')
.assert.containsText('*[data-id="solidityLocals"]', 'toast')
.assert.containsText('*[data-id="solidityLocals"]', '999')
},
'Should debug transaction using slider': function (browser) {
browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]')
.waitForElementVisible('*[data-id="slider"]')
.click('*[data-id="slider"]')
.setValue('*[data-id="slider"]', 50)
.pause(2000)
.assert.containsText('*[data-id="solidityLocals"]', 'no locals')
.assert.containsText('*[data-id="stepdetail"]', 'vm trace step: 92')
},
'Should step back and forward transaction': function (browser) {
browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]')
.waitForElementPresent('*[data-id="buttonNavigatorIntoBack"]')
.scrollAndClick('*[data-id="buttonNavigatorIntoBack"]')
.pause(2000)
.assert.containsText('*[data-id="stepdetail"]', 'vm trace step: 91')
.assert.containsText('*[data-id="stepdetail"]', 'execution step: 91')
.click('*[data-id="buttonNavigatorIntoForward"]')
.pause(2000)
.assert.containsText('*[data-id="stepdetail"]', 'vm trace step: 92')
.assert.containsText('*[data-id="stepdetail"]', 'execution step: 92')
},
'Should jump through breakpoints': function (browser) {
browser.waitForElementVisible('*[data-id="editorInput"]')
.click('.ace_gutter-cell:nth-of-type(10)')
.click('.ace_gutter-cell:nth-of-type(20)')
.waitForElementVisible('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]')
.click('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]')
.pause(2000)
.assert.containsText('*[data-id="stepdetail"]', 'vm trace step: 0')
.assert.containsText('*[data-id="stepdetail"]', 'execution step: 0')
.click('*[data-id="buttonNavigatorJumpNextBreakpoint"]')
.pause(2000)
.assert.containsText('*[data-id="stepdetail"]', 'vm trace step: 140')
.assert.containsText('*[data-id="stepdetail"]', 'execution step: 140')
.end()
},
tearDown: sauce
}
var sources = [
{
'browser/blah.sol': {
content: `
pragma solidity >=0.4.22 <0.6.0;
contract Kickstarter {
enum State { Started, Completed }
struct Project {
address owner;
string name;
uint goal;
State state;
}
Project[] public projects;
constructor() public {
}
function createProject(string memory name, uint goal) public {
Project storage project = projects[projects.length];
project.name = name;
project.owner = msg.sender;
project.state = State.Started;
project.goal = goal;
}
}
`
}
}
]
Loading…
Cancel
Save