Skip to content

Commit

Permalink
Merge pull request ethereum#1465 from ethereum/generateTestFile
Browse files Browse the repository at this point in the history
Testing Tab
  • Loading branch information
yann300 authored Aug 17, 2018
2 parents 69ea9d5 + c53e1e4 commit 4064d19
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 13 deletions.
4 changes: 2 additions & 2 deletions src/app/panels/righthand-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ module.exports = class RighthandPanel {
const { compile, run, settings, analysis, debug, support, test } = self._components
self._components.tabbedMenu.addTab('Compile', 'compileView', compile.render())
self._components.tabbedMenu.addTab('Run', 'runView', run.render())
self._components.tabbedMenu.addTab('Settings', 'settingsView', settings.render())
self._components.tabbedMenu.addTab('Analysis', 'staticanalysisView', analysis.render())
self._components.tabbedMenu.addTab('Testing', 'testView', test.render())
self._components.tabbedMenu.addTab('Debugger', 'debugView', debug.render())
self._components.tabbedMenu.addTab('Settings', 'settingsView', settings.render())
self._components.tabbedMenu.addTab('Support', 'supportView', support.render())
self._components.tabbedMenu.addTab('Test', 'testView', test.render())
self._components.tabbedMenu.selectTabByTitle('Compile')
}
// showDebugger () {
Expand Down
9 changes: 9 additions & 0 deletions src/app/tabs/styles/test-tab-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ var css = csjs`
.runButton {
${styles.rightPanel.testTab.button_runTests};
}
.generateTestFile {
${styles.rightPanel.testTab.button_generateTestFile};
min-width: 100px
}
.title {
font-size: 1.1em;
font-weight: bold;
margin-bottom: 1em;
}
`

module.exports = css
95 changes: 87 additions & 8 deletions src/app/tabs/test-tab.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
var yo = require('yo-yo')
var async = require('async')
var helper = require('../../lib/helper.js')
var tooltip = require('../ui/tooltip')
var modalDialogCustom = require('../ui/modal-dialog-custom')
var globalRegistry = require('../../global/registry')
var css = require('./styles/test-tab-styles')
var remixTests = require('remix-tests')
Expand All @@ -17,13 +20,12 @@ module.exports = class TestTab {
filePanel: self._components.registry.get('filepanel').api
}
self.data = {}
self.testList = yo`<div class=${css.testList}></div>`
}
render () {
const self = this
var testsOutput = yo`<div class=${css.container} hidden='true' id="tests"></div>`
var testsSummary = yo`<div class=${css.container} hidden='true' id="tests"></div>`
self.data.allTests = getTests(self)
self.data.selectedTests = [...self.data.allTests]

var testCallback = function (result) {
testsOutput.hidden = false
Expand Down Expand Up @@ -79,29 +81,44 @@ module.exports = class TestTab {
})
}

function getTests (self) {
function getTests (self, cb) {
var path = self._deps.fileManager.currentPath()
var provider = self._deps.fileManager.fileProviderOf(path)
var tests = []
self._deps.fileManager.filesFromPath(path, (error, files) => {
if (error) return cb(error)
if (!error) {
for (var file in files) {
if (/.(_test.sol)$/.exec(file)) tests.push(provider.type + '/' + file)
}
cb(null, tests)
}
})
return tests
}

self._deps.filePanel.event.register('newTestFileCreated', file => {
var testList = document.querySelector("[class^='testList']")
var test = yo`<label><input onchange =${(e) => toggleCheckbox(e, file)} type="checkbox" checked="true">${file} </label>`
var test = yo`<label><input onchange=${(e) => toggleCheckbox(e, file)} type="checkbox" checked="true">${file}</label>`
testList.appendChild(test)
self.data.allTests.push(file)
self.data.selectedTests.push(file)
})

self._deps.fileManager.event.register('currentFileChanged', (file, provider) => {
getTests(self, (error, tests) => {
if (error) return tooltip(error)
self.data.allTests = tests
self.data.selectedTests = [...self.data.allTests]
if (!tests.length) {
yo.update(self.testList, yo`<div class=${css.testList}>No test file available</div>`)
} else {
yo.update(self.testList, yo`<div class=${css.testList}>${listTests()}</div>`)
}
testsOutput.hidden = true
testsSummary.hidden = true
testsOutput.innerHTML = ''
testsSummary.innerHTML = ''
})
})

// self._events.filePanel.register('fileRenamed', (oldName, newName, isFolder) => {
Expand Down Expand Up @@ -129,15 +146,37 @@ module.exports = class TestTab {
async.eachOfSeries(tests, (value, key, callback) => { runTest(value, callback) })
}

var generateTestFile = function () {
var fileManager = self._deps.fileManager
var path = fileManager.currentPath()
var fileProvider = fileManager.fileProviderOf(path)
if (fileProvider) {
helper.createNonClashingNameWithPrefix(path + '/test.sol', fileProvider, '_test', (error, newFile) => {
if (error) return modalDialogCustom.alert('Failed to create file. ' + newFile + ' ' + error)
if (!fileProvider.set(newFile, testContractSample)) {
modalDialogCustom.alert('Failed to create test file ' + newFile)
} else {
fileManager.switchFile(newFile)
}
})
}
}

var el = yo`
<div class="${css.testTabView}" id="testView">
<div class="${css.infoBox}">
Test your smart contract by creating a foo_test.sol file.
Open ballot_test.sol to see the example. For more details, see
<div class="${css.title}">Unit Testing</div>
Test your smart contract by creating a foo_test.sol file. Open ballot_test.sol to see the example.
<br/>
Then use the stand alone NPM module remix-tests to run unit tests in your Continuous Integration
<a href="https://www.npmjs.com/package/remix-tests">https://www.npmjs.com/package/remix-tests</a>.
<br/>
For more details, see
How to test smart contracts guide in our documentation.
<div class=${css.generateTestFile} onclick=${generateTestFile}>Generate test file</div>
</div>
<div class="${css.tests}">
<div class=${css.testList}>${listTests()}</div>
${self.testList}
<div class=${css.buttons}>
<div class=${css.runButton} onclick=${runTests}>Run Tests</div>
</div>
Expand All @@ -150,3 +189,43 @@ module.exports = class TestTab {
return el
}
}

var testContractSample = `pragma solidity ^0.4.0;
import "remix_tests.sol"; // this import is automatically injected by Remix.
// file name has to end with '_test.sol'
contract test_1 {
function beforeAll () {
// here should instanciate tested contract
}
function check1 () public {
// this function is not constant, use 'Assert' to test the contract
Assert.equal(uint(2), uint(1), "error message");
Assert.equal(uint(2), uint(2), "error message");
}
function check2 () public constant returns (bool) {
// this function is constant, use the return value (true or false) to test the contract
return true;
}
}
contract test_2 {
function beforeAll () {
// here should instanciate tested contract
}
function check1 () public {
// this function is not constant, use 'Assert' to test the contract
Assert.equal(uint(2), uint(1), "error message");
Assert.equal(uint(2), uint(2), "error message");
}
function check2 () public constant returns (bool) {
// this function is constant, use the return value (true or false) to test the contract
return true;
}
}`
6 changes: 6 additions & 0 deletions src/app/ui/styles-guide/style-guide.js
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,12 @@ function styleGuide () {
Color: appProperties.primaryButton_TextColor
}),

button_generateTestFile: appProperties.uiElements.button({
BackgroundColor: appProperties.primaryButton_BackgroundColor,
BorderColor: appProperties.primaryButton_BorderColor,
Color: appProperties.primaryButton_TextColor
}),

color_testPass: appProperties.success_BackgroundColor,
color_testFail: appProperties.danger_BackgroundColor
},
Expand Down
26 changes: 26 additions & 0 deletions src/app/ui/styles-guide/styleGuideDark.js
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,32 @@ function styleGuideDark () {

},

/* ::::::::::::::
TEST TAB
::::::::::::::: */
testTab: {
box_listTests: appProperties.uiElements.solidBorderBox({
BackgroundColor: appProperties.solidBorderBox_BackgroundColor,
BorderColor: appProperties.solidBorderBox_BackgroundColor,
Color: appProperties.solidBorderBox_TextColor
}),

button_runTests: appProperties.uiElements.button({
BackgroundColor: appProperties.primaryButton_BackgroundColor,
BorderColor: appProperties.primaryButton_BorderColor,
Color: appProperties.primaryButton_TextColor
}),

button_generateTestFile: appProperties.uiElements.button({
BackgroundColor: appProperties.primaryButton_BackgroundColor,
BorderColor: appProperties.primaryButton_BorderColor,
Color: appProperties.primaryButton_TextColor
}),

color_testPass: appProperties.success_BackgroundColor,
color_testFail: appProperties.danger_BackgroundColor
},

/* ::::::::::::::
SETTINGS TAB
::::::::::::::: */
Expand Down
9 changes: 6 additions & 3 deletions src/lib/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = {
var len = data.length
return data.slice(0, 5) + '...' + data.slice(len - 5, len)
},
createNonClashingName (name, fileProvider, cb) {
createNonClashingNameWithPrefix (name, fileProvider, prefix, cb) {
var counter = ''
var ext = 'sol'
var reg = /(.*)\.([^.]+)/g
Expand All @@ -24,7 +24,7 @@ module.exports = {
async.whilst(
() => { return exist },
(callback) => {
fileProvider.exists(name + counter + '.' + ext, (error, currentExist) => {
fileProvider.exists(name + counter + prefix + '.' + ext, (error, currentExist) => {
if (error) {
callback(error)
} else {
Expand All @@ -34,9 +34,12 @@ module.exports = {
}
})
},
(error) => { cb(error, name + counter + '.' + ext) }
(error) => { cb(error, name + counter + prefix + '.' + ext) }
)
},
createNonClashingName (name, fileProvider, cb) {
this.createNonClashingNameWithPrefix(name, fileProvider, '', cb)
},
checkSpecialChars (name) {
return name.match(/[/:*?"<>\\'|]/) != null
},
Expand Down

0 comments on commit 4064d19

Please sign in to comment.