Merge pull request #1465 from ethereum/generateTestFile

Testing Tab
pull/1/head
yann300 7 years ago committed by GitHub
commit 4064d19f6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/app/panels/righthand-panel.js
  2. 9
      src/app/tabs/styles/test-tab-styles.js
  3. 95
      src/app/tabs/test-tab.js
  4. 6
      src/app/ui/styles-guide/style-guide.js
  5. 26
      src/app/ui/styles-guide/styleGuideDark.js
  6. 9
      src/lib/helper.js

@ -111,11 +111,11 @@ module.exports = class RighthandPanel {
const { compile, run, settings, analysis, debug, support, test } = self._components const { compile, run, settings, analysis, debug, support, test } = self._components
self._components.tabbedMenu.addTab('Compile', 'compileView', compile.render()) self._components.tabbedMenu.addTab('Compile', 'compileView', compile.render())
self._components.tabbedMenu.addTab('Run', 'runView', run.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('Analysis', 'staticanalysisView', analysis.render())
self._components.tabbedMenu.addTab('Testing', 'testView', test.render())
self._components.tabbedMenu.addTab('Debugger', 'debugView', debug.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('Support', 'supportView', support.render())
self._components.tabbedMenu.addTab('Test', 'testView', test.render())
self._components.tabbedMenu.selectTabByTitle('Compile') self._components.tabbedMenu.selectTabByTitle('Compile')
} }
// showDebugger () { // showDebugger () {

@ -49,6 +49,15 @@ var css = csjs`
.runButton { .runButton {
${styles.rightPanel.testTab.button_runTests}; ${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 module.exports = css

@ -1,5 +1,8 @@
var yo = require('yo-yo') var yo = require('yo-yo')
var async = require('async') 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 globalRegistry = require('../../global/registry')
var css = require('./styles/test-tab-styles') var css = require('./styles/test-tab-styles')
var remixTests = require('remix-tests') var remixTests = require('remix-tests')
@ -17,13 +20,12 @@ module.exports = class TestTab {
filePanel: self._components.registry.get('filepanel').api filePanel: self._components.registry.get('filepanel').api
} }
self.data = {} self.data = {}
self.testList = yo`<div class=${css.testList}></div>`
} }
render () { render () {
const self = this const self = this
var testsOutput = yo`<div class=${css.container} hidden='true' id="tests"></div>` var testsOutput = yo`<div class=${css.container} hidden='true' id="tests"></div>`
var testsSummary = 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) { var testCallback = function (result) {
testsOutput.hidden = false testsOutput.hidden = false
@ -79,29 +81,44 @@ module.exports = class TestTab {
}) })
} }
function getTests (self) { function getTests (self, cb) {
var path = self._deps.fileManager.currentPath() var path = self._deps.fileManager.currentPath()
var provider = self._deps.fileManager.fileProviderOf(path) var provider = self._deps.fileManager.fileProviderOf(path)
var tests = [] var tests = []
self._deps.fileManager.filesFromPath(path, (error, files) => { self._deps.fileManager.filesFromPath(path, (error, files) => {
if (error) return cb(error)
if (!error) { if (!error) {
for (var file in files) { for (var file in files) {
if (/.(_test.sol)$/.exec(file)) tests.push(provider.type + '/' + file) if (/.(_test.sol)$/.exec(file)) tests.push(provider.type + '/' + file)
} }
cb(null, tests)
} }
}) })
return tests
} }
self._deps.filePanel.event.register('newTestFileCreated', file => { self._deps.filePanel.event.register('newTestFileCreated', file => {
var testList = document.querySelector("[class^='testList']") 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) testList.appendChild(test)
self.data.allTests.push(file) self.data.allTests.push(file)
self.data.selectedTests.push(file) self.data.selectedTests.push(file)
}) })
self._deps.fileManager.event.register('currentFileChanged', (file, provider) => { 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) => { // self._events.filePanel.register('fileRenamed', (oldName, newName, isFolder) => {
@ -129,15 +146,37 @@ module.exports = class TestTab {
async.eachOfSeries(tests, (value, key, callback) => { runTest(value, callback) }) 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` var el = yo`
<div class="${css.testTabView}" id="testView"> <div class="${css.testTabView}" id="testView">
<div class="${css.infoBox}"> <div class="${css.infoBox}">
Test your smart contract by creating a foo_test.sol file. <div class="${css.title}">Unit Testing</div>
Open ballot_test.sol to see the example. For more details, see 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. How to test smart contracts guide in our documentation.
<div class=${css.generateTestFile} onclick=${generateTestFile}>Generate test file</div>
</div> </div>
<div class="${css.tests}"> <div class="${css.tests}">
<div class=${css.testList}>${listTests()}</div> ${self.testList}
<div class=${css.buttons}> <div class=${css.buttons}>
<div class=${css.runButton} onclick=${runTests}>Run Tests</div> <div class=${css.runButton} onclick=${runTests}>Run Tests</div>
</div> </div>
@ -150,3 +189,43 @@ module.exports = class TestTab {
return el 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;
}
}`

@ -670,6 +670,12 @@ function styleGuide () {
Color: appProperties.primaryButton_TextColor 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_testPass: appProperties.success_BackgroundColor,
color_testFail: appProperties.danger_BackgroundColor color_testFail: appProperties.danger_BackgroundColor
}, },

@ -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 SETTINGS TAB
::::::::::::::: */ ::::::::::::::: */

@ -11,7 +11,7 @@ module.exports = {
var len = data.length var len = data.length
return data.slice(0, 5) + '...' + data.slice(len - 5, len) return data.slice(0, 5) + '...' + data.slice(len - 5, len)
}, },
createNonClashingName (name, fileProvider, cb) { createNonClashingNameWithPrefix (name, fileProvider, prefix, cb) {
var counter = '' var counter = ''
var ext = 'sol' var ext = 'sol'
var reg = /(.*)\.([^.]+)/g var reg = /(.*)\.([^.]+)/g
@ -24,7 +24,7 @@ module.exports = {
async.whilst( async.whilst(
() => { return exist }, () => { return exist },
(callback) => { (callback) => {
fileProvider.exists(name + counter + '.' + ext, (error, currentExist) => { fileProvider.exists(name + counter + prefix + '.' + ext, (error, currentExist) => {
if (error) { if (error) {
callback(error) callback(error)
} else { } else {
@ -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) { checkSpecialChars (name) {
return name.match(/[/:*?"<>\\'|]/) != null return name.match(/[/:*?"<>\\'|]/) != null
}, },

Loading…
Cancel
Save