Unverified Commit 4bf5f682 authored by yann300's avatar yann300 Committed by GitHub

Merge pull request #1046 from ethereum/fixlocalhost

Fix localhost explorer & add tests
parents 4c47a3f1 8d5d0398
contract test2 { function get () returns (uint) { return 11; }}
\ No newline at end of file
contract test2 { function get () returns (uint) { return 11; }}
\ No newline at end of file
...@@ -23,11 +23,13 @@ class BasicReadOnlyExplorer { ...@@ -23,11 +23,13 @@ class BasicReadOnlyExplorer {
exists (path) { exists (path) {
if (!this.files) return false if (!this.files) return false
return this.files[path] !== undefined var unprefixedPath = this.removePrefix(path)
return this.files[unprefixedPath] !== undefined
} }
get (path, cb) { get (path, cb) {
var content = this.files[path] var unprefixedPath = this.removePrefix(path)
var content = this.files[unprefixedPath]
if (!content) { if (!content) {
content = this.files[this.type + '/' + this.normalizedNames[path]] content = this.files[this.type + '/' + this.normalizedNames[path]]
} }
...@@ -48,6 +50,7 @@ class BasicReadOnlyExplorer { ...@@ -48,6 +50,7 @@ class BasicReadOnlyExplorer {
try { // lazy try to format JSON try { // lazy try to format JSON
content = JSON.stringify(JSON.parse(content), null, '\t') content = JSON.stringify(JSON.parse(content), null, '\t')
} catch (e) {} } catch (e) {}
if (!rawPath) rawPath = path
// splitting off the path in a tree structure, the json tree is used in `resolveDirectory` // splitting off the path in a tree structure, the json tree is used in `resolveDirectory`
var split = path var split = path
var folder = false var folder = false
......
...@@ -6,6 +6,7 @@ var modalDialogCustom = require('../ui/modal-dialog-custom') ...@@ -6,6 +6,7 @@ var modalDialogCustom = require('../ui/modal-dialog-custom')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager var EventManager = remixLib.EventManager
var contextMenu = require('../ui/contextMenu') var contextMenu = require('../ui/contextMenu')
var addTooltip = require('../ui/tooltip')
var helper = require('../../lib/helper') var helper = require('../../lib/helper')
var styleGuide = remixLib.ui.themeChooser var styleGuide = remixLib.ui.themeChooser
...@@ -163,11 +164,12 @@ function fileExplorer (appAPI, files) { ...@@ -163,11 +164,12 @@ function fileExplorer (appAPI, files) {
self.treeView.event.register('leafRightClick', function (key, data, label, event) { self.treeView.event.register('leafRightClick', function (key, data, label, event) {
contextMenu(event, { contextMenu(event, {
'Rename': () => { 'Rename': () => {
if (self.files.readonly) return if (self.files.readonly) { return addTooltip('cannot rename. ' + self.files.type + ' is a read only explorer') }
var name = label.querySelector('label[data-path="' + key + '"]') var name = label.querySelector('label[data-path="' + key + '"]')
if (name) editModeOn(name) if (name) editModeOn(name)
}, },
'Delete': () => { 'Delete': () => {
if (self.files.readonly) { return addTooltip('cannot delete. ' + self.files.type + ' is a read only explorer') }
modalDialogCustom.confirm(null, 'Do you want to delete this file?', () => { files.remove(key) }, () => {}) modalDialogCustom.confirm(null, 'Do you want to delete this file?', () => { files.remove(key) }, () => {})
} }
}) })
...@@ -218,13 +220,21 @@ function fileExplorer (appAPI, files) { ...@@ -218,13 +220,21 @@ function fileExplorer (appAPI, files) {
}) })
var textUnderEdit = null var textUnderEdit = null
var textInRename = false
function selectElementContents (el) {
var range = document.createRange()
range.selectNodeContents(el)
var sel = window.getSelection()
sel.removeAllRanges()
sel.addRange(range)
}
function editModeOn (label) { function editModeOn (label) {
textUnderEdit = label.innerText textUnderEdit = label.innerText
label.setAttribute('contenteditable', true) label.setAttribute('contenteditable', true)
label.classList.add(css.rename) label.classList.add(css.rename)
label.focus() label.focus()
selectElementContents(label)
} }
function editModeOff (event) { function editModeOff (event) {
...@@ -249,8 +259,7 @@ function fileExplorer (appAPI, files) { ...@@ -249,8 +259,7 @@ function fileExplorer (appAPI, files) {
} }
if (event.which === 13) event.preventDefault() if (event.which === 13) event.preventDefault()
if (!textInRename && (event.type === 'blur' || event.which === 27 || event.which === 13) && label.getAttribute('contenteditable')) { if (event.type === 'blur' || event.which === 13 && label.getAttribute('contenteditable')) {
textInRename = true
var isFolder = label.className.indexOf('folder') !== -1 var isFolder = label.className.indexOf('folder') !== -1
var save = textUnderEdit !== label.innerText var save = textUnderEdit !== label.innerText
if (save) { if (save) {
...@@ -258,7 +267,6 @@ function fileExplorer (appAPI, files) { ...@@ -258,7 +267,6 @@ function fileExplorer (appAPI, files) {
} }
label.removeAttribute('contenteditable') label.removeAttribute('contenteditable')
label.classList.remove(css.rename) label.classList.remove(css.rename)
textInRename = false
} }
} }
} }
......
...@@ -114,8 +114,6 @@ class FileManager { ...@@ -114,8 +114,6 @@ class FileManager {
return $(this).find('.name').text() === newfile return $(this).find('.name').text() === newfile
}) })
if (active.length) active.addClass('active') if (active.length) active.addClass('active')
else this.switchFile()
// $('#input').toggle(active)
$('#output').toggle(active) $('#output').toggle(active)
} }
......
...@@ -49,8 +49,10 @@ module.exports = class SharedFolder { ...@@ -49,8 +49,10 @@ module.exports = class SharedFolder {
} }
init (cb) { init (cb) {
this._isReady = true this._remixd.ensureSocket((error) => {
cb() this._isReady = !error
cb(error)
})
} }
// @TODO: refactor all `this._remixd.call(....)` uses into `this.remixd[api](...)` // @TODO: refactor all `this._remixd.call(....)` uses into `this.remixd[api](...)`
......
...@@ -13,6 +13,7 @@ var css = csjs` ...@@ -13,6 +13,7 @@ var css = csjs`
width:150px; width:150px;
background: ${styles.appProperties.solidBorderBox_BackgroundColor}; background: ${styles.appProperties.solidBorderBox_BackgroundColor};
border-radius: 2px; border-radius: 2px;
z-index: 1000;
} }
.liitem .liitem
...@@ -42,9 +43,17 @@ var css = csjs` ...@@ -42,9 +43,17 @@ var css = csjs`
module.exports = (event, items) => { module.exports = (event, items) => {
event.preventDefault() event.preventDefault()
function hide (event, force) {
if (force || (event.target !== container)) {
container.parentElement.removeChild(container)
}
window.removeEventListener('click', hide)
}
var menu = Object.keys(items).map((item, index) => { var menu = Object.keys(items).map((item, index) => {
var current = yo`<li class=${css.liitem}>${item}</li>` var current = yo`<li id="menuitem${item.toLowerCase()}" class=${css.liitem}>${item}</li>`
current.onclick = () => items[item]() current.onclick = () => { hide(null, true); items[item]() }
return current return current
}) })
var container = yo`<div class=${css.container}><ul id='menuitems'>${menu}</ul></div>` var container = yo`<div class=${css.container}><ul id='menuitems'>${menu}</ul></div>`
...@@ -52,12 +61,8 @@ module.exports = (event, items) => { ...@@ -52,12 +61,8 @@ module.exports = (event, items) => {
container.style.top = event.pageY + 'px' container.style.top = event.pageY + 'px'
container.style.display = 'block' container.style.display = 'block'
function hide (event) {
if (event.target !== container) {
container.parentElement.removeChild(container)
}
window.removeEventListener('click', hide)
}
window.addEventListener('click', hide)
document.querySelector('body').appendChild(container) document.querySelector('body').appendChild(container)
setTimeout(() => {
window.addEventListener('click', hide)
}, 500)
} }
...@@ -17,7 +17,10 @@ module.exports = { ...@@ -17,7 +17,10 @@ module.exports = {
createContract, createContract,
modalFooterOKClick, modalFooterOKClick,
setEditorValue, setEditorValue,
getEditorValue getEditorValue,
testEditorValue,
renameFile,
removeFile
} }
function getCompiledContracts (browser, compiled, callback) { function getCompiledContracts (browser, compiled, callback) {
...@@ -146,12 +149,13 @@ function testFunction (fnFullName, txHash, log, expectedInput, expectedReturn, e ...@@ -146,12 +149,13 @@ function testFunction (fnFullName, txHash, log, expectedInput, expectedReturn, e
return this return this
} }
function setEditorValue (value) { function setEditorValue (value, callback) {
this.perform((client, done) => { this.perform((client, done) => {
this.execute(function (value) { this.execute(function (value) {
document.getElementById('input').editor.session.setValue(value) document.getElementById('input').editor.session.setValue(value)
}, [value], function (result) { }, [value], function (result) {
done() done()
if (callback) callback()
}) })
}) })
return this return this
...@@ -184,6 +188,13 @@ function getEditorValue (callback) { ...@@ -184,6 +188,13 @@ function getEditorValue (callback) {
return this return this
} }
function testEditorValue (testvalue, callback) {
this.getEditorValue((value) => {
this.assert.equal(testvalue, value)
callback()
})
}
function modalFooterOKClick () { function modalFooterOKClick () {
this.perform((client, done) => { this.perform((client, done) => {
this.execute(function () { this.execute(function () {
...@@ -215,6 +226,73 @@ function addFile (browser, name, content, done) { ...@@ -215,6 +226,73 @@ function addFile (browser, name, content, done) {
}) })
} }
function renameFile (browser, path, newFileName, renamedPath, done) {
browser.execute(function (path) {
function contextMenuClick (element) {
var evt = element.ownerDocument.createEvent('MouseEvents')
var RIGHT_CLICK_BUTTON_CODE = 2 // the same for FF and IE
evt.initMouseEvent('contextmenu', true, true,
element.ownerDocument.defaultView, 1, 0, 0, 0, 0, false,
false, false, false, RIGHT_CLICK_BUTTON_CODE, null)
if (document.createEventObject) {
// dispatch for IE
return element.fireEvent('onclick', evt)
} else {
// dispatch for firefox + others
return !element.dispatchEvent(evt)
}
}
contextMenuClick(document.querySelector('[data-path="' + path + '"]'))
}, [path], function (result) {
browser
.click('#menuitemrename')
.perform((client, doneSetValue) => {
browser.execute(function (path, addvalue) {
document.querySelector('[data-path="' + path + '"]').innerHTML = addvalue
}, [path, newFileName], () => {
doneSetValue()
})
})
.click('body') // blur
.pause(500)
.click('#modal-footer-ok')
.waitForElementNotPresent('[data-path="' + path + '"]')
.waitForElementPresent('[data-path="' + renamedPath + '"]')
.perform(() => {
done()
})
})
}
function removeFile (browser, path, done) {
browser.execute(function (path, value) {
function contextMenuClick (element) {
var evt = element.ownerDocument.createEvent('MouseEvents')
var RIGHT_CLICK_BUTTON_CODE = 2 // the same for FF and IE
evt.initMouseEvent('contextmenu', true, true,
element.ownerDocument.defaultView, 1, 0, 0, 0, 0, false,
false, false, false, RIGHT_CLICK_BUTTON_CODE, null)
if (document.createEventObject) {
// dispatch for IE
return element.fireEvent('onclick', evt)
} else {
// dispatch for firefox + others
return !element.dispatchEvent(evt)
}
}
contextMenuClick(document.querySelector('[data-path="' + path + '"]'))
}, [path], function (result) {
browser
.click('#menuitemdelete')
.pause(500)
.click('#modal-footer-ok')
.waitForElementNotPresent('[data-path="' + path + '"]')
.perform(() => {
done()
})
})
}
function useFilter (browser, filter, test, done) { function useFilter (browser, filter, test, done) {
if (browser.options.desiredCapabilities.browserName === 'chrome') { // nightwatch deos not handle well that part.... works locally if (browser.options.desiredCapabilities.browserName === 'chrome') { // nightwatch deos not handle well that part.... works locally
done() done()
......
...@@ -23,6 +23,12 @@ module.exports = { ...@@ -23,6 +23,12 @@ module.exports = {
} }
function runTests (browser, testData) { function runTests (browser, testData) {
browser.testFunction = contractHelper.testFunction
browser.clickFunction = contractHelper.clickFunction
browser.setEditorValue = contractHelper.setEditorValue
browser.modalFooterOKClick = contractHelper.modalFooterOKClick
browser.getEditorValue = contractHelper.getEditorValue
browser.testEditorValue = contractHelper.testEditorValue
var browserName = browser.options.desiredCapabilities.browserName var browserName = browser.options.desiredCapabilities.browserName
if (browserName === 'safari' || browserName === 'internet explorer') { if (browserName === 'safari' || browserName === 'internet explorer') {
console.log('do not run remixd test for ' + browserName + ': sauce labs doesn\'t seems to handle websocket') console.log('do not run remixd test for ' + browserName + ': sauce labs doesn\'t seems to handle websocket')
...@@ -38,14 +44,66 @@ function runTests (browser, testData) { ...@@ -38,14 +44,66 @@ function runTests (browser, testData) {
.click('[data-path="localhost"]') .click('[data-path="localhost"]')
.waitForElementVisible('[data-path="localhost/folder1"]') .waitForElementVisible('[data-path="localhost/folder1"]')
.click('[data-path="localhost/folder1"]') .click('[data-path="localhost/folder1"]')
.waitForElementVisible('[data-path="localhost/contract1.sol"]')
.assert.containsText('[data-path="localhost/contract1.sol"]', 'contract1.sol') .assert.containsText('[data-path="localhost/contract1.sol"]', 'contract1.sol')
.assert.containsText('[data-path="localhost/contract2.sol"]', 'contract2.sol') .assert.containsText('[data-path="localhost/contract2.sol"]', 'contract2.sol')
.assert.containsText('[data-path="localhost/folder1/contract1.sol"]', 'contract1.sol') .assert.containsText('[data-path="localhost/folder1/contract1.sol"]', 'contract1.sol')
.assert.containsText('[data-path="localhost/folder1/contract2.sol"]', 'contract2.sol') .assert.containsText('[data-path="localhost/folder1/contract2.sol"]', 'contract2.sol') // load and test sub folder
.click('[data-path="localhost/folder1/contract2.sol"]') .click('[data-path="localhost/folder1/contract2.sol"]')
.waitForElementPresent('#compileTabView select option', 50000, true, function () { .click('[data-path="localhost/folder1/contract1.sol"]') // open localhost/folder1/contract1.sol
contractHelper.verifyContract(browser, ['test2'], function () { .pause(1000)
browser.click('.websocketconn').end() .perform(function (done) { // check the content and replace by another
browser.testEditorValue('contract test1 { function get () returns (uint) { return 10; }}', () => {
console.log('testEditorValue')
done()
}) })
}) })
.perform(function (done) {
browser.setEditorValue('contract test1Changed { function get () returns (uint) { return 10; }}', () => {
console.log('setEditorValue')
done()
})
})
.perform(function (done) {
browser.testEditorValue('contract test1Changed { function get () returns (uint) { return 10; }}', () => {
console.log('testEditorValue')
done()
})
})
.perform(function (done) {
browser.setEditorValue('contract test1 { function get () returns (uint) { return 10; }}', () => {
console.log('setEditorValue')
done()
})
})
.click('[data-path="localhost/folder1/contract_' + browserName + '.sol"]') // rename a file and check
.pause(1000)
.perform(function (done) {
contractHelper.renameFile(browser, 'localhost/folder1/contract_' + browserName + '.sol', 'renamed_contract_' + browserName + '.sol',
'localhost/folder1/renamed_contract_' + browserName + '.sol', () => {
console.log('tested file renaming')
done()
})
})
.pause(1000)
.perform(function (done) { // remove a file and check
contractHelper.removeFile(browser, 'localhost/folder1/contract_' + browserName + '_toremove.sol', () => {
console.log('tested file removing')
done()
})
})
.perform(function () {
browser.click('[data-path="localhost"]') // collapse and expand
.waitForElementNotVisible('[data-path="localhost/folder1"]')
.click('[data-path="localhost"]')
.waitForElementVisible('[data-path="localhost/folder1"]')
.click('[data-path="localhost/folder1"]')
.waitForElementVisible('[data-path="localhost/folder1/contract1.sol"]')
.waitForElementVisible('[data-path="localhost/folder1/renamed_contract_' + browserName + '.sol"]') // check if renamed file is preset
.waitForElementNotPresent('[data-path="localhost/folder1/contract_' + browserName + '.sol"]') // check if renamed (old) file is not present
.waitForElementNotPresent('[data-path="localhost/folder1/contract_' + browserName + '_toremove.sol"]') // check if removed (old) file is not present
.click('[data-path="localhost/folder1/renamed_contract_' + browserName + '.sol"]')
.click('.websocketconn')
.end()
})
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment