Merge pull request #4747 from ethereum/vyper-patch-007

Vyper-patch-007
pull/4734/merge
Joseph Izang 7 months ago committed by GitHub
commit e59f1bdaa7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 74
      apps/remix-ide-e2e/src/commands/addFileSnekmate.ts
  2. 16
      apps/remix-ide-e2e/src/commands/openFile.ts
  3. 60
      apps/remix-ide-e2e/src/tests/pinned_contracts.test.ts
  4. 54
      apps/remix-ide-e2e/src/tests/vyper_api.test.ts
  5. 1
      apps/remix-ide-e2e/src/types/index.d.ts
  6. 4
      apps/vyper/src/app/app.tsx
  7. 8
      apps/vyper/src/app/utils/compiler.tsx
  8. 8
      apps/vyper/src/app/utils/remix-client.tsx

@ -0,0 +1,74 @@
import EventEmitter from 'events'
import { NightwatchBrowser, NightwatchContractContent } from 'nightwatch'
class AddFileSnekmate extends EventEmitter {
command(this: NightwatchBrowser, name: string, content: NightwatchContractContent): NightwatchBrowser {
this.api.perform((done) => {
addFileSnekmate(this.api, name, content, () => {
done()
this.emit('complete')
})
})
return this
}
}
function addFileSnekmate(browser: NightwatchBrowser, name: string, content: NightwatchContractContent, done: VoidFunction) {
browser
.isVisible({
selector: "//*[@data-id='sidePanelSwapitTitle' and contains(.,'File explorer')]",
locateStrategy: 'xpath',
suppressNotFoundErrors: true,
timeout: 1000
}, (okVisible) => {
if (!okVisible.value) {
browser.clickLaunchIcon('filePanel')
}
})
.scrollInto('li[data-id="treeViewLitreeViewItemREADME.txt"]')
.waitForElementVisible('li[data-id="treeViewLitreeViewItemLICENSE"]')
.click('li[data-id="treeViewLitreeViewItemLICENSE"]').pause(1000) // focus on root directory
.isVisible({
selector: `//*[@data-id="treeViewLitreeViewItem${name}"]`,
locateStrategy: 'xpath',
abortOnFailure: false,
suppressNotFoundErrors: true,
timeout: 2000
}, (okVisible) => {
// @ts-ignore
// status === -1 means the element is not visible, 0 means it is visible.
if (okVisible.status === 0) {
browser.openFile(name)
.perform(function () {
done()
})
} else {
browser.click('[data-id="fileExplorerNewFilecreateNewFile"]')
.waitForElementContainsText('*[data-id$="fileExplorerTreeItemInput"]', '', 60000)
.sendKeys('*[data-id$="fileExplorerTreeItemInput"]', name)
.sendKeys('*[data-id$="fileExplorerTreeItemInput"]', browser.Keys.ENTER)
// isvisible is protocol action called isDisplayed https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/WebElement.html#isDisplayed--
.isVisible({
selector: `li[data-id="treeViewLitreeViewItem${name}"]`,
abortOnFailure: false,
suppressNotFoundErrors: true,
timeout: 60000
})
.waitForElementVisible({
selector: `//*[@data-id='tab-active' and contains(@data-path, "${name}")]`,
locateStrategy: 'xpath'
})
.setEditorValue(content.content)
.getEditorValue((result) => {
if(result != content.content) {
browser.setEditorValue(content.content)
}
})
.perform(function () {
done()
})
}
})
}
module.exports = AddFileSnekmate

@ -31,15 +31,15 @@ function openFile (browser: NightwatchBrowser, name: string, done: VoidFunction)
done() done()
}) })
} }
}) })
})
.waitForElementVisible('li[data-id="treeViewLitreeViewItem' + name + '"', 60000)
.click('li[data-id="treeViewLitreeViewItem' + name + '"')
.pause(2000)
.perform(() => {
done()
}) })
.waitForElementVisible('li[data-id="treeViewLitreeViewItem' + name + '"', 60000)
.click('li[data-id="treeViewLitreeViewItem' + name + '"')
.pause(2000)
.perform(() => {
done()
})
} }
module.exports = OpenFile module.exports = OpenFile

@ -29,7 +29,7 @@ module.exports = {
.assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.') .assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.')
.assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]') .assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]')
.assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') .assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]')
}, },
'Test pinned contract loading on environment change #group1': function (browser: NightwatchBrowser) { 'Test pinned contract loading on environment change #group1': function (browser: NightwatchBrowser) {
browser browser
.switchEnvironment('vm-shanghai') .switchEnvironment('vm-shanghai')
@ -41,7 +41,7 @@ module.exports = {
.assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-cancun)') .assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-cancun)')
.assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]') .assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]')
.assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') .assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]')
}, },
'Interact with pinned contract #group1': function (browser: NightwatchBrowser) { 'Interact with pinned contract #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="universalDappUiTitleExpander0"]') .click('*[data-id="universalDappUiTitleExpander0"]')
@ -51,23 +51,23 @@ module.exports = {
.assert.textContains('*[data-id="instanceContractFilePath"]', 'default_workspace/contracts/1_Storage.sol') .assert.textContains('*[data-id="instanceContractFilePath"]', 'default_workspace/contracts/1_Storage.sol')
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.testFunction('last', .testFunction('last',
{ {
to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138',
'decoded output': { "0": "uint256: 0" } 'decoded output': { "0": "uint256: 0" }
}) })
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '35' }) .clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '35' })
.testFunction('last', .testFunction('last',
{ {
status: '0x1 Transaction mined and execution succeed', status: '0x1 Transaction mined and execution succeed',
'decoded input': { "uint256 num": "35" } 'decoded input': { "uint256 num": "35" }
}) })
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.testFunction('last', .testFunction('last',
{ {
to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138',
'decoded output': { "0": "uint256: 35" } 'decoded output': { "0": "uint256: 35" }
}) })
}, },
'Unpin & interact #group1': function (browser: NightwatchBrowser) { 'Unpin & interact #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="universalDappUiUdappUnpin"]') .click('*[data-id="universalDappUiUdappUnpin"]')
@ -78,23 +78,23 @@ module.exports = {
.assert.not.elementPresent('*[data-id="instanceContractFilePath"]') .assert.not.elementPresent('*[data-id="instanceContractFilePath"]')
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.testFunction('last', .testFunction('last',
{ {
to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138',
'decoded output': { "0": "uint256: 35" } 'decoded output': { "0": "uint256: 35" }
}) })
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '55' }) .clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '55' })
.testFunction('last', .testFunction('last',
{ {
status: '0x1 Transaction mined and execution succeed', status: '0x1 Transaction mined and execution succeed',
'decoded input': { "uint256 num": "55" } 'decoded input': { "uint256 num": "55" }
}) })
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.testFunction('last', .testFunction('last',
{ {
to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138',
'decoded output': { "0": "uint256: 55" } 'decoded output': { "0": "uint256: 55" }
}) })
}, },
'Re-pin & delete immediately #group1': function (browser: NightwatchBrowser) { 'Re-pin & delete immediately #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="universalDappUiUdappPin"]') .click('*[data-id="universalDappUiUdappPin"]')
@ -102,5 +102,5 @@ module.exports = {
.click('*[data-id="universalDappUiUdappDelete"]') .click('*[data-id="universalDappUiUdappDelete"]')
.assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network') .assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network')
.assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.') .assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.')
}, },
} }

@ -27,28 +27,30 @@ module.exports = {
.frameParent() .frameParent()
.clickLaunchIcon('filePanel') .clickLaunchIcon('filePanel')
.waitForElementVisible({ .waitForElementVisible({
selector: "//*[@data-id='workspacesSelect' and contains(.,'vyper-lang')]", selector: "//*[@data-id='workspacesSelect' and contains(.,'snekmate')]",
locateStrategy: 'xpath', locateStrategy: 'xpath',
timeout: 60000 timeout: 60000
}) })
.currentWorkspaceIs('vyper-lang') .currentWorkspaceIs('snekmate')
.waitForElementVisible({ .waitForElementVisible({
selector: "//*[@data-id='treeViewLitreeViewItemexamples' and contains(.,'examples')]", selector: "//*[@data-id='treeViewLitreeViewItemsrc' and contains(.,'src')]",
locateStrategy: 'xpath', locateStrategy: 'xpath',
timeout: 60000 timeout: 60000
}) })
.openFile('examples') .openFile('src')
.openFile('examples/auctions') .openFile('src/snekmate')
.openFile('examples/auctions/blind_auction.vy') .openFile('src/snekmate/tokens')
.openFile('src/snekmate/tokens/ERC721.vy')
}, },
// 'Add vyper file to run tests #group1': function (browser: NightwatchBrowser) { // 'Add vyper file to run tests #group1': function (browser: NightwatchBrowser) {
// browser.addFile('TestBallot.sol', sources[0]['TestBallot.sol']) // browser.addFile('TestBallot.sol', sources[0]['TestBallot.sol'])
// }, // },
'@sources': () => sources,
'Context menu click to compile blind_auction should succeed #group1': function (browser: NightwatchBrowser) { 'Context menu click to compile blind_auction should succeed #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="treeViewLitreeViewItemexamples/auctions/blind_auction.vy"]') .addFileSnekmate('blind_auction.vy', sources[0]['blindAuction'])
.rightClick('*[data-id="treeViewLitreeViewItemexamples/auctions/blind_auction.vy"]') .click('*[data-id="treeViewLitreeViewItemblind_auction.vy"]')
.rightClick('*[data-id="treeViewLitreeViewItemblind_auction.vy"]')
.waitForElementPresent('[data-id="contextMenuItemvyper"]') .waitForElementPresent('[data-id="contextMenuItemvyper"]')
.click('[data-id="contextMenuItemvyper"]') .click('[data-id="contextMenuItemvyper"]')
.clickLaunchIcon('vyper') .clickLaunchIcon('vyper')
@ -145,6 +147,33 @@ module.exports = {
browser.verifyCallReturnValue(contractAddress, ['0:uint256: 0']) browser.verifyCallReturnValue(contractAddress, ['0:uint256: 0'])
.perform(() => done()) .perform(() => done())
}) })
},
'Compile Ownable contract from snekmate #group1': function (browser: NightwatchBrowser) {
let contractAddress
browser
.frameParent()
.clickLaunchIcon('filePanel')
.switchWorkspace('snekmate')
.openFile('src')
.openFile('src/snekmate')
.openFile('src/snekmate/auth')
.openFile('src/snekmate/auth/Ownable.vy')
.rightClick('*[data-id="treeViewLitreeViewItemsrc/snekmate/auth/Ownable.vy"]')
.waitForElementVisible('*[data-id="contextMenuItemvyper"]')
.click('*[data-id="contextMenuItemvyper"]')
.clickLaunchIcon('vyper')
// @ts-ignore
.frame(0)
.click('[data-id="compile"]')
.waitForElementVisible({
selector:'[data-id="compilation-details"]',
timeout: 60000
})
.click('[data-id="compilation-details"]')
.frameParent()
.waitForElementVisible('[data-id="copy-abi"]')
.end()
} }
} }
@ -180,8 +209,9 @@ def _createPokemon(_name: String[32], _dna: uint256, _HP: uint256):
wins: 0 wins: 0
}) })
self.totalPokemonCount += 1` self.totalPokemonCount += 1`
const sources = [{
const blindAuction = ` 'blindAuction' : { content: `
# Blind Auction. Adapted to Vyper from [Solidity by Example](https://github.com/ethereum/solidity/blob/develop/docs/solidity-by-example.rst#blind-auction-1) # Blind Auction. Adapted to Vyper from [Solidity by Example](https://github.com/ethereum/solidity/blob/develop/docs/solidity-by-example.rst#blind-auction-1)
#pragma version ^0.3.10 #pragma version ^0.3.10
@ -358,4 +388,6 @@ def auctionEnd():
# Transfer funds to beneficiary # Transfer funds to beneficiary
send(self.beneficiary, self.highestBid) send(self.beneficiary, self.highestBid)
` `}
}
]

@ -73,6 +73,7 @@ declare module 'nightwatch' {
waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser
hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser
enableClipBoard: () => NightwatchBrowser enableClipBoard: () => NightwatchBrowser
addFileSnekmate: (name: string, content: NightwatchContractContent) => NightwatchBrowser
} }
export interface NightwatchBrowser { export interface NightwatchBrowser {

@ -117,9 +117,9 @@ const App = () => {
<main id="vyper-plugin"> <main id="vyper-plugin">
<section> <section>
<div className="px-3 pt-3 mb-3 w-100"> <div className="px-3 pt-3 mb-3 w-100">
<CustomTooltip placement="bottom" tooltipText="Clone Vyper examples. Switch to the File Explorer to see the examples."> <CustomTooltip placement="bottom" tooltipText="Clone a repo of Vyper examples. Switch to the File Explorer to see the examples.">
<Button data-id="add-repository" className="w-100 btn btn-secondary" onClick={() => remixClient.cloneVyperRepo()}> <Button data-id="add-repository" className="w-100 btn btn-secondary" onClick={() => remixClient.cloneVyperRepo()}>
Clone Vyper examples repository Clone a repo of Vyper examples
</Button> </Button>
</CustomTooltip> </CustomTooltip>
</div> </div>

@ -144,14 +144,18 @@ const compileReturnType = (output, contract) => {
const fixContractContent = (content: string) => { const fixContractContent = (content: string) => {
if (content.length === 0) return if (content.length === 0) return
const pragmaFound = content.includes('#pragma version ^0.3.10') const pragmaFound = content.includes('#pragma version ^0.3.10')
const wrongpragmaFound = content.includes('# pragma version ^0.3.10')
const evmVerFound = content.includes('#pragma evm-version shanghai') const evmVerFound = content.includes('#pragma evm-version shanghai')
const pragma = '#pragma version ^0.3.10' const pragma = '#pragma version ^0.3.10'
const evmVer = '#pragma evm-version shanghai' const evmVer = '#pragma evm-version shanghai'
if (!evmVerFound) { if (evmVerFound === false) {
content = `${evmVer}\n${content}` content = `${evmVer}\n${content}`
} }
if (!pragmaFound) { if (wrongpragmaFound === true) {
content = content.replace('# pragma version ^0.3.10', '')
}
if (pragmaFound === false ) {
content = `${pragma}\n${content}` content = `${pragma}\n${content}`
} }
return content return content

@ -80,20 +80,20 @@ export class RemixClient extends PluginClient {
async cloneVyperRepo() { async cloneVyperRepo() {
try { try {
// @ts-ignore // @ts-ignore
this.call('notification', 'toast', 'cloning Vyper repository...') this.call('notification', 'toast', 'cloning Snekmate Vyper repository...')
await this.call('manager', 'activatePlugin', 'dGitProvider') await this.call('manager', 'activatePlugin', 'dGitProvider')
await this.call( await this.call(
'dGitProvider', 'dGitProvider',
'clone', 'clone',
{url: 'https://github.com/vyperlang/vyper', token: null, branch: 'v0.3.10'}, {url: 'https://github.com/pcaversaccio/snekmate', token: null, branch: 'v0.0.5'},
// @ts-ignore // @ts-ignore
'vyper-lang' 'snekmate'
) )
this.call( this.call(
// @ts-ignore // @ts-ignore
'notification', 'notification',
'toast', 'toast',
'Vyper repository cloned, the workspace Vyper has been created.' 'Snekmate Vyper repository cloned, the workspace snekmate has been created.'
) )
} catch (e) { } catch (e) {
// @ts-ignore // @ts-ignore

Loading…
Cancel
Save