Merge branch 'master' of https://github.com/ethereum/remix-project into github_fe

largegittest2
bunsenstraat 3 months ago
commit 093ccc8e50
  1. 15
      .circleci/config.yml
  2. 19
      apps/remix-ide-e2e/src/commands/pinGrid.ts
  3. 27
      apps/remix-ide-e2e/src/commands/renamePath.ts
  4. 34
      apps/remix-ide-e2e/src/commands/switchEnvironment.ts
  5. 16
      apps/remix-ide-e2e/src/tests/dgit_local.test.ts
  6. 20
      apps/remix-ide-e2e/src/tests/grid.test.ts
  7. 8
      apps/remix-ide-e2e/src/tests/plugin_api.ts
  8. 80
      apps/remix-ide-e2e/src/tests/remixd.test.ts
  9. 5
      apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts
  10. 6
      apps/remix-ide-e2e/yarn.lock
  11. 18
      apps/remix-ide/src/blockchain/blockchain.tsx
  12. 2
      libs/remix-ui/run-tab/src/lib/components/environment.tsx
  13. 2
      libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx

@ -16,6 +16,7 @@ jobs:
xlarge
working_directory: ~/remix-project
steps:
- run: sudo apt update && sudo apt install zstd
- checkout
- restore_cache:
keys:
@ -44,8 +45,8 @@ jobs:
key: soljson-v7-{{ checksum "soljson-versions.txt" }}
paths:
- dist/apps/remix-ide/assets/js/soljson
- run: mkdir persist && zip -0 -r persist/dist.zip dist
- run: mkdir persist && tar -cf - dist | zstd -1 -o persist/dist.tar.zst
- persist_to_workspace:
root: .
paths:
@ -360,11 +361,13 @@ jobs:
- checkout
- attach_workspace:
at: .
- run: unzip ./persist/dist.zip
- run: sudo apt update && sudo apt install python3-pip -y zstd
- run: zstd -d persist/dist.tar.zst -o persist/dist.tar
- run: tar -xf persist/dist.tar
- run: yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules || yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules
- run: mkdir node_modules/hardhat && wget https://unpkg.com/hardhat/console.sol -O node_modules/hardhat/console.sol
- run: ls -la ./dist/apps/remix-ide/assets/js
- run: sudo apt update && sudo apt install python3-pip -y
- when:
condition:
equal: [ "chrome", << parameters.browser >> ]
@ -416,7 +419,9 @@ jobs:
- checkout
- attach_workspace:
at: .
- run: unzip ./persist/dist.zip
- run: sudo apt update && sudo apt install zstd
- run: zstd -d persist/dist.tar.zst -o persist/dist.tar
- run: tar -xf persist/dist.tar
- run: unzip ./persist/plugin-<< parameters.plugin >>.zip
- run: yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules || yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules
- browser-tools/install-browser-tools:

@ -3,11 +3,20 @@ import EventEmitter from 'events'
class pinGrid extends EventEmitter {
command (this: NightwatchBrowser, provider: string, status: boolean): NightwatchBrowser {
this.api.useCss().waitForElementVisible('[data-id="settingsSelectEnvOptions"]')
.click('[data-id="settingsSelectEnvOptions"] button')
.waitForElementVisible(`[data-id="dropdown-item-another-chain"]`)
.click(`[data-id="dropdown-item-another-chain"]`)
.waitForElementVisible(`[data-id="${provider}-${status ? 'unpinned' : 'pinned'}"]`)
this.api.useCss()
.perform((done) => {
// check if the providers plugin is loaded.
this.api.isVisible({ selector: '[data-id="remixUIGSDeploy using a Browser Extension."]', suppressNotFoundErrors: true}, (result) => {
if (!result.value) {
this.api.waitForElementVisible('[data-id="settingsSelectEnvOptions"]')
.click('[data-id="settingsSelectEnvOptions"] button')
.waitForElementVisible(`[data-id="dropdown-item-another-chain"]`)
.click(`[data-id="dropdown-item-another-chain"]`)
.perform(() => done())
} else done()
})
})
.waitForElementVisible(`[data-id="${provider}-${status ? 'unpinned' : 'pinned'}"]`, 60000)
.click(`[data-id="${provider}-${status ? 'unpinned' : 'pinned'}"]`)
.perform((done) => {
done()

@ -2,7 +2,7 @@ import EventEmitter from 'events'
import { NightwatchBrowser } from 'nightwatch'
class RenamePath extends EventEmitter {
command (this: NightwatchBrowser, path: string, newFileName: string, renamedPath: string) {
command(this: NightwatchBrowser, path: string, newFileName: string, renamedPath: string) {
this.api.perform((done) => {
renamePath(this.api, path, newFileName, renamedPath, () => {
done()
@ -13,9 +13,9 @@ class RenamePath extends EventEmitter {
}
}
function renamePath (browser: NightwatchBrowser, path: string, newFileName: string, renamedPath: string, done: VoidFunction) {
function renamePath(browser: NightwatchBrowser, path: string, newFileName: string, renamedPath: string, done: VoidFunction) {
browser.execute(function (path: string) {
function contextMenuClick (element) {
function contextMenuClick(element) {
const evt = element.ownerDocument.createEvent('MouseEvents')
const RIGHT_CLICK_BUTTON_CODE = 2 // the same for FF and IE
@ -32,15 +32,18 @@ function renamePath (browser: NightwatchBrowser, path: string, newFileName: stri
}
contextMenuClick(document.querySelector('[data-path="' + path + '"]'))
}, [path], function () {
browser
.click('#menuitemrename')
.sendKeys('[data-input-path="' + path + '"]', newFileName)
.sendKeys('[data-input-path="' + path + '"]', browser.Keys.ENTER)
.waitForElementNotPresent('[data-path="' + path + '"]')
.waitForElementPresent('[data-path="' + renamedPath + '"]')
.perform(() => {
done()
})
try {
browser
.click('#menuitemrename')
.sendKeys('[data-input-path="' + path + '"]', newFileName)
.sendKeys('[data-input-path="' + path + '"]', browser.Keys.ENTER)
.waitForElementNotPresent('[data-path="' + path + '"]')
.waitForElementPresent('[data-path="' + renamedPath + '"]');
} catch (error) {
console.error('An error occurred:', error.message);
} finally {
done(); // Ensure done is called even if there's an error
}
})
}

@ -4,13 +4,35 @@ import EventEmitter from 'events'
class switchEnvironment extends EventEmitter {
command (this: NightwatchBrowser, provider: string): NightwatchBrowser {
this.api.useCss().waitForElementVisible('[data-id="settingsSelectEnvOptions"]')
.click('[data-id="settingsSelectEnvOptions"] button')
.waitForElementVisible(`[data-id="dropdown-item-${provider}"]`)
.click(`[data-id="dropdown-item-${provider}"]`)
.perform((done) => {
done()
this.emit('complete')
})
this.api.isPresent({ selector: `[data-id="selected-provider-${provider}"]`, suppressNotFoundErrors: true, timeout: 5000}, (result) => {
if (result.value) {
done()
} else {
browser.perform(() => {
this.api
.click('[data-id="settingsSelectEnvOptions"] button') // open dropdown
.isPresent({ selector: `[data-id="dropdown-item-${provider}"]`, suppressNotFoundErrors: true, timeout: 5000}, (result) => {
console.log(result)
this.api.click('[data-id="settingsSelectEnvOptions"] button') // close dropdown
if (!result.value) {
this.api.pinGrid(provider, true)
.click('[data-id="settingsSelectEnvOptions"] button')
.waitForElementVisible(`[data-id="dropdown-item-${provider}"]`)
.click(`[data-id="dropdown-item-${provider}"]`)
.perform(() => done())
} else {
browser.click('[data-id="settingsSelectEnvOptions"] button')
.waitForElementVisible(`[data-id="dropdown-item-${provider}"]`)
.click(`[data-id="dropdown-item-${provider}"]`)
.perform(() => done())
}
})
})
}
})
}).perform(() => this.emit('complete'))
return this
}
}

@ -244,6 +244,8 @@ module.exports = {
'check if the branch is in the filePanel #group2': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('filePanel')
.waitForElementVisible('*[data-id="workspaceGitBranchesDropdown"]')
.pause(1000)
.click('[data-id="workspaceGitBranchesDropdown"]')
.expect.element('[data-id="workspaceGit-testbranch"]').text.to.contain('✓ ')
},
@ -317,18 +319,30 @@ module.exports = {
},
'switch back to master #group2': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible({
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-branch-master']",
locateStrategy: 'xpath',
})
.click({
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-branch-master']",
locateStrategy: 'xpath',
})
.pause(1000)
.click({
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-branch-master']",
locateStrategy: 'xpath',
abortOnFailure: false,
suppressNotFoundErrors: true
})
.waitForElementVisible({
selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-current-branch-master']",
locateStrategy: 'xpath',
timeout: 60000
})
},
'check if test file is gone #group2': function (browser: NightwatchBrowser) {
browser
.pause()
.pause(2000)
.clickLaunchIcon('filePanel')
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.txt"]')
},

@ -32,5 +32,25 @@ module.exports = {
.click('[data-id="settingsSelectEnvOptions"] button')
.waitForElementNotPresent(`[data-id="dropdown-item-vm-sepolia-fork"]`)
.click('[data-id="settingsSelectEnvOptions"] button') // close the dropdown
},
'remember pin upon reload': function (browser: NightwatchBrowser) {
browser
.pinGrid('vm-paris', true)
.click('[data-id="settingsSelectEnvOptions"] button') // open the dropdown
.waitForElementPresent(`[data-id="dropdown-item-vm-paris"]`)
.refreshPage()
.waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts"]') // wait loaded
.clickLaunchIcon('udapp')
.click('[data-id="settingsSelectEnvOptions"] button') // open the dropdown
.waitForElementPresent(`[data-id="dropdown-item-vm-paris"]`)
.click('[data-id="settingsSelectEnvOptions"] button') // close the dropdown
.pinGrid('vm-paris', false)
.click('[data-id="settingsSelectEnvOptions"] button') // open the dropdown
.waitForElementNotPresent(`[data-id="dropdown-item-vm-paris"]`)
.refreshPage()
.waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts"]') // wait loaded
.clickLaunchIcon('udapp')
.click('[data-id="settingsSelectEnvOptions"] button') // open the dropdown
.waitForElementNotPresent(`[data-id="dropdown-item-vm-paris"]`)
}
}

@ -179,6 +179,14 @@ module.exports = {
},
'Should select another provider #group1': async function (browser: NightwatchBrowser) {
await browser
.frameParent()
.useCss()
.clickLaunchIcon('udapp')
.pinGrid('vm-berlin', true)
.clickLaunchIcon('localPlugin')
.useXpath()
.frame(0)
await clickAndCheckLog(browser, 'udapp:setEnvironmentMode', null, null, { context: 'vm-berlin' })
await browser
.frameParent()

@ -2,10 +2,9 @@
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
import { join } from 'path'
import { ChildProcess, spawn } from 'child_process'
import { ChildProcess, exec, spawn } from 'child_process'
import { homedir } from 'os'
import kill from 'tree-kill'
import treeKill from 'tree-kill'
let remixd: ChildProcess
const assetsTestContract = `import "./contract.sol";
@ -50,15 +49,30 @@ const sources = [
}
]
module.exports = {
'@disabled': true,
before: function (browser, done) {
init(browser, done)
},
after: function (browser) {
browser.perform((done) => {
console.log('remixd', remixd.pid)
kill(remixd.pid)
try {
console.log('remixd pid', remixd.pid);
treeKill(remixd.pid, 'SIGKILL', (err) => {
console.log('remixd killed', err)
})
console.log('Service disconnected successfully.');
} catch (error) {
console.error('Failed to disconnect service:', error);
}
try {
resetGitToHead()
} catch (error) {
console.error('Failed to restore git changes:', error);
}
done()
})
},
@ -66,12 +80,14 @@ module.exports = {
'@sources': function () {
return sources
},
'run Remixd tests #group1': function (browser) {
'run Remixd tests #group1': function (browser: NightwatchBrowser) {
browser.perform(async (done) => {
try {
remixd = await spawnRemixd(join(process.cwd(), '/apps/remix-ide', '/contracts'))
} catch (err) {
console.error(err)
// fail
browser.assert.fail('Failed to start remixd')
}
console.log('working directory', process.cwd())
connectRemixd(browser, done)
@ -86,7 +102,12 @@ module.exports = {
remix try to resolve it against the node_modules and installed_contracts folder.
*/
browser.perform(async (done) => {
try{
remixd = await spawnRemixd(join(process.cwd(), '/apps/remix-ide', '/contracts'))
} catch (err) {
console.error(err)
browser.assert.fail('Failed to start remixd')
}
console.log('working directory', process.cwd())
connectRemixd(browser, done)
})
@ -97,7 +118,12 @@ module.exports = {
},
'Import from node_modules and reference a github import #group3': function (browser) {
browser.perform(async (done) => {
try{
remixd = await spawnRemixd(join(process.cwd(), '/apps/remix-ide', '/contracts'))
} catch (err) {
console.error(err)
browser.assert.fail('Failed to start remixd')
}
console.log('working directory', process.cwd())
connectRemixd(browser, done)
})
@ -117,7 +143,12 @@ module.exports = {
'Should listen on compilation result from hardhat #group4': function (browser: NightwatchBrowser) {
browser.perform(async (done) => {
try{
remixd = await spawnRemixd(join(process.cwd(), '/apps/remix-ide/hardhat-boilerplate'))
} catch (err) {
console.error(err)
browser.assert.fail('Failed to start remixd')
}
console.log('working directory', process.cwd())
connectRemixd(browser, done)
})
@ -188,7 +219,12 @@ module.exports = {
browser.perform(async (done) => {
console.log('working directory', homedir() + '/foundry_tmp/hello_foundry')
try{
remixd = await spawnRemixd(join(homedir(), '/foundry_tmp/hello_foundry'))
} catch (err) {
console.error(err)
browser.assert.fail('Failed to start remixd')
}
connectRemixd(browser, done)
})
.perform(async (done) => {
@ -249,7 +285,12 @@ module.exports = {
'Should disable git when running remixd #group9': function (browser: NightwatchBrowser) {
browser.perform(async (done) => {
try{
remixd = await spawnRemixd(join(process.cwd(), '/apps/remix-ide', '/contracts/hardhat'))
} catch (err) {
console.error(err)
browser.assert.fail('Failed to start remixd')
}
console.log('working directory', process.cwd())
connectRemixd(browser, done)
})
@ -281,6 +322,7 @@ module.exports = {
remixd = await spawnRemixd(join(process.cwd(), '/apps/remix-ide', '/contracts'))
} catch (err) {
console.error(err)
browser.assert.fail('Failed to start remixd')
}
console.log('working directory', process.cwd())
connectRemixd(browser, done)
@ -322,8 +364,11 @@ function runTests(browser: NightwatchBrowser, done: any) {
.setEditorValue('contract test1Changed { function get () returns (uint) { return 10; }}')
.testEditorValue('contract test1Changed { function get () returns (uint) { return 10; }}')
.setEditorValue('contract test1 { function get () returns (uint) { return 10; }}')
.waitForElementVisible('[data-path="folder1"]')
.waitForElementVisible('[data-path="folder1/contract_' + browserName + '.sol"]')
.click('[data-path="folder1/contract_' + browserName + '.sol"]') // rename a file and check
.pause(1000)
.renamePath('folder1/contract_' + browserName + '.sol', 'renamed_contract_' + browserName, 'folder1/renamed_contract_' + browserName + '.sol')
.pause(1000)
.removeFile('folder1/contract_' + browserName + '_toremove.sol', 'localhost')
@ -558,3 +603,26 @@ async function installSlither(): Promise<void> {
console.log(e)
}
}
function resetGitToHead() {
if (process.env.CIRCLECI) {
console.log("Running on CircleCI, resetting Git to HEAD...");
} else {
console.log("Not running on CircleCI, skipping Git reset.");
return
}
const command = 'git reset --hard HEAD && git clean -fd';
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`Error executing command: ${command}\n${error.message}`);
return;
}
if (stderr) {
console.error(`Error output from command: ${command}\n${stderr}`);
return;
}
console.log(`Git reset to HEAD successfully.\n${stdout}`);
});
}

@ -163,16 +163,17 @@ module.exports = {
.click('.remixui_compilerConfigSection')
.setValue('#evmVersionSelector', 'london')
.click('*[data-id="compilerContainerCompileBtn"]')
.pause(5000)
.clickLaunchIcon('udapp')
.switchEnvironment('vm-london')
.clickLaunchIcon('filePanel')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]')
.click('*[data-id="treeViewLitreeViewItemscripts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/deploy_with_web3.ts"]')
.openFile('scripts/deploy_with_web3.ts')
.click('[data-id="play-editor"]')
.waitForElementPresent('[data-id="treeViewDivDraggableItem.states/vm-london/state.json"]')
.click('[data-id="treeViewDivDraggableItem.states/vm-london/state.json"]')
.pause(100000)
.pause(1000)
.getEditorValue((content) => {
browser
.assert.ok(content.includes('"latestBlockNumber": "0x1"'), 'State is saved')

@ -923,9 +923,9 @@ ejs@3.1.8:
jake "^10.8.5"
elliptic@^6.5.4:
version "6.5.4"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
version "6.5.7"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
dependencies:
bn.js "^4.11.9"
brorand "^1.1.0"

@ -80,6 +80,7 @@ export class Blockchain extends Plugin {
providers: {[key: string]: VMProvider | InjectedProvider | NodeProvider}
transactionContextAPI: TransactionContextAPI
registeredPluginEvents: string[]
defaultPinnedProviders: string[]
pinnedProviders: string[]
// NOTE: the config object will need to be refactored out in remix-lib
@ -112,7 +113,8 @@ export class Blockchain extends Plugin {
this.networkcallid = 0
this.networkStatus = { network: { name: ' - ', id: ' - ' } }
this.registeredPluginEvents = []
this.pinnedProviders = ['vm-cancun', 'vm-shanghai', 'vm-mainnet-fork', 'vm-london', 'vm-berlin', 'vm-paris', 'walletconnect', 'injected-MetaMask', 'basic-http-provider', 'ganache-provider', 'hardhat-provider', 'foundry-provider']
this.defaultPinnedProviders = ['vm-cancun', 'vm-mainnet-fork', 'walletconnect', 'injected-MetaMask', 'basic-http-provider', 'hardhat-provider', 'foundry-provider']
this.pinnedProviders = []
this.setupEvents()
this.setupProviders()
}
@ -139,11 +141,25 @@ export class Blockchain extends Plugin {
this.on('environmentExplorer', 'providerPinned', (name, provider) => {
this.emit('shouldAddProvidertoUdapp', name, provider)
this.pinnedProviders.push(name)
this.call('config', 'setAppParameter', 'settings/pinned-providers', JSON.stringify(this.pinnedProviders))
})
this.on('environmentExplorer', 'providerUnpinned', (name, provider) => {
this.emit('shouldRemoveProviderFromUdapp', name, provider)
const index = this.pinnedProviders.indexOf(name)
this.pinnedProviders.splice(index, 1)
this.call('config', 'setAppParameter', 'settings/pinned-providers', JSON.stringify(this.pinnedProviders))
})
this.call('config', 'getAppParameter', 'settings/pinned-providers').then((providers) => {
if (!providers) {
this.call('config', 'setAppParameter', 'settings/pinned-providers', JSON.stringify(this.defaultPinnedProviders))
this.pinnedProviders = this.defaultPinnedProviders
} else {
this.pinnedProviders = JSON.parse(providers)
}
}).catch((error) => { console.log(error) })
}
onDeactivation() {

@ -39,7 +39,7 @@ export function EnvironmentUI(props: EnvironmentProps) {
</a>
</CustomTooltip>
</label>
<div className="udapp_environment">
<div className="udapp_environment" data-id={`selected-provider-${currentProvider && currentProvider.name}`}>
<Dropdown id="selectExEnvOptions" data-id="settingsSelectEnvOptions" className="udapp_selectExEnvOptions">
<Dropdown.Toggle as={CustomToggle} id="dropdown-custom-components" className="btn btn-light btn-block w-100 d-inline-block border border-dark form-control" icon={null}>
{isL2(currentProvider && currentProvider.displayName)}

@ -320,7 +320,7 @@ export const TabsUI = (props: TabsUIProps) => {
>
<TabList className="d-flex flex-row align-items-center">
{props.tabs.map((tab, i) => (
<Tab className="" key={tab.name}>
<Tab className="" key={tab.name} data-id={tab.id}>
{renderTab(tab, i)}
</Tab>
))}

Loading…
Cancel
Save