Merge pull request #937 from ethereum/recordTxsUI

Records Transactions GUI
pull/1/head
yann300 7 years ago committed by GitHub
commit c6c1b343fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 63
      src/app/tabs/run-tab.js
  2. 2
      src/recorder.js
  3. 37
      test-browser/helpers/contracts.js
  4. 2
      test-browser/tests/ballot.js
  5. 4
      test-browser/tests/compiling.js
  6. 130
      test-browser/tests/units/testRecorder.js

@ -177,6 +177,13 @@ var css = csjs`
.networkItem {
margin-right: 5px;
}
.clearinstance {
font-size: 20px;
cursor: pointer;
margin-right: 10px;
}
.transactionActions {
float: right;
`
module.exports = runTab
@ -184,13 +191,26 @@ module.exports = runTab
var instanceContainer = yo`<div class="${css.instanceContainer}"></div>`
var noInstancesText = yo`<div class="${css.noInstancesText}">0 contract Instances</div>`
var pendingTxsText = yo`<div class="${css.pendingTxsText}"></div>`
var pendingTxsText = yo`<span></span>`
function runTab (container, appAPI, appEvents, opts) {
var events = new EventManager()
var clearInstanceElement = yo`<i class="${css.clearinstance} fa fa-minus-square-o" title="Clear Instances List" aria-hidden="true"></i>`
clearInstanceElement.addEventListener('click', () => {
events.trigger('clearInstance', [])
})
var recorderInterface = makeRecorder(events, appAPI, appEvents)
var pendingTxsContainer = yo`
<div class="${css.pendingTxsContainer}">
${pendingTxsText}
<div class="${css.pendingTxsText}">
${pendingTxsText}
<span class="${css.transactionActions}">
${clearInstanceElement}
${recorderInterface.recordButton}
${recorderInterface.runButton}
</span>
</div>
</div>`
var el = yo`
@ -216,7 +236,7 @@ function runTab (container, appAPI, appEvents, opts) {
// set the final context. Cause it is possible that this is not the one we've originaly selected
selectExEnv.value = executionContext.getProvider()
fillAccountsList(appAPI, el)
clearInstance()
events.trigger('clearInstance', [])
})
})
selectExEnv.value = executionContext.getProvider()
@ -226,12 +246,11 @@ function runTab (container, appAPI, appEvents, opts) {
updatePendingTxs(container, appAPI)
}, 500)
var clearInstance = function () {
events.register('clearInstance', () => {
instanceContainer.innerHTML = '' // clear the instances list
noInstancesText.style.display = 'block'
instanceContainer.appendChild(noInstancesText)
events.trigger('clearInstance', [])
}
})
}
function fillAccountsList (appAPI, container) {
@ -275,29 +294,21 @@ function makeRecorder (events, appAPI, appEvents) {
})
var css2 = csjs`
.container {
margin: 10px;
display: flex;
justify-content: space-evenly;
width: 100%;
}
.recorder {
${styles.button}
width: 135px;
font-size: 20px;
cursor: pointer;
}
.runTxs {
${styles.button}
margin-left: 10px;
width: 135px;
font-size: 20px;
cursor: pointer;
}
`
var recordButton = yo`<button class="${css.transaction} savetransaction">save transactions</button>`
var runButton = yo`<button class="${css.transaction} runtransaction">run transactions</button>`
var el = yo`
<div class=${css2.container}>
${recordButton}
${runButton}
</div>
`
var recordButton = yo`<i class="fa fa-floppy-o savetransaction ${css2.recorder}" title="Save Transactions" aria-hidden="true"></i>`
var runButton = yo`<i class="fa fa-play runtransaction ${css2.runTxs}" title="Run Transactions" aria-hidden="true"></i>`
recordButton.onclick = () => {
var txJSON = JSON.stringify(recorder.getAll(), null, 2)
var path = appAPI.currentPath()
@ -335,10 +346,10 @@ function makeRecorder (events, appAPI, appEvents) {
})
}
} else {
modalDialogCustom.alert('Scenario File require JSON type')
modalDialogCustom.alert('A Scenario File is required. The file must be of type JSON. Use the "Save Transactions" Button to generate a new Scenario File.')
}
}
return el
return { recordButton, runButton }
}
/* ------------------------------------------------
section CONTRACT DROPDOWN and BUTTONS
@ -357,7 +368,7 @@ function contractDropdown (events, appAPI, appEvents, instanceContainer) {
})
var atAddressButtonInput = yo`<input class="${css.input} ataddressinput" placeholder="Load contract from Address" title="atAddress" />`
var createButtonInput = yo`<input class="${css.input}" placeholder="" title="Create" />`
var createButtonInput = yo`<input class="${css.input} create" placeholder="" title="Create" />`
var selectContractNames = yo`<select class="${css.contractNames}" disabled></select>`
function getSelectedContract () {
@ -371,6 +382,7 @@ function contractDropdown (events, appAPI, appEvents, instanceContainer) {
return null
}
appAPI.getSelectedContract = getSelectedContract
var el = yo`
<div class="${css.container}">
<div class="${css.subcontainer}">
@ -385,7 +397,6 @@ function contractDropdown (events, appAPI, appEvents, instanceContainer) {
${atAddressButtonInput}
<div class="${css.atAddress}" onclick=${function () { loadFromAddress(appAPI) }}>At Address</div>
</div>
<div class=${css.buttons}>${makeRecorder(events, appAPI, appEvents)}</div>
</div>
</div>
`

@ -21,7 +21,7 @@ class Recorder {
opts.events.executioncontext.register('contextChanged', () => {
self.clearAll()
})
opts.events.runtab.register('clearInstances', () => {
opts.events.runtab.register('clearInstance', () => {
self.clearAll()
})

@ -14,7 +14,10 @@ module.exports = {
addInstance,
clickFunction,
verifyCallReturnValue,
setEditorValue
createContract,
modalFooterOKClick,
setEditorValue,
getEditorValue
}
function getCompiledContracts (browser, compiled, callback) {
@ -34,6 +37,13 @@ function getCompiledContracts (browser, compiled, callback) {
})
}
function createContract (browser, inputParams, callback) {
browser.click('.runView')
.setValue('input.create', inputParams, function () {
browser.click('#runTabView div[class^="create"]').perform(function () { callback() })
})
}
function verifyContract (browser, compiledContractNames, callback) {
getCompiledContracts(browser, compiledContractNames, (result) => {
if (result.value) {
@ -96,7 +106,7 @@ function verifyCallReturnValue (browser, address, checks, done) {
return ret
}, [address], function (result) {
for (var k in checks) {
browser.assert.equal(checks[k], result.value[k])
browser.assert.equal(result.value[k], checks[k])
}
done()
})
@ -162,6 +172,29 @@ function addInstance (browser, address, callback) {
})
}
function getEditorValue (callback) {
this.perform((client, done) => {
this.execute(function (value) {
return document.getElementById('input').editor.getValue()
}, [], function (result) {
done(result.value)
callback(result.value)
})
})
return this
}
function modalFooterOKClick () {
this.perform((client, done) => {
this.execute(function () {
document.querySelector('#modal-footer-ok').click()
}, [], function (result) {
done()
})
})
return this
}
function addFile (browser, name, content, done) {
browser.click('.newFile')
.perform((client, done) => {

@ -23,6 +23,8 @@ module.exports = {
function runTests (browser, testData) {
browser.testFunction = contractHelper.testFunction
browser.clickFunction = contractHelper.clickFunction
browser.modalFooterOKClick = contractHelper.modalFooterOKClick
browser.setEditorValue = contractHelper.setEditorValue
browser
.waitForElementVisible('.newFile', 10000)

@ -22,12 +22,14 @@ function runTests (browser) {
browser.testFunction = contractHelper.testFunction
browser.clickFunction = contractHelper.clickFunction
browser.setEditorValue = contractHelper.setEditorValue
browser.modalFooterOKClick = contractHelper.modalFooterOKClick
browser.getEditorValue = contractHelper.getEditorValue
browser
.waitForElementVisible('.newFile', 10000)
.click('.compileView')
.perform(() => {
// the first fn is used to pass browser to the other ones.
async.waterfall([function (callback) { callback(null, browser) }, testSimpleContract, testReturnValues, testInputValues, testRecorder], function () {
async.waterfall([function (callback) { callback(null, browser) }, testSimpleContract, testReturnValues, testInputValues, testRecorder.test], function () {
browser.end()
})
})

@ -1,21 +1,59 @@
'use strict'
var contractHelper = require('../../helpers/contracts')
module.exports = function (browser, callback) {
contractHelper.addFile(browser, 'scenario.json', {content: records}, () => {
browser
.click('.runView')
.click('#runTabView .runtransaction')
.clickFunction('getInt - call')
.clickFunction('getAddress - call')
.clickFunction('getFromLib - call')
.waitForElementPresent('div[class^="contractProperty"] div[class^="value"]')
.perform(() => {
contractHelper.verifyCallReturnValue(browser, '0x35ef07393b57464e93deb59175ff72e6499450cf', ['0: uint256: 1', '0: uint256: 3456', '0: address: 0xca35b7d915458ef540ade6068dfe2f44e8fa733c'], () => { callback() })
module.exports = {
'@sources': function () {
return sources
},
test: function (browser, callback) {
contractHelper.addFile(browser, 'scenario.json', {content: records}, () => {
browser
.click('.runView')
.click('#runTabView .runtransaction')
.clickFunction('getInt - call')
.clickFunction('getAddress - call')
.clickFunction('getFromLib - call')
.waitForElementPresent('div[class^="contractProperty"] div[class^="value"]')
.perform((client, done) => {
contractHelper.verifyCallReturnValue(browser, '0x35ef07393b57464e93deb59175ff72e6499450cf', ['0: uint256: 1', '0: uint256: 3456', '0: address: 0xca35b7d915458ef540ade6068dfe2f44e8fa733c'], () => {
done()
})
})
.click('i[class^="clearinstance"]')
.perform((client, done) => {
contractHelper.testContracts(browser, 'testRecorder.sol', sources[0]['browser/testRecorder.sol'], ['testRecorder'], function () {
contractHelper.createContract(browser, '12', function () {
browser.clickFunction('set - transact (not payable)', {types: 'uint256 _p', values: '34'})
.click('i.savetransaction').modalFooterOKClick().getEditorValue(function (result) {
var parsed = JSON.parse(result)
browser.assert.equal(JSON.stringify(parsed.transactions[0].record.parameters), JSON.stringify(scenario.transactions[0].record.parameters))
browser.assert.equal(JSON.stringify(parsed.transactions[0].record.name), JSON.stringify(scenario.transactions[0].record.name))
browser.assert.equal(JSON.stringify(parsed.transactions[0].record.type), JSON.stringify(scenario.transactions[0].record.type))
browser.assert.equal(JSON.stringify(parsed.transactions[0].record.from), JSON.stringify(scenario.transactions[0].record.from))
browser.assert.equal(JSON.stringify(parsed.transactions[0].record.contractName), JSON.stringify(scenario.transactions[0].record.contractName))
browser.assert.equal(JSON.stringify(parsed.transactions[1].record.parameters), JSON.stringify(scenario.transactions[1].record.parameters))
browser.assert.equal(JSON.stringify(parsed.transactions[1].record.name), JSON.stringify(scenario.transactions[1].record.name))
browser.assert.equal(JSON.stringify(parsed.transactions[1].record.type), JSON.stringify(scenario.transactions[1].record.type))
browser.assert.equal(JSON.stringify(parsed.transactions[1].record.from), JSON.stringify(scenario.transactions[1].record.from))
callback()
})
})
})
})
})
})
}
}
var sources = [{'browser/testRecorder.sol': {content: `pragma solidity ^0.4.0;contract testRecorder {
function testRecorder(uint p) {
}
function set (uint _p) {
}
}`}}]
var records = `{
"accounts": {
"account{0}": "0xca35b7d915458ef540ade6068dfe2f44e8fa733c"
@ -170,3 +208,71 @@ var records = `{
]
}
}`
var scenario = {
'accounts': {
'account{0}': '0xca35b7d915458ef540ade6068dfe2f44e8fa733c'
},
'linkReferences': {},
'transactions': [
{
'timestamp': 1512912691086,
'record': {
'value': '0',
'parameters': [
12
],
'abi': '0x54a8c0ab653c15bfb48b47fd011ba2b9617af01cb45cab344acd57c924d56798',
'contractName': 'testRecorder',
'bytecode': '6060604052341561000f57600080fd5b6040516020806100cd833981016040528080519060200190919050505060938061003a6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506064565b005b505600a165627a7a723058204839660366b94f5f3c8c6da233a2c5fe95ad5635b5c8a2bb630a8b845d68ecdd0029',
'linkReferences': {},
'name': '',
'type': 'constructor',
'from': 'account{0}'
}
},
{
'timestamp': 1512912696128,
'record': {
'value': '0',
'parameters': [
34
],
'to': 'created{1512912691086}',
'abi': '0x54a8c0ab653c15bfb48b47fd011ba2b9617af01cb45cab344acd57c924d56798',
'name': 'set',
'type': 'function',
'from': 'account{0}'
}
}
],
'abis': {
'0x54a8c0ab653c15bfb48b47fd011ba2b9617af01cb45cab344acd57c924d56798': [
{
'constant': false,
'inputs': [
{
'name': '_p',
'type': 'uint256'
}
],
'name': 'set',
'outputs': [],
'payable': false,
'stateMutability': 'nonpayable',
'type': 'function'
},
{
'inputs': [
{
'name': 'p',
'type': 'uint256'
}
],
'payable': false,
'stateMutability': 'nonpayable',
'type': 'constructor'
}
]
}
}

Loading…
Cancel
Save