diff --git a/apps/remix-ide-e2e/src/commands/createContract.ts b/apps/remix-ide-e2e/src/commands/createContract.ts index aa53d9378d0..7fb00da086b 100644 --- a/apps/remix-ide-e2e/src/commands/createContract.ts +++ b/apps/remix-ide-e2e/src/commands/createContract.ts @@ -18,12 +18,13 @@ function createContract (browser: NightwatchBrowser, inputParams: string, callba browser.setValue('.udapp_contractActionsContainerSingle > input', inputParams, function () { browser .pause(1000) // wait to get the button enabled - .waitForElementVisible('.udapp_contractActionsContainerSingle > div') - .click('.udapp_contractActionsContainerSingle > div').pause(500).perform(function () { callback() }) + .waitForElementVisible('.udapp_contractActionsContainerSingle button') + .click('.udapp_contractActionsContainerSingle button').pause(500).perform(function () { callback() }) }) } else { browser - .click('.udapp_contractActionsContainerSingle > div') + .waitForElementVisible('.udapp_contractActionsContainerSingle button') + .click('.udapp_contractActionsContainerSingle button') .pause(500) .perform(function () { callback() }) } diff --git a/apps/remix-ide-e2e/src/commands/expandAllFolders.ts b/apps/remix-ide-e2e/src/commands/expandAllFolders.ts new file mode 100644 index 00000000000..1d295c2a4aa --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/expandAllFolders.ts @@ -0,0 +1,75 @@ +import { NightwatchBrowser } from 'nightwatch' +import EventEmitter from 'events' + +class ExpandAllFolders extends EventEmitter { + command (this: NightwatchBrowser, targetDirectory?: string) { + this.api.perform((done) => { + expandAllFolders(this.api, targetDirectory, () => { + done() + this.emit('complete') + }) + }) + return this + } +} + +function expandAllFolders (browser: NightwatchBrowser, targetDirectory?: string, done?: VoidFunction) { + // Ensure file panel is open + browser.perform((bdone: VoidFunction) => { + browser.isVisible('[data-id="remixIdeSidePanel"]', (result) => { + if (result.value) { + browser.element('css selector', '[data-id="verticalIconsKindfilePanel"] img[data-id="selected"]', (result) => { + if (result.status === 0) { + bdone() + } else browser.clickLaunchIcon('filePanel').perform(() => { + bdone() + }) + }) + } else { + browser.clickLaunchIcon('filePanel').perform(() => { + bdone() + }) + } + }) + }) + .perform(() => { + let attempts = 0 + const maxAttempts = 200 + + const expandNextClosedFolder = () => { + if (attempts >= maxAttempts) { + if (done) done() + return + } + attempts++ + + const closedFolderSelector = targetDirectory + ? `li[data-id*="treeViewLitreeViewItem${targetDirectory}"] .fa-folder:not(.fa-folder-open)` + : 'li[data-id*="treeViewLitreeViewItem"] .fa-folder:not(.fa-folder-open)' + + browser.element('css selector', closedFolderSelector, (result) => { + if (result.status === 0 && result.value) { + // Found a closed folder icon, now find its parent li element and click it + browser.elementIdElement((result.value as any)['element-6066-11e4-a52e-4f735466cecf'], 'xpath', './..', (parentResult) => { + if (parentResult.status === 0) { + browser.elementIdClick((parentResult.value as any)['element-6066-11e4-a52e-4f735466cecf']) + .pause(100) // Wait for folder to expand and DOM to update + .perform(() => expandNextClosedFolder()) // Look for next closed folder + } else { + // Failed to find parent, try alternative approach + browser.click(closedFolderSelector) + .pause(100) + .perform(() => expandNextClosedFolder()) // recursive call + } + }) + } else { + if (done) done() + } + }) + } + + expandNextClosedFolder() + }) +} + +module.exports = ExpandAllFolders \ No newline at end of file diff --git a/apps/remix-ide-e2e/src/tests/ai_panel.test.ts b/apps/remix-ide-e2e/src/tests/ai_panel.test.ts index ac8c8d3f088..b5f22a22ab1 100644 --- a/apps/remix-ide-e2e/src/tests/ai_panel.test.ts +++ b/apps/remix-ide-e2e/src/tests/ai_panel.test.ts @@ -8,7 +8,7 @@ const sources = [ { 'Untitled.sol': { content: examples.ballot.content } } ] -module.exports = { +const tests = { '@disabled': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { init(browser, done) @@ -271,3 +271,18 @@ module.exports = { .waitForElementNotVisible('*[data-id="remix-ai-assistant"]', 5000) }, } + +const branch = process.env.CIRCLE_BRANCH +const runTestsConditions = branch && (branch === 'master' || branch === 'remix_live' || branch.includes('remix_beta') || branch.includes('metamask')) + +const checkBrowserIsChrome = function (browser: NightwatchBrowser) { + return browser.browserName.indexOf('chrome') > -1 +} + +if (!checkBrowserIsChrome(browser)) { + module.exports = {} +} else { + module.exports = { + ...(branch ? (runTestsConditions ? tests : {}) : tests) + }; +} diff --git a/apps/remix-ide-e2e/src/tests/expandAllFolders.test.ts b/apps/remix-ide-e2e/src/tests/expandAllFolders.test.ts new file mode 100644 index 00000000000..01e46011352 --- /dev/null +++ b/apps/remix-ide-e2e/src/tests/expandAllFolders.test.ts @@ -0,0 +1,49 @@ +'use strict' +import { NightwatchBrowser } from 'nightwatch' +import init from '../helpers/init' + +module.exports = { + '@disabled': true, + before: function (browser: NightwatchBrowser, done: VoidFunction) { + init(browser, done) + }, + + 'Should expand all folders in the file explorer': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]') + .expandAllFolders() + .pause(2000) + .isVisible({ + selector: '*[data-id="treeViewLitreeViewItemcontracts"] .fa-folder-open', + timeout: 5000, + suppressNotFoundErrors: true + }) + .isVisible({ + selector: '*[data-id="treeViewLitreeViewItemscripts"] .fa-folder-open', + timeout: 5000, + suppressNotFoundErrors: true + }) + }, + + 'Should expand all folders within a specific directory': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .addFile('package.json', sources[0]['package.json']) + .addFile('Untitled10.sol', sources[0]['Untitled10.sol']) + .waitForElementVisible('*[data-id="treeViewLitreeViewItem.deps"]') + .expandAllFolders() + .pause(5000) + } +} +const sources = [ + { + 'Untitled10.sol': { content: 'pragma solidity ^0.8.0; import "@module_remapping/token/ERC20/ERC20.sol"; contract test15 {}' }, + 'package.json': { content: `{ + "dependencies": { + "@module_remapping": "npm:@openzeppelin/contracts@^4.9.0" + } +}` } + } +] diff --git a/apps/remix-ide-e2e/src/tests/solidityImport.test.ts b/apps/remix-ide-e2e/src/tests/solidityImport.test.ts index d73e6a443f1..34e6e841a82 100644 --- a/apps/remix-ide-e2e/src/tests/solidityImport.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityImport.test.ts @@ -100,6 +100,7 @@ module.exports = { .click('li[data-id="treeViewLitreeViewItemREADME.txt"') .addFile('Untitled9.sol', sources[8]['Untitled9.sol']) // avoid invalid source issues + .expandAllFolders() .isVisible({ selector: '*[data-id="treeViewLitreeViewItem.deps/npm/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"]', timeout: 120000, @@ -108,6 +109,7 @@ module.exports = { .clickLaunchIcon('solidity') .click('[data-id="compilerContainerCompileBtn"]') .clickLaunchIcon('filePanel') + .expandAllFolders() .isVisible({ selector: '*[data-id="treeViewLitreeViewItem.deps/npm/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"]', timeout: 120000, @@ -126,7 +128,8 @@ module.exports = { .clickLaunchIcon('filePanel') .click('li[data-id="treeViewLitreeViewItemREADME.txt"') .addFile('package.json', sources[9]['package.json']) - .addFile('Untitled10.sol', sources[9]['Untitled10.sol']) + .addFile('Untitled10.sol', sources[9]['Untitled10.sol']) + .expandAllFolders() // avoid invalid source issues .isVisible({ selector: '*[data-id="treeViewLitreeViewItem.deps/npm/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"]', @@ -136,6 +139,7 @@ module.exports = { .clickLaunchIcon('solidity') .click('[data-id="compilerContainerCompileBtn"]') .clickLaunchIcon('filePanel') + .expandAllFolders() .isVisible({ selector: '*[data-id="treeViewLitreeViewItem.deps/npm/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"]', timeout: 120000, diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts index cd6619ee2b2..cde0347d2ab 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts @@ -192,6 +192,7 @@ module.exports = { .modalFooterOKClick('TemplatesSelection') .pause(3000) .currentWorkspaceIs('workspace_new') + .expandAllFolders() .waitForElementVisible('li[data-id="treeViewLitreeViewItem.deps/remix-tests/remix_tests.sol"]') .waitForElementVisible('li[data-id="treeViewLitreeViewItem.deps/remix-tests/remix_accounts.sol"]') .openFile('.deps/remix-tests/remix_tests.sol') diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index 817f36fcd7a..c67bcbd8b1b 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -84,6 +84,7 @@ declare module 'nightwatch' { addFileSnekmate: (name: string, content: NightwatchContractContent) => NightwatchBrowser selectFiles: (selelectedElements: any[]) => NightwatchBrowser waitForCompilerLoaded: () => NightwatchBrowser + expandAllFolders: (targetDirectory?: string) => NightwatchBrowser } export interface NightwatchBrowser { diff --git a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts index 969cd10bf2c..e3c9613cfc4 100644 --- a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts @@ -337,8 +337,8 @@ export const browserReducer = (state = browserInitialState, action: Actions) => const check = checkCurrentParentPathInView(payload, state.mode === 'browser' ? state.browser.expandPath : state.localhost.expandPath) const fd = fileAdded(state, payload) - const browserExpandPath = state.mode === 'browser' && !isElectron() && check.inView ? [...new Set([...state.browser.expandPath, payload])] : state.browser.expandPath - const localhostExpandPath = state.mode === 'localhost' && check.inView ? [...new Set([...state.localhost.expandPath, payload])] : state.localhost.expandPath + const browserExpandPath = state.mode === 'browser' && !isElectron() && check.inView && !payload.includes('.deps') ? [...new Set([...state.browser.expandPath, payload])] : state.browser.expandPath + const localhostExpandPath = state.mode === 'localhost' && check.inView && !payload.includes('.deps') ? [...new Set([...state.localhost.expandPath, payload])] : state.localhost.expandPath const flatTree = flattenTree(fd, state.mode === 'browser'? browserExpandPath : localhostExpandPath) return { ...state, @@ -373,8 +373,8 @@ export const browserReducer = (state = browserInitialState, action: Actions) => const inView = check.inView || check.rootViewToAdd payload.folderPath = check.inView ? payload.folderPath : check.rootViewToAdd ? check.rootFolder : '' - const browserExpandPath = state.mode === 'browser' && !isElectron() && inView ? [...new Set([...state.browser.expandPath, payload.folderPath])] : state.browser.expandPath - const localhostExpandPath = state.mode === 'localhost' && inView ? [...new Set([...state.localhost.expandPath, payload.folderPath])] : state.localhost.expandPath + const browserExpandPath = state.mode === 'browser' && !isElectron() && inView && !payload.folderPath.includes('.deps') ? [...new Set([...state.browser.expandPath, payload.folderPath])] : state.browser.expandPath + const localhostExpandPath = state.mode === 'localhost' && inView && !payload.folderPath.includes('.deps') ? [...new Set([...state.localhost.expandPath, payload.folderPath])] : state.localhost.expandPath const flatTree = flattenTree(fd, state.mode === 'browser'? browserExpandPath : localhostExpandPath) return { ...state, diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index fd61244832b..ef5811a3d2f 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -659,7 +659,7 @@ export function Workspace() { const uploadFile = (target) => { const parentFolder = getFocusedFolder() - const expandPath = [...new Set([...global.fs.browser.expandPath, parentFolder])] + const expandPath = [...new Set([...global.fs.browser.expandPath, parentFolder].filter(path => !path.includes('.deps')))] global.dispatchHandleExpandPath(expandPath) global.dispatchUploadFile(target, parentFolder) @@ -667,7 +667,7 @@ export function Workspace() { const uploadFolder = (target) => { const parentFolder = getFocusedFolder() - const expandPath = [...new Set([...global.fs.browser.expandPath, parentFolder])] + const expandPath = [...new Set([...global.fs.browser.expandPath, parentFolder].filter(path => !path.includes('.deps')))] global.dispatchHandleExpandPath(expandPath) global.dispatchUploadFolder(target, parentFolder) @@ -810,7 +810,7 @@ export function Workspace() { const handleNewFileInput = async (parentFolder?: string) => { if (!parentFolder) parentFolder = getFocusedFolder() - const expandPath = [...new Set([...global.fs.browser.expandPath, parentFolder])] + const expandPath = [...new Set([...global.fs.browser.expandPath, parentFolder].filter(path => !path.includes('.deps')))] await global.dispatchAddInputField(parentFolder, 'file') global.dispatchHandleExpandPath(expandPath) @@ -820,7 +820,7 @@ export function Workspace() { const handleNewFolderInput = async (parentFolder?: string) => { if (!parentFolder) parentFolder = getFocusedFolder() else if (parentFolder.indexOf('.sol') !== -1 || parentFolder.indexOf('.js') !== -1) parentFolder = extractParentFromKey(parentFolder) - const expandPath = [...new Set([...global.fs.browser.expandPath, parentFolder])] + const expandPath = [...new Set([...global.fs.browser.expandPath, parentFolder].filter(path => !path.includes('.deps')))] await global.dispatchAddInputField(parentFolder, 'folder') global.dispatchHandleExpandPath(expandPath)