diff --git a/apps/remixdesktop/nightwatch.conf.js b/apps/remixdesktop/nightwatch.conf.js new file mode 100644 index 0000000000..03f35c4350 --- /dev/null +++ b/apps/remixdesktop/nightwatch.conf.js @@ -0,0 +1,344 @@ +// +// Refer to the online docs for more details: +// https://nightwatchjs.org/guide/configuration/nightwatch-configuration-file.html +// +// _ _ _ _ _ _ _ +// | \ | |(_) | | | | | | | | +// | \| | _ __ _ | |__ | |_ __ __ __ _ | |_ ___ | |__ +// | . ` || | / _` || '_ \ | __|\ \ /\ / / / _` || __| / __|| '_ \ +// | |\ || || (_| || | | || |_ \ V V / | (_| || |_ | (__ | | | | +// \_| \_/|_| \__, ||_| |_| \__| \_/\_/ \__,_| \__| \___||_| |_| +// __/ | +// |___/ +// + +module.exports = { + // An array of folders (excluding subfolders) where your tests are located; + // if this is not specified, the test source must be passed as the second argument to the test runner. + src_folders: [], + + // See https://nightwatchjs.org/guide/concepts/page-object-model.html + page_objects_path: ['node_modules/nightwatch/examples/pages/'], + + // See https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-commands.html + custom_commands_path: ['node_modules/nightwatch/examples/custom-commands/'], + + // See https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-assertions.html + custom_assertions_path: '', + + // See https://nightwatchjs.org/guide/extending-nightwatch/adding-plugins.html + plugins: [], + + // See https://nightwatchjs.org/guide/concepts/test-globals.html#external-test-globals + globals_path : '', + + webdriver: {}, + + test_settings: { + default: { + disable_error_log: false, + launch_url: 'https://nightwatchjs.org', + + screenshots: { + enabled: false, + path: 'screens', + on_failure: true + }, + + desiredCapabilities: { + browserName : 'firefox' + }, + + webdriver: { + start_process: true, + server_path: '' + } + }, + + + + firefox: { + desiredCapabilities : { + browserName : 'firefox', + alwaysMatch: { + acceptInsecureCerts: true, + 'moz:firefoxOptions': { + args: [ + // '-headless', + // '-verbose' + ] + } + } + }, + webdriver: { + start_process: true, + server_path: '', + cli_args: [ + // very verbose geckodriver logs + // '-vv' + ] + } + }, + + chrome: { + desiredCapabilities : { + browserName : 'chrome', + 'goog:chromeOptions' : { + // More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/ + // + // w3c:false tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78) + w3c: true, + args: [ + //'--no-sandbox', + //'--ignore-certificate-errors', + //'--allow-insecure-localhost', + //'--headless' + ] + } + }, + + webdriver: { + start_process: true, + server_path: '', + cli_args: [ + // --verbose + ] + } + }, + + edge: { + desiredCapabilities : { + browserName : 'MicrosoftEdge', + 'ms:edgeOptions' : { + w3c: true, + // More info on EdgeDriver: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options + args: [ + //'--headless' + ] + } + }, + + webdriver: { + start_process: true, + // Download msedgedriver from https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/ + // and set the location below: + server_path: '', + cli_args: [ + // --verbose + ] + } + }, + + ////////////////////////////////////////////////////////////////////////////////// + // Configuration for when using cucumber-js (https://cucumber.io) | + // | + // It uses the bundled examples inside the nightwatch examples folder; feel free | + // to adapt this to your own project needs | + ////////////////////////////////////////////////////////////////////////////////// + 'cucumber-js': { + src_folders: ['examples/cucumber-js/features/step_definitions'], + + test_runner: { + // set cucumber as the runner + type: 'cucumber', + + // define cucumber specific options + options: { + //set the feature path + feature_path: 'node_modules/nightwatch/examples/cucumber-js/*/*.feature', + + // start the webdriver session automatically (enabled by default) + // auto_start_session: true + + // use parallel execution in Cucumber + // parallel: 2 // set number of workers to use (can also be defined in the cli as --parallel 2 + } + } + }, + + ////////////////////////////////////////////////////////////////////////////////// + // Configuration for when using the browserstack.com cloud service | + // | + // Please set the username and access key by setting the environment variables: | + // - BROWSERSTACK_USERNAME | + // - BROWSERSTACK_ACCESS_KEY | + // .env files are supported | + ////////////////////////////////////////////////////////////////////////////////// + browserstack: { + selenium: { + host: 'hub.browserstack.com', + port: 443 + }, + // More info on configuring capabilities can be found on: + // https://www.browserstack.com/automate/capabilities?tag=selenium-4 + desiredCapabilities: { + 'bstack:options' : { + userName: '${BROWSERSTACK_USERNAME}', + accessKey: '${BROWSERSTACK_ACCESS_KEY}', + } + }, + + disable_error_log: true, + webdriver: { + timeout_options: { + timeout: 15000, + retry_attempts: 3 + }, + keep_alive: true, + start_process: false + } + }, + + 'browserstack.local': { + extends: 'browserstack', + desiredCapabilities: { + 'browserstack.local': true + } + }, + + 'browserstack.chrome': { + extends: 'browserstack', + desiredCapabilities: { + browserName: 'chrome', + chromeOptions : { + w3c: true + } + } + }, + + 'browserstack.firefox': { + extends: 'browserstack', + desiredCapabilities: { + browserName: 'firefox' + } + }, + + 'browserstack.ie': { + extends: 'browserstack', + desiredCapabilities: { + browserName: 'internet explorer', + browserVersion: '11.0' + } + }, + + 'browserstack.safari': { + extends: 'browserstack', + desiredCapabilities: { + browserName: 'safari' + } + }, + + 'browserstack.local_chrome': { + extends: 'browserstack.local', + desiredCapabilities: { + browserName: 'chrome' + } + }, + + 'browserstack.local_firefox': { + extends: 'browserstack.local', + desiredCapabilities: { + browserName: 'firefox' + } + }, + ////////////////////////////////////////////////////////////////////////////////// + // Configuration for when using the SauceLabs cloud service | + // | + // Please set the username and access key by setting the environment variables: | + // - SAUCE_USERNAME | + // - SAUCE_ACCESS_KEY | + ////////////////////////////////////////////////////////////////////////////////// + saucelabs: { + selenium: { + host: 'ondemand.saucelabs.com', + port: 443 + }, + // More info on configuring capabilities can be found on: + // https://docs.saucelabs.com/dev/test-configuration-options/ + desiredCapabilities: { + 'sauce:options' : { + username: '${SAUCE_USERNAME}', + accessKey: '${SAUCE_ACCESS_KEY}', + screenResolution: '1280x1024' + // https://docs.saucelabs.com/dev/cli/sauce-connect-proxy/#--region + // region: 'us-west-1' + // https://docs.saucelabs.com/dev/test-configuration-options/#tunnelidentifier + // parentTunnel: '', + // tunnelIdentifier: '', + } + }, + disable_error_log: false, + webdriver: { + start_process: false + } + }, + 'saucelabs.chrome': { + extends: 'saucelabs', + desiredCapabilities: { + browserName: 'chrome', + browserVersion: 'latest', + javascriptEnabled: true, + acceptSslCerts: true, + timeZone: 'London', + chromeOptions : { + w3c: true + } + } + }, + 'saucelabs.firefox': { + extends: 'saucelabs', + desiredCapabilities: { + browserName: 'firefox', + browserVersion: 'latest', + javascriptEnabled: true, + acceptSslCerts: true, + timeZone: 'London' + } + }, + ////////////////////////////////////////////////////////////////////////////////// + // Configuration for when using the Selenium service, either locally or remote, | + // like Selenium Grid | + ////////////////////////////////////////////////////////////////////////////////// + selenium_server: { + // Selenium Server is running locally and is managed by Nightwatch + // Install the NPM package @nightwatch/selenium-server or download the selenium server jar file from https://github.com/SeleniumHQ/selenium/releases/, e.g.: selenium-server-4.1.1.jar + selenium: { + start_process: true, + port: 4444, + server_path: '', // Leave empty if @nightwatch/selenium-server is installed + command: 'standalone', // Selenium 4 only + cli_args: { + //'webdriver.gecko.driver': '', + //'webdriver.chrome.driver': '' + } + }, + webdriver: { + start_process: false, + default_path_prefix: '/wd/hub' + } + }, + + 'selenium.chrome': { + extends: 'selenium_server', + desiredCapabilities: { + browserName: 'chrome', + chromeOptions : { + w3c: true + } + } + }, + + 'selenium.firefox': { + extends: 'selenium_server', + desiredCapabilities: { + browserName: 'firefox', + 'moz:firefoxOptions': { + args: [ + // '-headless', + // '-verbose' + ] + } + } + } + } +}; diff --git a/apps/remixdesktop/package.json b/apps/remixdesktop/package.json index 08bfd30431..ce7056120a 100644 --- a/apps/remixdesktop/package.json +++ b/apps/remixdesktop/package.json @@ -29,6 +29,7 @@ "installRipGrepMacOXarm64": "rm -rf node_modules/@vscode/ripgrep/bin && npm_config_arch=arm64 node node_modules/@vscode/ripgrep/lib/postinstall.js", "postinstall": "electron-builder install-app-deps", "selenium-install-linux": "selenium-standalone install --drivers.chrome.version=116.0.5845.228 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com", + "selenium-install-win": "selenium-standalone install --drivers.chrome.version=116.0.5845.228 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com", "selenium-install-mac": "selenium-standalone install --drivers.chromiumedge.version=114.0.1788.0 --drivers.chrome.version=114.0.1788.0 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com", "selenium-linux": "selenium-standalone start --config=./selenium-linux.config.js", "selenium-mac": "selenium-standalone start --config=./selenium-mac.config.js", diff --git a/apps/remixdesktop/selenium-win.config.js b/apps/remixdesktop/selenium-win.config.js new file mode 100644 index 0000000000..31f2b50a68 --- /dev/null +++ b/apps/remixdesktop/selenium-win.config.js @@ -0,0 +1,10 @@ +module.exports = { + baseURL: 'https://selenium-release.storage.googleapis.com', + drivers: { + chrome: { + version: '116.0.5845.96-win32', + arch: process.arch, + baseURL: 'https://chromedriver.storage.googleapis.com' + } + } +} \ No newline at end of file diff --git a/apps/remixdesktop/src/main.ts b/apps/remixdesktop/src/main.ts index b7ee55f60c..b42e4eca68 100644 --- a/apps/remixdesktop/src/main.ts +++ b/apps/remixdesktop/src/main.ts @@ -6,6 +6,7 @@ export let isPackaged = false; export const version = app.getVersion(); const args = process.argv.slice(1) +console.log("args", args) export const isE2ELocal = args.find(arg => arg.startsWith('--e2e-local')) export const isE2E = args.find(arg => arg.startsWith('--e2e')) diff --git a/apps/remixdesktop/test/nighwatch.app.ts b/apps/remixdesktop/test/nighwatch.app.ts index b4f5d55a45..c40a480bc7 100644 --- a/apps/remixdesktop/test/nighwatch.app.ts +++ b/apps/remixdesktop/test/nighwatch.app.ts @@ -73,20 +73,31 @@ module.exports = { } } }, - windows: { + winlocal: { desiredCapabilities: { browserName: 'chrome', javascriptEnabled: true, acceptSslCerts: true, 'goog:chromeOptions': { - "binary": "./out/remixconnect-win32-x64/remixconnect.exe", + "binary": "./release/win-unpacked/Remix-Desktop.exe", "args": [ - "--folder=test/contracts", - "--remix-ide-url=http://localhost:8080", - "--e2e" + "--e2e-local", ] } } - } + }, + win: { + desiredCapabilities: { + browserName: 'chrome', + javascriptEnabled: true, + acceptSslCerts: true, + 'goog:chromeOptions': { + "binary": "./release/win-unpacked/Remix-Desktop.exe", + "args": [ + "--e2e", + ] + } + } + }, } } \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/xterm.test.ts b/apps/remixdesktop/test/tests/app/xterm.test.ts index 6ab641455a..6d7cd9595e 100644 --- a/apps/remixdesktop/test/tests/app/xterm.test.ts +++ b/apps/remixdesktop/test/tests/app/xterm.test.ts @@ -1,195 +1,217 @@ -import { NightwatchBrowser } from 'nightwatch' +import {NightwatchBrowser} from 'nightwatch' + + + + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + open: function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') + }, + 'open xterm linux and create a file': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible('*[data-type="remixUIXT"]', 10000) + .click('*[data-type="remixUIXT"]') + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('echo test > example.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemexample.txt"]', 10000) + }, + 'rename that file': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('mv example.txt newExample.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample.txt"]', 10000) + }, + 'create a file and delete it': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('touch newExample2.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('rm newExample2.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) + }, + 'run a git clone command': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('git clone https://github.com/ethereum/awesome-remix').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) + .click('*[data-id="treeViewLitreeViewItemawesome-remix"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix/README.md"]', 10000) + }, + 'remove the cloned repo': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-type="remixUIXT"]', 10000) + .click('*[data-type="remixUIXT"]') + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('rm -rf awesome-remix').sendKeys(this.Keys.ENTER) + }) + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) + }, + 'list files': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('ls').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample.txt')) + } + ) + }, + 'switch to a new terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="createTerminalButton"]', 10000) + .click('*[data-id="createTerminalButton"]') + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 2) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample.txt')) + } + ) + }, + 'switch to a third terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="createTerminalButton"]', 10000) + .click('*[data-id="createTerminalButton"]') + .waitForElementVisible( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + 10000 + ) + .click({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 3) + }) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('echo thirdterminal').sendKeys(this.Keys.ENTER) + }) + }, + 'switch back to the second terminal': function (browser: NightwatchBrowser) { + browser + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.elementIdClick(Object.values((result.value as any)[1])[0] as any) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample.txt')) + } + ) + }, + 'close the second terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) + .click('*[data-id="closeTerminalButton"]') + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 2) + }) + }, + 'switch back to the first terminal': function (browser: NightwatchBrowser) { + browser + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.elementIdClick(Object.values((result.value as any)[0])[0] as any) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample.txt')) + } + ) + }, + 'switch to the output panel': function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="tabOutput"]', 10000).click('*[data-id="tabOutput"]').waitForElementNotPresent('*[data-id="createTerminalButton"]', 10000) + }, + 'switch back to xterminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible('*[data-type="remixUIXT"]', 10000) + .click('*[data-type="remixUIXT"]') + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample.txt')) + } + ) + }, + 'clear the terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="clearTerminalButton"]', 10000) + .click('*[data-id="clearTerminalButton"]') + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample.txt')) + } + ) + }, +} + module.exports = { - before: function (browser: NightwatchBrowser, done: VoidFunction) { - done() - }, - 'opem template': function (browser: NightwatchBrowser) { - browser - .waitForElementVisible('*[data-id="openFolderButton"]', 10000) - .click('*[data-id="openFolderButton"]') - }, - 'open xterm linux and create a file': function (browser: NightwatchBrowser) { - browser - .waitForElementVisible('*[data-id="tabXTerm"]', 10000) - .click('*[data-id="tabXTerm"]') - .waitForElementVisible('*[data-type="remixUIXT"]', 10000) - .click('*[data-type="remixUIXT"]') - .perform(function () { - const actions = this.actions({ async: true }) - return actions.sendKeys('echo test > example.txt').sendKeys(this.Keys.ENTER) - }) - .waitForElementVisible('*[data-id="treeViewLitreeViewItemexample.txt"]', 10000) - }, - 'rename that file': function (browser: NightwatchBrowser) { - browser - .perform(function () { - const actions = this.actions({ async: true }) - return actions.sendKeys('mv example.txt newExample.txt').sendKeys(this.Keys.ENTER) - }) - .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample.txt"]', 10000) - }, - 'create a file and delete it': function (browser: NightwatchBrowser) { - browser - .perform(function () { - const actions = this.actions({ async: true }) - return actions.sendKeys('touch newExample2.txt').sendKeys(this.Keys.ENTER) - }) - .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) - .perform(function () { - const actions = this.actions({ async: true }) - return actions.sendKeys('rm newExample2.txt').sendKeys(this.Keys.ENTER) - }) - .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) - }, - 'run a git clone command': function (browser: NightwatchBrowser) { - browser - .perform(function () { - const actions = this.actions({ async: true }) - return actions.sendKeys('git clone https://github.com/ethereum/awesome-remix').sendKeys(this.Keys.ENTER) - } - ) - .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) - .click('*[data-id="treeViewLitreeViewItemawesome-remix"]') - .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix/README.md"]', 10000) - }, - 'remove the cloned repo': function (browser: NightwatchBrowser) { - browser - .waitForElementVisible('*[data-type="remixUIXT"]', 10000) - .click('*[data-type="remixUIXT"]') - .perform(function () { - const actions = this.actions({ async: true }) - return actions.sendKeys('rm -rf awesome-remix').sendKeys(this.Keys.ENTER) - } - ) - .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) - }, - 'list files': function (browser: NightwatchBrowser) { - browser - .perform(function () { - const actions = this.actions({ async: true }) - return actions.sendKeys('ls').sendKeys(this.Keys.ENTER) - }) - .waitForElementVisible({ - selector: "//*[@data-type='remixUIXT' and @data-active='1']", - timeout: 10000, - locateStrategy: 'xpath' - }) - .getText({ - selector: "//*[@data-type='remixUIXT' and @data-active='1']", - timeout: 10000, - locateStrategy: 'xpath' - }, function (result) { - console.log('Text content of the element:', result.value); - browser.assert.ok((result.value as string).includes('newExample.txt')) - }) - }, - 'switch to a new terminal': function (browser: NightwatchBrowser) { - browser - .waitForElementVisible('*[data-id="createTerminalButton"]', 10000) - .click('*[data-id="createTerminalButton"]') - .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { - browser.assert.ok((result.value as any).length === 2) - }) - .getText({ - selector: "//*[@data-type='remixUIXT' and @data-active='1']", - timeout: 10000, - locateStrategy: 'xpath' - }, function (result) { - console.log('Text content of the element:', result.value); - browser.assert.ok(!(result.value as string).includes('newExample.txt')) - }) - }, - 'switch to a third terminal': function (browser: NightwatchBrowser) { - browser - .waitForElementVisible('*[data-id="createTerminalButton"]', 10000) - .click('*[data-id="createTerminalButton"]') - .waitForElementVisible({ - selector: "//*[@data-type='remixUIXT' and @data-active='1']", - timeout: 10000, - locateStrategy: 'xpath' - }, 10000) - .click({ - selector: "//*[@data-type='remixUIXT' and @data-active='1']", - timeout: 10000, - locateStrategy: 'xpath' - }) - .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { - browser.assert.ok((result.value as any).length === 3) - }) - .perform(function () { - const actions = this.actions({ async: true }) - return actions.sendKeys('echo thirdterminal').sendKeys(this.Keys.ENTER) - }) - }, - 'switch back to the second terminal': function (browser: NightwatchBrowser) { - browser - .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { - browser.elementIdClick(((Object.values((result.value as any)[1]))[0] as any)) - }) - .getText({ - selector: "//*[@data-type='remixUIXT' and @data-active='1']", - timeout: 10000, - locateStrategy: 'xpath' - }, function (result) { - console.log('Text content of the element:', result.value); - browser.assert.ok(!(result.value as string).includes('newExample.txt')) - }) - }, - 'close the second terminal': function (browser: NightwatchBrowser) { - browser - .waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) - .click('*[data-id="closeTerminalButton"]') - .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { - browser.assert.ok((result.value as any).length === 2) - }) - }, - 'switch back to the first terminal': function (browser: NightwatchBrowser) { - browser - .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { - browser.elementIdClick(((Object.values((result.value as any)[0]))[0] as any)) - }) - .getText({ - selector: "//*[@data-type='remixUIXT' and @data-active='1']", - timeout: 10000, - locateStrategy: 'xpath' - }, function (result) { - console.log('Text content of the element:', result.value); - browser.assert.ok((result.value as string).includes('newExample.txt')) - }) - }, - 'switch to the output panel': function (browser: NightwatchBrowser) { - browser - .waitForElementVisible('*[data-id="tabOutput"]', 10000) - .click('*[data-id="tabOutput"]') - .waitForElementNotPresent('*[data-id="createTerminalButton"]', 10000) - }, - 'switch back to xterminal': function (browser: NightwatchBrowser) { - browser - .waitForElementVisible('*[data-id="tabXTerm"]', 10000) - .click('*[data-id="tabXTerm"]') - .waitForElementVisible('*[data-type="remixUIXT"]', 10000) - .click('*[data-type="remixUIXT"]') - .getText({ - selector: "//*[@data-type='remixUIXT' and @data-active='1']", - timeout: 10000, - locateStrategy: 'xpath' - }, function (result) { - console.log('Text content of the element:', result.value); - browser.assert.ok((result.value as string).includes('newExample.txt')) - }) - }, - 'clear the terminal': function (browser: NightwatchBrowser) { - browser - .waitForElementVisible('*[data-id="clearTerminalButton"]', 10000) - .click('*[data-id="clearTerminalButton"]') - .getText({ - selector: "//*[@data-type='remixUIXT' and @data-active='1']", - timeout: 10000, - locateStrategy: 'xpath' - }, function (result) { - console.log('Text content of the element:', result.value); - browser.assert.ok(!(result.value as string).includes('newExample.txt')) - }) - } + ...process.platform.startsWith('win')?{}:tests } \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/xtermwin.test.ts b/apps/remixdesktop/test/tests/app/xtermwin.test.ts new file mode 100644 index 0000000000..dd448d746d --- /dev/null +++ b/apps/remixdesktop/test/tests/app/xtermwin.test.ts @@ -0,0 +1,243 @@ +import {NightwatchBrowser} from 'nightwatch' + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + open: function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') + }, + 'open xterm linux and create a file': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible('*[data-id="select_shell"]') + .click('*[data-id="select_shell"]') + .waitForElementVisible('*[data-id="select_powershell.exe"]') + .click('*[data-id="select_powershell.exe"]') + .pause(3000) + .waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) + .click("[data-active='1'][data-type='remixUIXT']") + .pause(1000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('"test" | Out-File -FilePath example.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemexample.txt"]', 10000) + }, + 'rename that file': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('Move-Item -Path example.txt -Destination newExample.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample.txt"]', 10000) + }, + 'create a file and delete it': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('touch newExample2.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('Remove-Item -Path newExample2.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) + }, + 'run a git clone command': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('git clone https://github.com/ethereum/awesome-remix').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) + .click('*[data-id="treeViewLitreeViewItemawesome-remix"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix/README.md"]', 10000) + }, + 'remove the cloned repo': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) + .click("[data-active='1'][data-type='remixUIXT']") + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('Remove-Item -Path awesome-remix -Recurse -Force').sendKeys(this.Keys.ENTER) + }) + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) + }, + 'list files': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('ls').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample.txt')) + } + ) + }, + 'switch to a new terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="select_shell"]') + .click('*[data-id="select_shell"]') + .waitForElementVisible('*[data-id="select_powershell.exe"]') + .click('*[data-id="select_powershell.exe"]') + .pause(3000) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + console.log(result) + browser.assert.ok((result.value as any).length === 3) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample.txt')) + } + ) + }, + 'switch to a third terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="select_shell"]') + .click('*[data-id="select_shell"]') + .waitForElementVisible('*[data-id="select_powershell.exe"]') + .click('*[data-id="select_powershell.exe"]') + .pause(3000) + .waitForElementVisible( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + 10000 + ) + .click({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 4) + }) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('echo thirdterminal').sendKeys(this.Keys.ENTER) + }) + }, + 'switch back to the second terminal': function (browser: NightwatchBrowser) { + browser + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.elementIdClick(Object.values((result.value as any)[2])[0] as any) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample.txt')) + } + ) + }, + 'close the second terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) + .click('*[data-id="closeTerminalButton"]') + .pause(1000) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 3) + }) + }, + 'switch back to the first terminal': function (browser: NightwatchBrowser) { + browser + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.elementIdClick(Object.values((result.value as any)[1])[0] as any) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample.txt')) + } + ) + }, + 'switch to the output panel': function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="tabOutput"]', 10000).click('*[data-id="tabOutput"]').waitForElementNotPresent('*[data-id="createTerminalButton"]', 10000) + }, + 'switch back to xterminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) + .click("[data-active='1'][data-type='remixUIXT']") + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample.txt')) + } + ) + }, + 'clear the terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="clearTerminalButton"]', 10000) + .click('*[data-id="clearTerminalButton"]') + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample.txt')) + } + ) + }, + 'close all terminals': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) + .click('*[data-id="closeTerminalButton"]') + .pause(3000) + .click('*[data-id="closeTerminalButton"]') + .pause(3000) + .click('*[data-id="closeTerminalButton"]') + .pause(3000) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 0) + }).end() + }, + after: function (browser: NightwatchBrowser) { + browser.end() + }, +} + +module.exports = { + ...process.platform.startsWith('win')?tests:{} +} \ No newline at end of file diff --git a/libs/remix-ui/xterm/src/lib/components/remix-ui-terminal-menu-xterm.tsx b/libs/remix-ui/xterm/src/lib/components/remix-ui-terminal-menu-xterm.tsx index 4f546ee442..1620aee195 100644 --- a/libs/remix-ui/xterm/src/lib/components/remix-ui-terminal-menu-xterm.tsx +++ b/libs/remix-ui/xterm/src/lib/components/remix-ui-terminal-menu-xterm.tsx @@ -35,10 +35,10 @@ export const RemixUIXtermMenu = (props: RemixUiTerminalProps) => {