Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests logic #1369

Merged
merged 8 commits into from
Jul 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
self._components.filePanel = new FilePanel()
self._view.leftpanel.appendChild(self._components.filePanel.render())
self._components.filePanel.event.register('resize', delta => self._adjustLayout('left', delta))
registry.put({api: self._components.filePanel, name: 'filepanel'})

// ----------------- Renderer -----------------
var renderer = new Renderer()
Expand Down
1 change: 1 addition & 0 deletions src/app/files/fileManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ class FileManager {
}

fileProviderOf (file) {
if (!file) return null
var provider = file.match(/[^/]*/)
if (provider !== null && this._deps.filesProviders[provider[0]]) {
return this._deps.filesProviders[provider[0]]
Expand Down
6 changes: 5 additions & 1 deletion src/app/panels/file-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,11 @@ function filepanel (localRegistry) {
if (!self._deps.fileProviders['browser'].set(newName, '')) {
modalDialogCustom.alert('Failed to create file ' + newName)
} else {
self._deps.fileManager.switchFile(self._deps.fileProviders['browser'].type + '/' + newName)
var file = self._deps.fileProviders['browser'].type + '/' + newName
self._deps.fileManager.switchFile(file)
if (file.includes('_test.sol')) {
self.event.trigger('newTestFileCreated', [file])
}
}
})
}, null, true)
Expand Down
94 changes: 46 additions & 48 deletions src/app/tabs/styles/test-tab-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,52 @@ var styleGuide = require('../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()

var css = csjs`
.opts_li {
display: block;
font-weight: bold;
color: ${styles.rightPanel.text_Teriary};
}
.opts_li.active {
color: ${styles.rightPanel.text_Primary};
}
.opts_li:hover {
color: ${styles.rightPanel.icon_HoverColor_TogglePanel};
}
.solIcon {
margin-left: 10px;
margin-right: 30px;
display: flex;
align-self: center;
height: 29px;
width: 20px;
background-color: ${styles.colors.transparent};
}
a {
color: ${styles.rightPanel.text_link};
}
#optionViews > div {
display: none;
}
#optionViews .pre {
word-wrap: break-word;
background-color: ${styles.rightPanel.BackgroundColor_Pre};
border-radius: 3px;
display: inline-block;
padding: 0 0.6em;
}
#optionViews .hide {
display: none;
}
.infoBox {
${styles.infoTextBox}
margin-bottom: 1em;
}
.textBox {
${styles.textBoxL}
margin-bottom: 1em;
}
.icon {
height: 70%;
margin-right: 2%;
}
.testTabView {}
.infoBox {
${styles.rightPanel.testTab.box_listTests};
margin: 2%;
}
.tests {}
.testList {
${styles.rightPanel.testTab.box_listTests};
line-height: 2em;
display: flex;
flex-direction: column;
margin: 2%;
}
.container {
${styles.rightPanel.testTab.box_listTests};
margin: 2%;
padding-bottom: 5%;
}
.outputTitle {
font-weight: bold;
margin: 10px 0;
}
.summaryTitle {
font-weight: bold;
}
.testPass {
background-color: ${styles.rightPanel.testTab.color_testPass};
}
.testLog {
margin-bottom: 1%;
border-radius: 4px;
padding: 1% 1% 1% 5%;
}
.testFailure {
background-color: ${styles.rightPanel.testTab.color_testFail};
}
.testFailureSummary {
color: ${styles.appProperties.errorText_Color};
}
.buttons {
${styles.rightPanel.testTab.box_listTests};
margin: 2%;
}
.runButton {
${styles.rightPanel.testTab.button_runTests};
}
`

module.exports = css
125 changes: 80 additions & 45 deletions src/app/tabs/test-tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,101 +13,136 @@ module.exports = class TestTab {
// dependencies
self._deps = {
fileManager: self._components.registry.get('filemanager').api,
app: self._components.registry.get('app').api
app: self._components.registry.get('app').api,
filePanel: self._components.registry.get('filepanel').api
}
self.data = {}

self._view.el = self.render()
self._deps.app.event.register('tabChanged', tabName => {
if (tabName !== 'test') return
yo.update(self._view.el, self.render())
self._view.el.style.display = 'block'
})

return { render () { return self._view.el } }
}
render () {
var self = this
var container = yo`<div class="tests" id="tests"></div>`

function append (container, txt) {
let child = yo`<div>${txt}</div>`
container.appendChild(child)
}
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]

let testCallback = function (result) {
var testCallback = function (result) {
testsOutput.hidden = false
if (result.type === 'contract') {
append(container, '\n ' + result.value)
testsOutput.appendChild(yo`<div class=${css.outputTitle}>${result.filename} (${result.value})</div>`)
} else if (result.type === 'testPass') {
append(container, '\t✓ ' + result.value)
testsOutput.appendChild(yo`<div class='${css.testPass} ${css.testLog}'>✓ (${result.value})</div>`)
} else if (result.type === 'testFailure') {
append(container, '\t✘ ' + result.value)
testsOutput.appendChild(yo`<div class='${css.testFailure} ${css.testLog}'>✘ (${result.value})</div>`)
}
}

let resultsCallback = function (_err, result, cb) {
var resultsCallback = function (_err, result, cb) {
// total stats for the test
// result.passingNum
// result.failureNum
// result.timePassed
cb()
}

let updateFinalResult = function (_err, result) {
var updateFinalResult = function (_err, result, filename) {
testsSummary.hidden = false
testsSummary.appendChild(yo`<div class=${css.summaryTitle}> ${filename} </div>`)
if (result.totalPassing > 0) {
append(container, (' ' + result.totalPassing + ' passing ') + ('(' + result.totalTime + 's)'))
testsSummary.appendChild(yo`<div>${result.totalPassing} passing (${result.totalTime}s)</div>`)
testsSummary.appendChild(yo`<br>`)
}
if (result.totalFailing > 0) {
append(container, (' ' + result.totalFailing + ' failing'))
testsSummary.appendChild(yo`<div>${result.totalFailing} failing</div>`)
testsSummary.appendChild(yo`<br>`)
}

result.errors.forEach((error, index) => {
append(container, ' ' + (index + 1) + ') ' + error.context + ' ' + error.value)
append(container, '')
append(container, ('\t error: ' + error.message))
testsSummary.appendChild(yo`<div>${error.context} - ${error.value} </div>`)
testsSummary.appendChild(yo`<div class=${css.testFailureSummary} >error: ${error.message}</div>`)
testsSummary.appendChild(yo`<br>`)
})
}

function runTest (testFilePath, provider, callback) {
provider.get(testFilePath, (error, content) => {
function runTest (testFilePath, callback) {
self._deps.fileManager.fileProviderOf(testFilePath).get(testFilePath, (error, content) => {
if (!error) {
var runningTest = {}
runningTest[testFilePath] = { content }
remixTests.runTestSources(runningTest, testCallback, resultsCallback, (error, result) => {
updateFinalResult(error, result)
updateFinalResult(error, result, testFilePath)
callback(error)
}, (url, cb) => { this._deps.app.importFileCb(url, cb) })
}, (url, cb) => { self._deps.app.importFileCb(url, cb) })
}
})
}

let runTests = function () {
container.innerHTML = ''
var path = this._deps.fileManager.currentPath()
var provider = this._deps.fileManager.fileProviderOf(path)
function getTests (self) {
var path = self._deps.fileManager.currentPath()
var provider = self._deps.fileManager.fileProviderOf(path)
var tests = []
self._deps.fileManager.filesFromPath(path, (error, files) => {
if (!error) {
for (var file in files) {
if (/.(_test.sol)$/.exec(file)) tests.push(provider.type + '/' + file)
}
async.eachOfSeries(tests, (value, key, callback) => { runTest(value, provider, callback) })
}
})
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>`
testList.appendChild(test)
self.data.allTests.push(file)
self.data.selectedTests.push(file)
})

self._deps.fileManager.event.register('currentFileChanged', (file, provider) => {
})

// self._events.filePanel.register('fileRenamed', (oldName, newName, isFolder) => {
// debugger
// self.data.allTests = self.data.allTests.filter(e => e != oldName)
// self.data.selectedTests = self.data.selectedTests.filter(e => e !== oldName)
// if (/.(_test.sol)$/.exec(newName)) self.data.allTests.push(newName)
// })

function listTests () {
var tests = self.data.allTests
return tests.map(test => yo`<label><input onchange =${(e) => toggleCheckbox(e, test)} type="checkbox" checked="true">${test} </label>`)
}

function toggleCheckbox (e, test) {
var selectedTests = self.data.selectedTests
selectedTests = e.target.checked ? [...selectedTests, test] : selectedTests.filter(el => el !== test)
self.data.selectedTests = selectedTests
}

var runTests = function () {
testsOutput.innerHTML = ''
testsSummary.innerHTML = ''
var tests = self.data.selectedTests
async.eachOfSeries(tests, (value, key, callback) => { runTest(value, callback) })
}

var el = yo`
<div class="${css.testTabView} "id="testView">
<div>
<div class="${css.infoBox}">
</div>
<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
How to test smart contracts guide in our documentation.
</div>
<div class="${css.testList}">
<p><button onclick=${runTests}>Run Tests</button></p>
${container}
<div class="${css.tests}">
<div class=${css.testList}>${listTests()}</div>
<div class=${css.buttons}>
<div class=${css.runButton} onclick=${runTests}>Run Tests</div>
</div>
${testsOutput}
${testsSummary}
</div>
</div>
`
if (!self._view.el) self._view.el = el
return el
}
}
20 changes: 20 additions & 0 deletions src/app/ui/styles-guide/style-guide.js
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,26 @@ function styleGuide () {

},

/* ::::::::::::::
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
}),

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

/* ::::::::::::::
SETTINGS TAB
::::::::::::::: */
Expand Down