Merge branch 'master' into theme-hacker-owl

pull/1527/head
U.M Andrew 3 years ago committed by GitHub
commit 45e1a55ac7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 292
      .circleci/config.yml
  2. 27
      .github/workflows/publish-action.yml
  3. 2
      .gitignore
  4. 3
      .gitmodules
  5. 1
      README.md
  6. 35
      apps/remix-ide-e2e/nightwatch.ts
  7. 4
      apps/remix-ide-e2e/seleniumConfig.js
  8. 33
      apps/remix-ide-e2e/src/buildGroupTests.js
  9. 15
      apps/remix-ide-e2e/src/checkGroupTests.js
  10. 14
      apps/remix-ide-e2e/src/commands/clearConsole.ts
  11. 24
      apps/remix-ide-e2e/src/commands/clearTransactions.ts
  12. 2
      apps/remix-ide-e2e/src/commands/clickInstance.ts
  13. 12
      apps/remix-ide-e2e/src/helpers/buildgrouptest.ts
  14. 2
      apps/remix-ide-e2e/src/helpers/init.ts
  15. 47
      apps/remix-ide-e2e/src/select_tests.sh
  16. 0
      apps/remix-ide-e2e/src/tests/ballot_0_4_11.test.ts
  17. 11
      apps/remix-ide-e2e/src/tests/compiler_api.test.ts
  18. 69
      apps/remix-ide-e2e/src/tests/debugger.test.ts
  19. 30
      apps/remix-ide-e2e/src/tests/fileManager_api.test.ts
  20. 2
      apps/remix-ide-e2e/src/tests/generalSettings.test.ts
  21. 5
      apps/remix-ide-e2e/src/tests/gist.test.ts
  22. 73
      apps/remix-ide-e2e/src/tests/plugin_api.ts
  23. 0
      apps/remix-ide-e2e/src/tests/recorder.test.ts
  24. 25
      apps/remix-ide-e2e/src/tests/remixd.test.ts
  25. 23
      apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts
  26. 19
      apps/remix-ide-e2e/src/tests/solidityImport.test.ts
  27. 6
      apps/remix-ide-e2e/src/tests/solidityImport_group1.spec.ts
  28. 68
      apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
  29. 53
      apps/remix-ide-e2e/src/tests/specialFunctions.test.ts
  30. 0
      apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts
  31. 47
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  32. 68
      apps/remix-ide-e2e/src/tests/transactionExecution.test.ts
  33. 0
      apps/remix-ide-e2e/src/tests/verticalIconsPanel.test.ts
  34. 2
      apps/remix-ide-e2e/src/types/index.d.ts
  35. 6
      apps/remix-ide/ci/browser_test.sh
  36. 2
      apps/remix-ide/ci/browser_tests.sh
  37. 27
      apps/remix-ide/ci/browser_tests_chrome_2.sh
  38. 27
      apps/remix-ide/ci/browser_tests_firefox_1.sh
  39. 27
      apps/remix-ide/ci/browser_tests_firefox_2.sh
  40. 8
      apps/remix-ide/ci/browser_tests_plugin_api.sh
  41. 21
      apps/remix-ide/ci/browser_tests_run_deploy.sh
  42. 22
      apps/remix-ide/ci/lint.sh
  43. 7
      apps/remix-ide/ci/publishIpfs
  44. 367
      apps/remix-ide/src/app.js
  45. 329
      apps/remix-ide/src/app/components/vertical-icons.js
  46. 8
      apps/remix-ide/src/app/editor/editor.js
  47. 1
      apps/remix-ide/src/app/files/fileManager.js
  48. 3
      apps/remix-ide/src/app/files/slither-handle.js
  49. 6
      apps/remix-ide/src/app/tabs/runTab/contractDropdown.js
  50. 20
      apps/remix-ide/src/app/tabs/theme-module.js
  51. 11
      apps/remix-ide/src/assets/css/themes/remix-black_undtds.css
  52. 9
      apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css
  53. 12
      apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css
  54. 7
      apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css
  55. 7
      apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css
  56. 3
      apps/remix-ide/src/blockchain/blockchain.js
  57. 10
      apps/remix-ide/src/framingService.js
  58. 1
      apps/remix-ide/src/index.html
  59. 10
      apps/remix-ide/src/index.js
  60. 16
      apps/remix-ide/src/index.tsx
  61. 1
      apps/remix-ide/src/production.index.html
  62. 2
      apps/remix-ide/src/remixAppManager.js
  63. 28
      apps/remix-ide/src/walkthroughService.js
  64. 1
      apps/remix-ide/src/webpack.index.html
  65. 3
      apps/remix-ide/tsconfig.json
  66. 11
      apps/remix-ide/webpack.config.js
  67. 9
      apps/solidity-compiler/src/app/app.tsx
  68. 5
      apps/solidity-compiler/src/app/compiler-api.ts
  69. 16
      apps/solidity-compiler/src/app/compiler.ts
  70. 2
      apps/solidity-compiler/src/environments/environment.prod.ts
  71. 2
      apps/solidity-compiler/src/environments/environment.ts
  72. 2
      apps/solidity-compiler/src/index.ts
  73. 9
      apps/solidity-compiler/src/main.tsx
  74. 4
      apps/solidity-compiler/src/polyfills.ts
  75. 9
      libs/remix-analyzer/package.json
  76. 7
      libs/remix-astwalker/package.json
  77. 2
      libs/remix-core-plugin/src/lib/compiler-artefacts.ts
  78. 8
      libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts
  79. 11
      libs/remix-debug/package.json
  80. 4
      libs/remix-lib/package.json
  81. 15
      libs/remix-lib/src/execution/txExecution.ts
  82. 7
      libs/remix-simulator/package.json
  83. 7
      libs/remix-solidity/package.json
  84. 11
      libs/remix-tests/package.json
  85. 4
      libs/remix-ui/app/.babelrc
  86. 248
      libs/remix-ui/app/.eslintrc
  87. 1
      libs/remix-ui/app/src/index.ts
  88. 5
      libs/remix-ui/app/src/lib/remix-app/context/context.tsx
  89. 26
      libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.css
  90. 53
      libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.tsx
  91. 43
      libs/remix-ui/app/src/lib/remix-app/modals/alert.tsx
  92. 51
      libs/remix-ui/app/src/lib/remix-app/modals/matomo.tsx
  93. 16
      libs/remix-ui/app/src/lib/remix-app/modals/splashscreen.tsx
  94. 90
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  95. 71
      libs/remix-ui/app/src/lib/remix-app/style/remix-app.css
  96. 19
      libs/remix-ui/app/tsconfig.json
  97. 13
      libs/remix-ui/app/tsconfig.lib.json
  98. 15
      libs/remix-ui/app/tsconfig.spec.json
  99. 2
      libs/remix-ui/clipboard/jest.config.js
  100. 2
      libs/remix-ui/clipboard/src/index.ts
  101. Some files were not shown because too many files have changed in this diff Show More

@ -2,12 +2,14 @@
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
version: 2.1
orbs:
browser-tools: circleci/browser-tools@1.2.3
jobs:
lint:
build:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -21,78 +23,29 @@ jobs:
steps:
- checkout
- run: npm install
- run:
name: Remix Libs Linting
command: npm run lint:libs
- run:
name: Remix IDE Linting
command: npm run lint
- run:
name: Remix IDE e2e Linting
command: npm run lint remix-ide-e2e
remix-libs:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
resource_class: xlarge
# - image: circleci/mongo:3.4.4
environment:
- COMMIT_AUTHOR_EMAIL: "yann@ethereum.org"
- COMMIT_AUTHOR: "Circle CI"
working_directory: ~/remix-project
steps:
- checkout
- restore_cache:
keys:
- v1-deps-{{ checksum "package-lock.json" }}
- run: npm install
- run: npm run build:libs
- run: cd dist/libs/remix-tests && npm install
- run: npm run test:libs
remix-ide-chrome-1:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
resource_class: xlarge
# - image: circleci/mongo:3.4.4
environment:
- COMMIT_AUTHOR_EMAIL: "yann@ethereum.org"
- COMMIT_AUTHOR: "Circle CI"
working_directory: ~/remix-project
parallelism: 12
steps:
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- run: npm install
- run: npx nx build remix-ide --with-deps
- run:
name: Download Selenium
command: ./node_modules/.bin/selenium-standalone install --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com
- run:
name: Start Selenium
command: ./node_modules/.bin/selenium-standalone start --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com
background: true
- run: ./apps/remix-ide/ci/browser_tests_chrome_1.sh
- store_test_results:
path: ./reports/tests
- store_artifacts:
path: ./reports/screenshots
- save_cache:
key: v1-deps-{{ checksum "package-lock.json" }}
paths:
- node_modules
- run: npm run downloadsolc_assets
- run: npx nx build remix-ide
- run: npx nx build remix-ide-e2e-src-local-plugin
remix-ide-chrome-2:
- run: npm run build:libs
- run: mkdir persist && zip -r persist/dist.zip dist
- persist_to_workspace:
root: .
paths:
- 'persist'
lint:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -103,32 +56,20 @@ jobs:
- COMMIT_AUTHOR_EMAIL: "yann@ethereum.org"
- COMMIT_AUTHOR: "Circle CI"
working_directory: ~/remix-project
parallelism: 12
parallelism: 35
steps:
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- restore_cache:
keys:
- v1-deps-{{ checksum "package-lock.json" }}
- run: npm install
- run: npm run downloadsolc_assets
- run: npx nx build remix-ide --with-deps
- run:
name: Download Selenium
command: ./node_modules/.bin/selenium-standalone install --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com
- run:
name: Start Selenium
command: ./node_modules/.bin/selenium-standalone start --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com
background: true
- run: ./apps/remix-ide/ci/browser_tests_chrome_2.sh
- store_test_results:
path: ./reports/tests
- store_artifacts:
path: ./reports/screenshots
remix-ide-firefox-1:
name: Remix Libs Linting
command: ./apps/remix-ide/ci/lint.sh
remix-libs:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -140,30 +81,22 @@ jobs:
- COMMIT_AUTHOR: "Circle CI"
working_directory: ~/remix-project
parallelism: 12
steps:
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- run: npm install
- run: npx nx build remix-ide --with-deps
- run:
name: Download Selenium
command: ./node_modules/.bin/selenium-standalone install --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js
- run:
name: Start Selenium
command: ./node_modules/.bin/selenium-standalone start --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js
background: true
- run: ./apps/remix-ide/ci/browser_tests_firefox_1.sh
- store_test_results:
path: ./reports/tests
- store_artifacts:
path: ./reports/screenshots
- attach_workspace:
at: .
- run: unzip ./persist/dist.zip
- restore_cache:
keys:
- v1-deps-{{ checksum "package-lock.json" }}
- run: npm i
- run: cd dist/libs/remix-tests && npm install
- run: npm run test:libs
remix-ide-firefox-2:
remix-ide-chrome:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -175,31 +108,33 @@ jobs:
- COMMIT_AUTHOR: "Circle CI"
working_directory: ~/remix-project
parallelism: 12
parallelism: 70
steps:
- browser-tools/install-chrome
- browser-tools/install-chromedriver
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- attach_workspace:
at: .
- run: unzip ./persist/dist.zip
- restore_cache:
keys:
- v1-deps-{{ checksum "package-lock.json" }}
- run: npm install
- run: npm run downloadsolc_assets
- run: npx nx build remix-ide --with-deps
- run:
name: Download Selenium
command: ./node_modules/.bin/selenium-standalone install --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js
- run: npm run selenium-install
- run:
name: Start Selenium
command: ./node_modules/.bin/selenium-standalone start --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js
command: npx selenium-standalone start
background: true
- run: ./apps/remix-ide/ci/browser_tests_firefox_2.sh
- run: ./apps/remix-ide/ci/browser_test.sh chrome
- store_test_results:
path: ./reports/tests
- store_artifacts:
path: ./reports/screenshots
remix-ide-run-deploy:
remix-ide-firefox:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -209,23 +144,26 @@ jobs:
environment:
- COMMIT_AUTHOR_EMAIL: "yann@ethereum.org"
- COMMIT_AUTHOR: "Circle CI"
- FILES_TO_PACKAGE: "dist/apps/remix-ide/assets dist/apps/remix-ide/index.html dist/apps/remix-ide/main.js dist/apps/remix-ide/polyfills.js dist/apps/remix-ide/runtime.js dist/apps/remix-ide/vendor.js dist/apps/remix-ide/favicon.ico"
working_directory: ~/remix-project
parallelism: 70
steps:
- browser-tools/install-firefox
- browser-tools/install-geckodriver
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- attach_workspace:
at: .
- run: unzip ./persist/dist.zip
- restore_cache:
keys:
- v1-deps-{{ checksum "package-lock.json" }}
- run: npm install
- run: npx nx build remix-ide --with-deps
- run:
name: Download Selenium
command: ./node_modules/.bin/selenium-standalone install --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com
- run: npm run selenium-install
- run:
name: Start Selenium
command: ./node_modules/.bin/selenium-standalone start --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com
command: npx selenium-standalone start
background: true
- run: ./apps/remix-ide/ci/browser_tests_run_deploy.sh
- run: ./apps/remix-ide/ci/browser_test.sh firefox
- store_test_results:
path: ./reports/tests
- store_artifacts:
@ -234,7 +172,7 @@ jobs:
remix-ide-plugin-api:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -246,20 +184,22 @@ jobs:
- COMMIT_AUTHOR: "Circle CI"
- FILES_TO_PACKAGE: "dist/apps/remix-ide/assets dist/apps/remix-ide/index.html dist/apps/remix-ide/main.js dist/apps/remix-ide/polyfills.js dist/apps/remix-ide/runtime.js dist/apps/remix-ide/vendor.js dist/apps/remix-ide/favicon.ico"
working_directory: ~/remix-project
parallelism: 7
steps:
- browser-tools/install-chrome
- browser-tools/install-chromedriver
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- attach_workspace:
at: .
- run: unzip ./persist/dist.zip
- restore_cache:
keys:
- v1-deps-{{ checksum "package-lock.json" }}
- run: npm install
- run: npx nx build remix-ide --with-deps
- run: npx nx build remix-ide-e2e-src-local-plugin
- run:
name: Download Selenium
command: ./node_modules/.bin/selenium-standalone install --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com
- run: npm run selenium-install
- run:
name: Start Selenium
command: ./node_modules/.bin/selenium-standalone start --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com
command: npx selenium-standalone start
background: true
- run: ./apps/remix-ide/ci/browser_tests_plugin_api.sh
- store_test_results:
@ -270,7 +210,7 @@ jobs:
deploy-remix-live:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -285,8 +225,6 @@ jobs:
steps:
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- run: npm install
- run: npm run downloadsolc_assets
- run: npm run build:production
@ -300,7 +238,7 @@ jobs:
publish:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -315,8 +253,6 @@ jobs:
steps:
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- setup_remote_docker
- run: npm install
- run: npm run downloadsolc_assets
@ -328,7 +264,7 @@ jobs:
deploy-remix-alpha:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -343,8 +279,6 @@ jobs:
steps:
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- run: npm install
- run: npm run downloadsolc_assets
- run: npm run build:production
@ -358,7 +292,7 @@ jobs:
deploy-remix-beta:
docker:
# specify the version you desire here
- image: circleci/node:14.17.6-browsers
- image: cimg/node:14.17.6-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@ -373,8 +307,6 @@ jobs:
steps:
- checkout
- run: git submodule sync --recursive
- run: git submodule update --recursive --init
- run: npm install
- run: npm run build:libs
- run: npm run downloadsolc_assets
@ -390,60 +322,48 @@ workflows:
version: 2
build_all:
jobs:
- lint
- build
- lint:
requires:
- build
- remix-libs:
requires:
- lint
- build
- remix-ide-plugin-api:
requires:
- lint
- remix-ide-chrome-1:
- build
- remix-ide-chrome:
requires:
- lint
- remix-ide-chrome-2:
- build
- remix-ide-firefox:
requires:
- lint
- remix-ide-firefox-1:
requires:
- lint
- remix-ide-firefox-2:
requires:
- lint
- remix-ide-run-deploy:
requires:
- lint
- publish:
requires:
- lint
- build
- deploy-remix-live:
requires:
- remix-ide-chrome-1
- remix-ide-chrome-2
- remix-ide-firefox-1
- remix-ide-firefox-2
- remix-ide-run-deploy
- lint
- remix-libs
- remix-ide-chrome
- remix-ide-firefox
- remix-ide-plugin-api
filters:
branches:
only: remix_live
- deploy-remix-alpha:
requires:
- remix-ide-chrome-1
- remix-ide-chrome-2
- remix-ide-firefox-1
- remix-ide-firefox-2
- remix-ide-run-deploy
- lint
- remix-libs
- remix-ide-chrome
- remix-ide-firefox
- remix-ide-plugin-api
filters:
branches:
only: master
- deploy-remix-beta:
requires:
- remix-ide-chrome-1
- remix-ide-chrome-2
- remix-ide-firefox-1
- remix-ide-firefox-2
- remix-ide-run-deploy
- lint
- remix-libs
- remix-ide-chrome
- remix-ide-firefox
- remix-ide-plugin-api
filters:
branches:

@ -0,0 +1,27 @@
name: remix-publish-action
on:
pull_request:
types: [ labeled ]
jobs:
build:
if: ${{ github.event.label.name == 'publish' }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- run: npm install
- run: ls
- run: pwd
- run: npm run downloadsolc_assets
- run: npm run build:production
- run: echo "action_state=$('./apps/remix-ide/ci/publishIpfs')" >> $GITHUB_ENV
- uses: mshick/add-pr-comment@v1
with:
message: |
ipfs://${{ env.action_state }}
https://ipfs.remixproject.org/ipfs/${{ env.action_state }}
https://gateway.ipfs.io/ipfs/${{ env.action_state }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
repo-token-user-login: 'github-actions[bot]' # The user.login for temporary GitHub tokens
allow-repeats: false # This is the default

2
.gitignore vendored

@ -12,6 +12,8 @@ docs/_build
TODO
soljson.js
*~
*_group*.*.ts
*_group*.ts
# compiled output

3
.gitmodules vendored

@ -1,3 +0,0 @@
[submodule "libs/remix-ui/tabs/react-tabs"]
path = libs/remix-ui/tabs/react-tabs
url = https://github.com/reactjs/react-tabs

@ -51,6 +51,7 @@ git clone https://github.com/ethereum/remix-project.git
```bash
cd remix-project
npm install
npm run build:libs // Build remix libs
nx build
nx serve
```

@ -1,8 +1,3 @@
import * as fs from 'fs'
const crxFile = fs.readFileSync('apps/remix-ide-e2e/src/extensions/chrome/metamask.crx')
const metamaskExtension = Buffer.from(crxFile).toString('base64')
module.exports = {
src_folders: ['dist/apps/remix-ide-e2e/src/tests'],
output_folder: './reports/tests',
@ -28,7 +23,10 @@ module.exports = {
desiredCapabilities: {
browserName: 'firefox',
javascriptEnabled: true,
acceptSslCerts: true
acceptSslCerts: true,
'moz:firefoxOptions': {
args: ['-headless']
}
},
exclude: ['dist/apps/remix-ide-e2e/src/tests/runAndDeploy.js', 'dist/apps/remix-ide-e2e/src/tests/pluginManager.spec.ts']
},
@ -39,34 +37,36 @@ module.exports = {
javascriptEnabled: true,
acceptSslCerts: true,
'goog:chromeOptions': {
args: ['window-size=2560,1440', 'start-fullscreen']
args: ['window-size=2560,1440', 'start-fullscreen', '--no-sandbox', '--headless', '--verbose']
}
}
},
'chrome-runAndDeploy': {
chromeDesktop: {
desiredCapabilities: {
browserName: 'chrome',
javascriptEnabled: true,
acceptSslCerts: true,
'goog:chromeOptions': {
args: ['window-size=2560,1440', 'start-fullscreen'],
extensions: [metamaskExtension]
args: ['window-size=2560,1440', 'start-fullscreen', '--no-sandbox']
}
}
},
safari: {
'chrome-runAndDeploy': {
desiredCapabilities: {
browserName: 'safari',
browserName: 'chrome',
javascriptEnabled: true,
acceptSslCerts: true
acceptSslCerts: true,
'goog:chromeOptions': {
args: ['window-size=2560,1440', 'start-fullscreen', '--no-sandbox', '--headless', '--verbose']
}
}
},
ie: {
firefoxDesktop: {
desiredCapabilities: {
browserName: 'internet explorer',
browserName: 'firefox',
javascriptEnabled: true,
acceptSslCerts: true
}
@ -76,7 +76,10 @@ module.exports = {
desiredCapabilities: {
browserName: 'firefox',
javascriptEnabled: true,
acceptSslCerts: true
acceptSslCerts: true,
'moz:firefoxOptions': {
args: ['-headless']
}
}
}
}

@ -1,10 +1,10 @@
/* eslint-disable */
module.exports = {
version: '3.8.1',
version: '4.0.0',
baseURL: 'https://selenium-release.storage.googleapis.com',
drivers: {
chrome: {
version: '2.39',
version: '96.0.4664.35',
arch: process.arch,
baseURL: 'https://chromedriver.storage.googleapis.com'
}

@ -0,0 +1,33 @@
const testFolder = './apps/remix-ide-e2e/src/tests/'
const fs = require('fs')
// build group tests
const source = `'use strict'
import * as test from './#file'
import buildGroupTest from '../helpers/buildgrouptest'
const group = '#groupname'
module.exports = buildGroupTest(group, test)
`
fs.readdirSync(testFolder).forEach(file => {
if (!file.includes('group')) {
const content = fs.readFileSync(testFolder + file, 'utf8')
const matches = content.match(/group\d+/g)
if (matches) {
const unique = matches.filter(onlyUnique)
unique.map((group) => {
const rewrite = source.replace('#groupname', group).replace('#file', file.replace('.ts', ''))
const extension = file.split('.')
extension.shift()
const filename = `${testFolder}${file.split('.').shift()}_${group}.${extension.join('.')}`
fs.writeFileSync(filename, rewrite)
})
}
}
})
function onlyUnique (value, index, self) {
return self.indexOf(value) === index
}

@ -0,0 +1,15 @@
const testFolder = './apps/remix-ide-e2e/src/tests/'
const fs = require('fs')
fs.readdirSync(testFolder).forEach(file => {
if (!file.includes('group')) {
const content = fs.readFileSync(testFolder + file, 'utf8')
const matches = content.match(/group\d+/g)
if (matches) {
const disabled = content.includes('@disabled')
if (!disabled) {
console.log(`WARNING ${file} has group tests but is not disabled`)
}
}
}
})

@ -0,0 +1,14 @@
import { NightwatchBrowser } from 'nightwatch'
import EventEmitter from 'events'
class clearConsole extends EventEmitter {
command (this: NightwatchBrowser): NightwatchBrowser {
this.api.waitForElementVisible('*[data-id="terminalCli"]').click('#clearConsole').perform((done) => {
done()
this.emit('complete')
})
return this
}
}
module.exports = clearConsole

@ -0,0 +1,24 @@
import { NightwatchBrowser } from 'nightwatch'
import EventEmitter from 'events'
class clearTransactions extends EventEmitter {
command (this: NightwatchBrowser): NightwatchBrowser {
const browser = this
this.api.clickLaunchIcon('udapp').element('css selector', '*[data-id="universalDappUiUdappClose"]', function (visible: any) {
if (visible.status && visible.status === -1) {
browser.api.perform((done) => {
done()
browser.emit('complete')
})
} else {
browser.api.pause(500).click('*[data-id="universalDappUiUdappClose"]').perform((done) => {
done()
browser.emit('complete')
})
}
})
return this
}
}
module.exports = clearTransactions

@ -6,7 +6,7 @@ class ClickInstance extends EventEmitter {
index = index + 2
const selector = '.instance:nth-of-type(' + index + ') > div > button'
this.api.waitForElementContainsText(selector, '', 60000).scrollAndClick(selector).perform(() => { this.emit('complete') })
this.api.waitForElementPresent(selector).waitForElementContainsText(selector, '', 60000).scrollAndClick(selector).perform(() => { this.emit('complete') })
return this
}
}

@ -0,0 +1,12 @@
export default function buildGroupTest (group: string, test: any) {
const ob = {}
// eslint-disable-next-line dot-notation
const defaults = test['default']
for (const key of Object.keys(defaults)) {
if (typeof defaults[key] === 'function' && (key.indexOf(`#${group}`) > -1 || key.indexOf('#group') === -1)) {
ob[key.replace(`#${group}`, '')] = defaults[key]
}
}
console.log(ob)
return ob
}

@ -5,7 +5,7 @@ require('dotenv').config()
export default function (browser: NightwatchBrowser, callback: VoidFunction, url?: string, preloadPlugins = true): void {
browser
.url(url || 'http://127.0.0.1:8080')
.pause(5000)
.pause(6000)
.switchBrowserTab(0)
.waitForElementVisible('[id="remixTourSkipbtn"]')
.click('[id="remixTourSkipbtn"]')

@ -0,0 +1,47 @@
#!/bin/bash
# Bash Menu Script Example
PS3='Select a browser: '
BROWSERS=( "chrome" "firefox" "exit" )
select opt in "${BROWSERS[@]}"
do
case $opt in
"chrome")
echo "Chrome selected"
BROWSER="chromeDesktop"
break
;;
"firefox")
echo "Firefox selected"
BROWSER="firefoxDesktop"
break
;;
"exit")
echo "Exiting"
exit 0
;;
*) echo "invalid option $REPLY";;
esac
done
npm run build:e2e
PS3='Select a test or command: '
TESTFILES=( $(grep -IRiL "disabled" "dist/apps/remix-ide-e2e/src/tests" | grep "\.spec\|\.test" | sort ) )
# declare -p TESTFILES
TESTFILES+=("list")
TESTFILES+=("exit")
select opt in "${TESTFILES[@]}"
do
if [ "$opt" = "exit" ]; then
break
fi
if [ "$opt" = "list" ]; then
for i in "${!TESTFILES[@]}"; do
printf "%s) %s\n" "$((i+1))" "${TESTFILES[$i]}"
done
else
# run the selected test
npm run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $opt --env=$BROWSER
fi
done

@ -9,6 +9,7 @@ const sources = [
]
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
@ -17,7 +18,7 @@ module.exports = {
return sources
},
'Should compile using "compileWithParamaters" API': function (browser: NightwatchBrowser) {
'Should compile using "compileWithParamaters" API #group1': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsCompile.js', { content: jsCompile })
.executeScript('remix.exeCurrent()')
@ -25,7 +26,7 @@ module.exports = {
.click('*[data-id="terminalClearConsole"]')
},
'Should compile using "compileWithParamaters" API with optimization On': function (browser: NightwatchBrowser) {
'Should compile using "compileWithParamaters" API with optimization On #group2': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsCompileWithOptimization.js', { content: jsCompileWithOptimization })
.executeScript('remix.exeCurrent()')
@ -33,7 +34,7 @@ module.exports = {
.click('*[data-id="terminalClearConsole"]')
},
'Should compile using "compileWithParamaters" API with optimization off check default runs': function (browser: NightwatchBrowser) {
'Should compile using "compileWithParamaters" API with optimization off check default runs #group3': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsCompileWithOptimizationDefault.js', { content: jsCompileWithOptimizationDefault })
.executeScript('remix.exeCurrent()')
@ -41,7 +42,7 @@ module.exports = {
.click('*[data-id="terminalClearConsole"]')
},
'Should update the compiler configuration with "setCompilerConfig" API': function (browser: NightwatchBrowser) {
'Should update the compiler configuration with "setCompilerConfig" API #group4': function (browser: NightwatchBrowser) {
browser
.addFile('test_updateConfiguration.js', { content: updateConfiguration })
.executeScript('remix.exeCurrent()')
@ -50,7 +51,7 @@ module.exports = {
.verifyContracts(['StorageTestUpdateConfiguration'], { wait: 5000, version: '0.6.8+commit.0bbfe453' })
},
'Should produce a stack too deep error': function (browser: NightwatchBrowser) {
'Should produce a stack too deep error #group5': function (browser: NightwatchBrowser) {
browser
.setSolidityCompilerVersion('soljson-v0.8.1+commit.df193b15.js')
.addFile('ContractStackLimit.sol', { content: contractStackLimit })

@ -3,7 +3,7 @@ import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
@ -12,16 +12,17 @@ module.exports = {
return sources
},
'Should launch debugger': function (browser: NightwatchBrowser) {
'Should launch debugger #group1': function (browser: NightwatchBrowser) {
browser.addFile('blah.sol', sources[0]['blah.sol'])
.clickLaunchIcon('udapp')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 65000)
.click('*[title="Deploy - transact (not payable)"]')
.debugTransaction(0)
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.clearConsole()
},
'Should debug failing transaction': function (browser: NightwatchBrowser) {
'Should debug failing transaction #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]')
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="universalDappUiTitleExpander"]')
@ -29,14 +30,14 @@ module.exports = {
.scrollAndClick('*[title="string name, uint256 goal"]')
.setValue('*[title="string name, uint256 goal"]', '"toast", 999')
.click('*[data-id="createProject - transact (not payable)"]')
.debugTransaction(1)
.debugTransaction(0)
.pause(2000)
.scrollAndClick('*[data-id="solidityLocals"]')
.waitForElementContainsText('*[data-id="solidityLocals"]', 'toast', 60000)
.waitForElementContainsText('*[data-id="solidityLocals"]', '999', 60000)
},
'Should debug transaction using slider': function (browser: NightwatchBrowser) {
'Should debug transaction using slider #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]')
.waitForElementVisible('*[data-id="slider"]')
// eslint-disable-next-line dot-notation
@ -48,7 +49,7 @@ module.exports = {
.waitForElementContainsText('*[data-id="stepdetail"]', 'vm trace step:\n51', 60000)
},
'Should step back and forward transaction': function (browser: NightwatchBrowser) {
'Should step back and forward transaction #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]')
.waitForElementPresent('*[data-id="buttonNavigatorIntoBack"]')
.scrollAndClick('*[data-id="buttonNavigatorIntoBack"]')
@ -61,7 +62,7 @@ module.exports = {
.waitForElementContainsText('*[data-id="stepdetail"]', 'execution step:\n51', 60000)
},
'Should jump through breakpoints': function (browser: NightwatchBrowser) {
'Should jump through breakpoints #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#editorView')
.execute(() => {
(window as any).addRemixBreakpoint(11)
@ -80,15 +81,17 @@ module.exports = {
.waitForElementContainsText('*[data-id="stepdetail"]', 'execution step:\n352', 60000)
},
'Should display solidity imported code while debugging github import': function (browser: NightwatchBrowser) {
'Should display solidity imported code while debugging github import #group2': function (browser: NightwatchBrowser) {
browser
.clearConsole()
.clearTransactions()
.clickLaunchIcon('solidity')
.testContracts('externalImport.sol', sources[1]['externalImport.sol'], ['ERC20'])
.clickLaunchIcon('udapp')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 35000)
.selectContract('ERC20')
.createContract('"tokenName", "symbol"')
.debugTransaction(2)
.debugTransaction(0)
.pause(2000)
.waitForElementVisible('#stepdetail')
.goToVMTraceStep(10)
@ -101,13 +104,14 @@ module.exports = {
})
},
'Should display correct source highlighting while debugging a contract which has ABIEncoderV2': function (browser: NightwatchBrowser) {
'Should display correct source highlighting while debugging a contract which has ABIEncoderV2 #group2': function (browser: NightwatchBrowser) {
/*
localVariable_step266_ABIEncoder and localVariable_step717_ABIEncoder
still contains unwanted values (related to decoding calldata types)
This is still an issue @todo(https://github.com/ethereum/remix-project/issues/481), so this test will fail when this issue is fixed
*/
browser
.clearConsole().clearTransactions()
.clickLaunchIcon('solidity')
.setSolidityCompilerVersion('soljson-v0.6.12+commit.27d51765.js')
.clickLaunchIcon('filePanel')
@ -116,9 +120,10 @@ module.exports = {
.clickLaunchIcon('udapp')
.selectContract('test')
.createContract('')
.clickInstance(2)
.clearConsole()
.clickInstance(0)
.clickFunction('test1 - transact (not payable)', { types: 'bytes userData', values: '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000015b38da6a701c568545dcfcb03fcb875f56beddc4' })
.debugTransaction(4)
.debugTransaction(0)
.pause(2000)
.waitForElementVisible('#stepdetail')
.goToVMTraceStep(261)
@ -138,11 +143,10 @@ module.exports = {
.goToVMTraceStep(717)
.pause(5000)
.checkVariableDebug('soliditylocals', localVariable_step717_ABIEncoder) // all locals should be initiaed
.clickLaunchIcon('udapp')
.clickInstance(2)
.clearTransactions()
},
'Should load more solidity locals array': function (browser: NightwatchBrowser) {
'Should load more solidity locals array #group3': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('solidity')
.testContracts('locals.sol', sources[3]['locals.sol'], ['testLocals'])
@ -150,32 +154,37 @@ module.exports = {
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 40000)
.createContract('')
.pause(2000)
.clickInstance(3)
.clearConsole()
.clickInstance(0)
.clickFunction('t - transact (not payable)')
.pause(2000)
.debugTransaction(6)
.waitForElementVisible('*[data-id="slider"]')
.debugTransaction(0)
.waitForElementVisible('*[data-id="slider"]').pause(2000)
// .setValue('*[data-id="slider"]', '5000') // Like this, setValue doesn't work properly for input type = range
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '7450' }) // It only moves slider to 7450 but vm traces are not updated
.execute(function () { document.getElementById('slider')['value'] = '7450' }).pause(10000) // It only moves slider to 7450 but vm traces are not updated
.setValue('*[data-id="slider"]', new Array(3).fill(browser.Keys.RIGHT_ARROW)) // This will press NEXT 3 times and will update the trace details
.waitForElementPresent('*[data-id="treeViewDivtreeViewItemarray"]')
.click('*[data-id="treeViewDivtreeViewItemarray"]')
.waitForElementPresent('*[data-id="treeViewDivtreeViewLoadMore"]')
.waitForElementVisible('*[data-id="solidityLocals"]')
.waitForElementContainsText('*[data-id="solidityLocals"]', '9: 9 uint256', 60000)
.notContainsText('*[data-id="solidityLocals"]', '10: 10 uint256')
.clearTransactions()
.clearConsole().pause(2000)
},
'Should debug using generated sources': function (browser: NightwatchBrowser) {
'Should debug using generated sources #group4': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('solidity')
.pause(2000)
.testContracts('withGeneratedSources.sol', sources[4]['withGeneratedSources.sol'], ['A'])
.clickLaunchIcon('udapp')
.createContract('')
.clickInstance(4)
.clearConsole()
.clickInstance(0)
.clickFunction('f - transact (not payable)', { types: 'uint256[] ', values: '[]' })
.debugTransaction(8)
.debugTransaction(0)
.pause(2000)
.click('*[data-id="debuggerTransactionStartButton"]') // stop debugging
.click('*[data-id="debugGeneratedSourcesLabel"]') // select debug with generated sources
@ -186,16 +195,16 @@ module.exports = {
})
.click('*[data-id="debuggerTransactionStartButton"]')
},
'Should call the debugger api: getTrace': function (browser: NightwatchBrowser) {
// depends on Should debug using generated sources
'Should call the debugger api: getTrace #group4': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsGetTrace.js', { content: jsGetTrace })
.executeScript('remix.exeCurrent()')
.pause(1000)
.pause(3000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '{"gas":"0x575f","return":"0x0000000000000000000000000000000000000000000000000000000000000000","structLogs":', 60000)
},
'Should call the debugger api: debug': function (browser: NightwatchBrowser) {
// depends on Should debug using generated sources
'Should call the debugger api: debug #group4': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsDebug.js', { content: jsDebug })
.executeScript('remix.exeCurrent()')
@ -214,7 +223,7 @@ module.exports = {
.waitForElementContainsText('*[data-id="stepdetail"]', 'vm trace step:\n154', 60000)
},
'Should start debugging using remix debug nodes (rinkeby)': '' + function (browser: NightwatchBrowser) {
'Should start debugging using remix debug nodes (rinkeby) #group4': '' + function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('solidity')
.setSolidityCompilerVersion('soljson-v0.8.7+commit.e28d00a7.js')
@ -428,7 +437,7 @@ const localVariable_step717_ABIEncoder = { // eslint-disable-line
const jsGetTrace = `(async () => {
try {
const result = await remix.call('debugger', 'getTrace', '0x9341be49e911afe99bf1abc67cbcf36739d2e6470a08a69511c205a0737d7332')
const result = await remix.call('debugger', 'getTrace', '0x16be5c31014a7e1552d136f7ed7bc7788f3bb9e45e31b059df253173f2df31e7')
console.log('result ', result)
} catch (e) {
console.log(e.message)
@ -437,7 +446,7 @@ const jsGetTrace = `(async () => {
const jsDebug = `(async () => {
try {
const result = await remix.call('debugger', 'debug', '0x9341be49e911afe99bf1abc67cbcf36739d2e6470a08a69511c205a0737d7332')
const result = await remix.call('debugger', 'debug', '0x16be5c31014a7e1552d136f7ed7bc7788f3bb9e45e31b059df253173f2df31e7')
console.log('result ', result)
} catch (e) {
console.log(e.message)

@ -3,11 +3,12 @@ import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'Should execute `file` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `file` api from file manager external api #group1': function (browser: NightwatchBrowser) {
browser
.addFile('file.js', { content: executeFile })
.executeScript('remix.exeCurrent()')
@ -15,7 +16,7 @@ module.exports = {
.waitForElementContainsText('*[data-id="terminalJournal"]', 'file.js', 60000)
},
'Should execute `exists` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `exists` api from file manager external api #group1': function (browser: NightwatchBrowser) {
browser
.addFile('exists.js', { content: executeExists })
.executeScript('remix.exeCurrent()')
@ -23,14 +24,14 @@ module.exports = {
.waitForElementContainsText('*[data-id="terminalJournal"]', 'non-exists.js false', 60000)
},
'Should execute `open` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `open` api from file manager external api #group1': function (browser: NightwatchBrowser) {
browser
.addFile('open.js', { content: executeOpen })
.executeScript('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'contracts/3_Ballot.sol', 60000)
},
'Should execute `writeFile` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `writeFile` api from file manager external api #group1': function (browser: NightwatchBrowser) {
browser
.addFile('writeFile.js', { content: executeWriteFile })
.executeScript('remix.exeCurrent()')
@ -41,21 +42,23 @@ module.exports = {
})
},
'Should execute `readFile` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `readFile` api from file manager external api #group2': function (browser: NightwatchBrowser) {
browser
.addFile('writeFile.js', { content: executeWriteFile })
.executeScript('remix.exeCurrent()')
.addFile('readFile.js', { content: executeReadFile })
.executeScript('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'pragma solidity ^0.6.0', 60000)
},
'Should execute `copyFile` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `copyFile` api from file manager external api #group2': function (browser: NightwatchBrowser) {
browser
.addFile('copyFile.js', { content: executeCopyFile })
.executeScript('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'pragma solidity >=0.7.0 <0.9.0;', 60000)
},
'Should execute `rename` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `rename` api from file manager external api #group2': function (browser: NightwatchBrowser) {
browser
.addFile('renameFile.js', { content: executeRename })
.executeScript('remix.exeCurrent()')
@ -63,7 +66,7 @@ module.exports = {
.waitForElementPresent('[data-id="treeViewLitreeViewItemold_contract.sol"]', 60000)
},
'Should execute `mkdir` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `mkdir` api from file manager external api #group3': function (browser: NightwatchBrowser) {
browser
.addFile('mkdirFile.js', { content: executeMkdir })
.executeScript('remix.exeCurrent()')
@ -71,7 +74,7 @@ module.exports = {
.waitForElementPresent('[data-id="treeViewLitreeViewItemTest_Folder"]', 60000)
},
'Should execute `readdir` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `readdir` api from file manager external api #group3': function (browser: NightwatchBrowser) {
browser
.addFile('readdirFile.js', { content: executeReaddir })
.executeScript('remix.exeCurrent()')
@ -79,8 +82,9 @@ module.exports = {
.waitForElementContainsText('*[data-id="terminalJournal"]', 'true', 5000)
},
'Should execute `remove` api from file manager external api': function (browser: NightwatchBrowser) {
'Should execute `remove` api from file manager external api #group4': function (browser: NightwatchBrowser) {
browser
.addFile('old_contract.sol', { content: 'test' })
.addFile('removeFile.js', { content: executeRemove })
.executeScript('remix.exeCurrent()')
.pause(2000)
@ -88,12 +92,12 @@ module.exports = {
},
// TODO: Fix remove root directory prefix for browser and localhost
'Should execute `remove` api from file manager external api on a folder': function (browser: NightwatchBrowser) {
'Should execute `remove` api from file manager external api on a folder #group4': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsRemoveFolder.js', { content: executeRemoveOnFolder })
.executeScript('remix.exeCurrent()')
.pause(2000)
.waitForElementNotPresent('[data-id="treeViewLitreeViewItemTest_Folder"]', 60000)
.waitForElementNotPresent('[data-id="treeViewLitreeViewItemcontracts"]', 60000)
.end()
}
}
@ -196,7 +200,7 @@ const executeRemove = `
const executeRemoveOnFolder = `(async () => {
try {
await remix.call('fileManager', 'remove', 'Test_Folder')
await remix.call('fileManager', 'remove', 'contracts')
} catch (e) {
console.log(e.message)
}

@ -147,7 +147,7 @@ const remixIdeThemes = {
},
light: {
primary: '#007aa6',
secondary: '#a8b3bc',
secondary: '#b3bcc483',
success: '#32ba89',
info: '#007aa6',
warning: '#c97539',

@ -72,7 +72,10 @@ module.exports = {
browser.clickLaunchIcon('home')
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('filePanel')
.scrollAndClick('*[data-id="landingPageImportFromGistButton"]')
.click('div[title="home"]')
.waitForElementVisible('button[data-id="landingPageImportFromGistButton"]')
.pause(1000)
.scrollAndClick('button[data-id="landingPageImportFromGistButton"]')
.waitForElementVisible('*[data-id="modalDialogModalTitle"]')
.assert.containsText('*[data-id="modalDialogModalTitle"]', 'Load a Gist')
.waitForElementVisible('*[data-id="modalDialogModalBody"]')

@ -10,7 +10,7 @@ declare global {
const localPluginData: Profile & LocationProfile & ExternalProfile = {
name: 'localPlugin',
displayName: 'Local Plugin',
canActivate: ['dGitProvider', 'flattener', 'solidityUnitTesting'],
canActivate: ['dGitProvider', 'flattener', 'solidityUnitTesting', 'udapp'],
url: 'http://localhost:2020',
location: 'sidePanel'
}
@ -127,8 +127,9 @@ const assertPluginIsActive = function (browser: NightwatchBrowser, id: string, s
}
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, 'http://127.0.0.1:8080', false)
init(browser, done) // , 'http://localhost:8080', false)
},
afterEach: function (browser: NightwatchBrowser) {
@ -144,13 +145,13 @@ module.exports = {
},
// UDAPP
'Should get accounts': async function (browser: NightwatchBrowser) {
'Should get accounts #group1': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'udapp:getAccounts', '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4', null, null)
},
// context menu item
'Should create context menu item': async function (browser: NightwatchBrowser) {
'Should create context menu item #group1': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:registerContextMenuItem', null, null, {
id: 'localPlugin',
name: 'testCommand',
@ -179,118 +180,118 @@ module.exports = {
// FILESYSTEM
'Should get current workspace': async function (browser: NightwatchBrowser) {
'Should get current workspace #group7': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:getCurrentWorkspace', { name: 'default_workspace', isLocalhost: false, absolutePath: '.workspaces/default_workspace' }, null, null)
},
'Should get current files': async function (browser: NightwatchBrowser) {
'Should get current files #group7': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:readdir', { contracts: { isDirectory: true }, scripts: { isDirectory: true }, tests: { isDirectory: true }, 'README.txt': { isDirectory: false } }, null, '/')
},
'Should throw error on current file': async function (browser: NightwatchBrowser) {
'Should throw error on current file #group7': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:getCurrentFile', 'Error from IDE : Error: No such file or directory No file selected', null, null)
},
'Should open readme.txt': async function (browser: NightwatchBrowser) {
'Should open readme.txt #group7': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:open', null, { event: 'currentFileChanged', args: ['README.txt'] }, 'README.txt')
},
'Should have current file': async function (browser: NightwatchBrowser) {
'Should have current file #group7': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:getCurrentFile', 'README.txt', null, null)
},
'Should create dir': async function (browser: NightwatchBrowser) {
'Should create dir #group7': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:mkdir', null, null, 'testdir')
await clickAndCheckLog(browser, 'fileManager:readdir', 'testdir', null, '/')
},
'Should get file': async function (browser: NightwatchBrowser) {
'Should get file #group7': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:getFile', 'REMIX EXAMPLE PROJECT', null, 'README.txt')
},
'Should close all files': async function (browser: NightwatchBrowser) {
'Should close all files #group7': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:closeAllFiles', null, { event: 'noFileSelected', args: [] }, null)
},
'Should switch to file': async function (browser: NightwatchBrowser) {
'Should switch to file #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:switchFile', null, { event: 'currentFileChanged', args: ['contracts/1_Storage.sol'] }, 'contracts/1_Storage.sol')
await clickAndCheckLog(browser, 'fileManager:getCurrentFile', 'contracts/1_Storage.sol', null, null)
await clickAndCheckLog(browser, 'fileManager:switchFile', null, { event: 'currentFileChanged', args: ['README.txt'] }, 'README.txt')
await clickAndCheckLog(browser, 'fileManager:getCurrentFile', 'README.txt', null, null)
},
'Should write to file': async function (browser: NightwatchBrowser) {
'Should write to file #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:writeFile', null, { event: 'fileSaved', args: ['README.txt'] }, ['README.txt', 'test'])
await clickAndCheckLog(browser, 'fileManager:readFile', 'test', null, 'README.txt')
},
'Should set file': async function (browser: NightwatchBrowser) {
'Should set file #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:setFile', null, { event: 'fileAdded', args: ['new.sol'] }, ['new.sol', 'test'])
await clickAndCheckLog(browser, 'fileManager:readFile', 'test', null, 'new.sol')
},
'Should write to new file': async function (browser: NightwatchBrowser) {
'Should write to new file #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:writeFile', null, { event: 'fileAdded', args: ['testing.txt'] }, ['testing.txt', 'test'])
await clickAndCheckLog(browser, 'fileManager:readFile', 'test', null, 'testing.txt')
},
'Should rename file': async function (browser: NightwatchBrowser) {
'Should rename file #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:rename', null, null, ['testing.txt', 'testrename.txt'])
await clickAndCheckLog(browser, 'fileManager:readFile', 'test', null, 'testrename.txt')
},
'Should create empty workspace': async function (browser: NightwatchBrowser) {
'Should create empty workspace #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, null, ['emptyworkspace', true])
await clickAndCheckLog(browser, 'filePanel:getCurrentWorkspace', { name: 'emptyworkspace', isLocalhost: false, absolutePath: '.workspaces/emptyworkspace' }, null, null)
await clickAndCheckLog(browser, 'fileManager:readdir', {}, null, '/')
},
'Should create workspace': async function (browser: NightwatchBrowser) {
'Should create workspace #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, null, 'testspace')
await clickAndCheckLog(browser, 'filePanel:getCurrentWorkspace', { name: 'testspace', isLocalhost: false, absolutePath: '.workspaces/testspace' }, null, null)
await clickAndCheckLog(browser, 'fileManager:readdir', { contracts: { isDirectory: true }, scripts: { isDirectory: true }, tests: { isDirectory: true }, 'README.txt': { isDirectory: false } }, null, null)
},
'Should get all workspaces': async function (browser: NightwatchBrowser) {
'Should get all workspaces #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:getWorkspaces', ['default_workspace', 'emptyworkspace', 'testspace'], null, null)
},
'Should have set workspace event': async function (browser: NightwatchBrowser) {
'Should have set workspace event #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, { event: 'setWorkspace', args: [{ name: 'newspace', isLocalhost: false }] }, 'newspace')
},
'Should have event when switching workspace': async function (browser: NightwatchBrowser) {
'Should have event when switching workspace #group2': async function (browser: NightwatchBrowser) {
// @ts-ignore
browser.frameParent().useCss().clickLaunchIcon('filePanel').click('*[data-id="workspacesSelect"] option[value="default_workspace"]').useXpath().click('//*[@data-id="verticalIconsKindlocalPlugin"]').frame(0, async () => {
await clickAndCheckLog(browser, null, null, { event: 'setWorkspace', args: [{ name: 'default_workspace', isLocalhost: false }] }, null)
})
},
'Should rename workspace': async function (browser: NightwatchBrowser) {
'Should rename workspace #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:renameWorkspace', null, null, ['default_workspace', 'renamed'])
await clickAndCheckLog(browser, 'filePanel:getWorkspaces', ['emptyworkspace', 'testspace', 'newspace', 'renamed'], null, null)
},
'Should delete workspace': async function (browser: NightwatchBrowser) {
'Should delete workspace #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:deleteWorkspace', null, null, ['testspace'])
await clickAndCheckLog(browser, 'filePanel:getWorkspaces', ['emptyworkspace', 'newspace', 'renamed'], null, null)
},
// DGIT
'Should have changes on new workspace': async function (browser: NightwatchBrowser) {
'Should have changes on new workspace #group3': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, null, 'dgit')
await clickAndCheckLog(browser, 'dGitProvider:status', [['README.txt', 0, 2, 0], ['contracts/1_Storage.sol', 0, 2, 0], ['contracts/2_Owner.sol', 0, 2, 0], ['contracts/3_Ballot.sol', 0, 2, 0], ['scripts/deploy_ethers.js', 0, 2, 0], ['scripts/deploy_web3.js', 0, 2, 0], ['tests/4_Ballot_test.sol', 0, 2, 0]], null, null)
},
'Should stage contract': async function (browser: NightwatchBrowser) {
'Should stage contract #group3': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'dGitProvider:add', null, null, {
filepath: 'contracts/1_Storage.sol'
})
await clickAndCheckLog(browser, 'dGitProvider:status', [['README.txt', 0, 2, 0], ['contracts/1_Storage.sol', 0, 2, 2], ['contracts/2_Owner.sol', 0, 2, 0], ['contracts/3_Ballot.sol', 0, 2, 0], ['scripts/deploy_ethers.js', 0, 2, 0], ['scripts/deploy_web3.js', 0, 2, 0], ['tests/4_Ballot_test.sol', 0, 2, 0]], null, null)
},
'Should commit changes': async function (browser: NightwatchBrowser) {
'Should commit changes #group3': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'dGitProvider:commit', null, null, { author: { name: 'Remix', email: 'Remix' }, message: 'commit-message' })
await clickAndCheckLog(browser, 'dGitProvider:log', 'commit-message', null, null)
},
'Should have git log': async function (browser: NightwatchBrowser) {
'Should have git log #group3': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'dGitProvider:log', 'commit-message', null, null)
},
'Should have branches': async function (browser: NightwatchBrowser) {
'Should have branches #group3': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'dGitProvider:branches', [{ name: 'main' }], null, null)
},
// resolver
'Should resolve url': async function (browser: NightwatchBrowser) {
'Should resolve url #group4': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'contentImport:resolve', '# Remix Project', null, 'https://github.com/ethereum/remix-project/blob/master/README.md')
},
'Should resolve and save url': async function (browser: NightwatchBrowser) {
'Should resolve and save url #group4': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'contentImport:resolveAndSave', '# Remix Project', { event: 'fileAdded', args: ['.deps/github/ethereum/remix-project/README.md'] }, 'https://github.com/ethereum/remix-project/blob/master/README.md')
},
// UNIT TESTING
'Should activate solidityUnitTesting': async function (browser: NightwatchBrowser) {
'Should activate solidityUnitTesting #group5': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'manager:activatePlugin', null, null, 'solidityUnitTesting')
browser.frameParent()
assertPluginIsActive(browser, 'solidityUnitTesting', true)
@ -299,11 +300,11 @@ module.exports = {
await clickAndCheckLog(browser, 'manager:isActive', true, null, 'solidityUnitTesting')
},
'Should test from path with solidityUnitTesting': async function (browser: NightwatchBrowser) {
'Should test from path with solidityUnitTesting #group5': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'solidityUnitTesting:testFromPath', '"totalPassing":2,"totalFailing":0', null, 'tests/4_Ballot_test.sol')
},
'Should deactivate solidityUnitTesting': async function (browser: NightwatchBrowser) {
'Should deactivate solidityUnitTesting #group5': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'manager:deactivatePlugin', null, null, 'solidityUnitTesting')
browser.frameParent()
assertPluginIsActive(browser, 'solidityUnitTesting', false)
@ -314,14 +315,14 @@ module.exports = {
// COMPILER
'Should compile a file': async function (browser: NightwatchBrowser) {
'Should compile a file #group6': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'solidity:compile', null, null, 'contracts/1_Storage.sol')
browser.pause(5000, async () => {
await clickAndCheckLog(browser, 'solidity:compile', null, 'compilationFinished', null)
})
},
'Should get compilationresults': async function (browser: NightwatchBrowser) {
'Should get compilationresults #group6': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'solidity:getCompilationResult', 'contracts/1_Storage.sol', null, null)
}
}

@ -45,6 +45,7 @@ const sources = [
]
module.exports = {
'@disabled': true,
before: function (browser, done) {
init(browser, done)
},
@ -52,25 +53,27 @@ module.exports = {
'@sources': function () {
return sources
},
Remixd: function (browser) {
'start Remixd': function (browser) {
startRemixd(browser)
},
'run Remixd tests #group4': function (browser) {
runTests(browser)
},
'Import from node_modules ': function (browser) {
'Import from node_modules #group1': function (browser) {
/*
when a relative import is used (i.e import "openzeppelin-solidity/contracts/math/SafeMath.sol")
remix (as well as truffle) try to resolve it against the node_modules and installed_contracts folder.
*/
browser.waitForElementVisible('#icon-panel', 2000)
// .clickLaunchIcon('filePanel')
.clickLaunchIcon('filePanel')
.click('[data-path="ballot.sol"]')
.addFile('test_import_node_modules.sol', sources[3]['test_import_node_modules.sol'])
.clickLaunchIcon('solidity')
.setSolidityCompilerVersion('soljson-v0.5.0+commit.1d4f565a.js')
.testContracts('test_import_node_modules.sol', sources[3]['test_import_node_modules.sol'], ['SafeMath'])
},
'Import from node_modules and reference a github import': function (browser) {
'Import from node_modules and reference a github import #group2': function (browser) {
browser.waitForElementVisible('#icon-panel', 2000)
.clickLaunchIcon('filePanel')
.addFile('test_import_node_modules_with_github_import.sol', sources[4]['test_import_node_modules_with_github_import.sol'])
@ -78,7 +81,7 @@ module.exports = {
.setSolidityCompilerVersion('soljson-v0.8.0+commit.c7dfd78e.js') // open-zeppelin moved to pragma ^0.8.0
.testContracts('test_import_node_modules_with_github_import.sol', sources[4]['test_import_node_modules_with_github_import.sol'], ['ERC20', 'test11'])
},
'Static Analysis run with remixd': function (browser) {
'Static Analysis run with remixd #group3': function (browser) {
browser.testContracts('test_static_analysis_with_remixd_and_hardhat.sol', sources[5]['test_static_analysis_with_remixd_and_hardhat.sol'], ['test5'])
.clickLaunchIcon('solidityStaticAnalysis')
.click('#staticanalysisButton button')
@ -101,7 +104,7 @@ module.exports = {
.journalLastChildIncludes('On branch ')
},
'Close Remixd': function (browser) {
'Close Remixd #group3': function (browser) {
browser
.clickLaunchIcon('pluginManager')
.scrollAndClick('#pluginManager *[data-id="pluginManagerComponentDeactivateButtonremixd"]')
@ -109,7 +112,7 @@ module.exports = {
}
}
function runTests (browser: NightwatchBrowser) {
function startRemixd (browser: NightwatchBrowser) {
const browserName = browser.options.desiredCapabilities.browserName
if (browserName === 'safari' || browserName === 'internet explorer') {
console.log('do not run remixd test for ' + browserName + ': sauce labs doesn\'t seems to handle websocket')
@ -126,7 +129,11 @@ function runTests (browser: NightwatchBrowser) {
.pause(2000)
.click('#modal-footer-ok')
// .click('*[data-id="workspacesModalDialog-modal-footer-ok-react"]')
.clickLaunchIcon('filePanel')
}
function runTests (browser: NightwatchBrowser) {
const browserName = browser.options.desiredCapabilities.browserName
browser.clickLaunchIcon('filePanel')
.waitForElementVisible('[data-path="folder1"]')
.click('[data-path="folder1"]')
.waitForElementVisible('[data-path="contract1.sol"]')

@ -6,7 +6,7 @@ const passphrase = process.env.account_passphrase
const password = process.env.account_password
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
@ -15,14 +15,14 @@ module.exports = {
return sources
},
'Should load run and deploy tab': function (browser: NightwatchBrowser) {
'Should load run and deploy tab #group1 #group2': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="sidePanelSwapitTitle"]')
.assert.containsText('*[data-id="sidePanelSwapitTitle"]', 'DEPLOY & RUN TRANSACTIONS')
},
'Should load run and deploy tab and check value validation': function (browser: NightwatchBrowser) {
'Should load run and deploy tab and check value validation #group1': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.assert.containsText('*[data-id="sidePanelSwapitTitle"]', 'DEPLOY & RUN TRANSACTIONS')
.validateValueInput('#value', '0000', '0')
@ -30,30 +30,31 @@ module.exports = {
.validateValueInput('#value', 'dragon', '0')
},
'Should sign message using account key': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="settingsRemixRunSignMsg"]')
'Should sign message using account key #group2': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="settingsRemixRunSignMsg"]')
.click('select[id="selectExEnvOptions"] option[value="vm-berlin"]')
.pause(2000)
.click('*[data-id="settingsRemixRunSignMsg"]')
.pause(2000)
.waitForElementPresent('*[data-id="modalDialogCustomPromptText"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptText"]', 120000)
.setValue('*[data-id="modalDialogCustomPromptText"]', 'Remix is cool!')
.assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgHash"]')
.assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgSignature"]')
.pause(2000)
.modalFooterOKClick()
.waitForElementPresent('*[data-id="modalDialogContainer"]', 12000)
.waitForElementVisible('*[data-id="modalDialogContainer"]', 12000)
.assert.elementPresent('*[data-id="settingsRemixRunSignMsgHash"]')
.assert.elementPresent('*[data-id="settingsRemixRunSignMsgSignature"]')
.modalFooterOKClick()
},
'Should deploy contract on JavascriptVM': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
'Should deploy contract on JavascriptVM #group3': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]')
.clickLaunchIcon('filePanel')
.addFile('Greet.sol', sources[0]['Greet.sol'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c')
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]', 45000)
.waitForElementVisible('*[data-id="Deploy - transact (not payable)"]', 45000)
.click('*[data-id="Deploy - transact (not payable)"]')
.pause(5000)
.testFunction('last', {
@ -61,7 +62,7 @@ module.exports = {
})
},
'Should run low level interaction (fallback function)': function (browser: NightwatchBrowser) {
'Should run low level interaction (fallback function) #group3': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.waitForElementPresent('*[data-id="universalDappUiTitleExpander"]')
.click('*[data-id="universalDappUiTitleExpander"]')

@ -3,6 +3,7 @@ import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
@ -11,11 +12,11 @@ module.exports = {
return sources
},
'Test Simple Contract': function (browser: NightwatchBrowser) {
'Test Simple Contract #group1': function (browser: NightwatchBrowser) {
browser.testContracts('Untitled.sol', sources[0]['Untitled.sol'], ['test1', 'test2'])
},
'Test Success Import': function (browser: NightwatchBrowser) {
'Test Success Import #group1': function (browser: NightwatchBrowser) {
browser.addFile('Untitled1.sol', sources[1]['Untitled1.sol'])
.addFile('Untitled2.sol', sources[1]['Untitled2.sol'])
.openFile('Untitled1.sol')
@ -23,13 +24,13 @@ module.exports = {
.pause(1000)
},
'Test Failed Import': function (browser: NightwatchBrowser) {
'Test Failed Import #group1': function (browser: NightwatchBrowser) {
browser.addFile('Untitled3.sol', sources[2]['Untitled3.sol'])
.clickLaunchIcon('solidity')
.assert.containsText('#compileTabView .error pre', 'not found Untitled11.sol')
},
'Test Github Import - from master branch': function (browser: NightwatchBrowser) {
'Test Github Import - from master branch #group1': function (browser: NightwatchBrowser) {
browser
.setSolidityCompilerVersion('soljson-v0.8.0+commit.c7dfd78e.js') // open-zeppelin moved to pragma ^0.8.0 (master branch)
.addFile('Untitled4.sol', sources[3]['Untitled4.sol'])
@ -37,7 +38,7 @@ module.exports = {
.verifyContracts(['test7', 'ERC20'], { wait: 10000 })
},
'Test Github Import - from other branch': function (browser: NightwatchBrowser) {
'Test Github Import - from other branch #group2': function (browser: NightwatchBrowser) {
browser
.setSolidityCompilerVersion('soljson-v0.5.0+commit.1d4f565a.js') // switch back to 0.5.0 : release-v2.3.0 branch is not solidity 0.6 compliant
.addFile('Untitled5.sol', sources[4]['Untitled5.sol'])
@ -45,7 +46,7 @@ module.exports = {
.verifyContracts(['test8', 'ERC20', 'SafeMath'], { wait: 10000 })
},
'Test Github Import - no branch specified': function (browser: NightwatchBrowser) {
'Test Github Import - no branch specified #group2': function (browser: NightwatchBrowser) {
browser
.setSolidityCompilerVersion('soljson-v0.8.0+commit.c7dfd78e.js') // open-zeppelin moved to pragma ^0.8.0 (master branch)
.clickLaunchIcon('filePanel')
@ -55,7 +56,7 @@ module.exports = {
.verifyContracts(['test10', 'ERC20'], { wait: 10000 })
},
'Test Github Import - raw URL': function (browser: NightwatchBrowser) {
'Test Github Import - raw URL #group4': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('filePanel')
.click('li[data-id="treeViewLitreeViewItemREADME.txt"')
@ -64,7 +65,7 @@ module.exports = {
.verifyContracts(['test11', 'ERC20'], { wait: 10000 })
},
'Test switch to a github import from a solidity warning': function (browser: NightwatchBrowser) {
'Test switch to a github import from a solidity warning #group3': function (browser: NightwatchBrowser) {
browser
.setSolidityCompilerVersion('soljson-v0.7.4+commit.3f05b770.js')
.clickLaunchIcon('filePanel')
@ -80,7 +81,7 @@ module.exports = {
})
},
'Test NPM Import (with unpkg.com)': function (browser: NightwatchBrowser) {
'Test NPM Import (with unpkg.com) #group3': function (browser: NightwatchBrowser) {
browser
.setSolidityCompilerVersion('soljson-v0.8.7+commit.e28d00a7.js')
.clickLaunchIcon('filePanel')

@ -0,0 +1,6 @@
'use strict'
import * as test from './solidityImport.test'
import buildGroupTest from '../helpers/buildgrouptest'
const group = 'group1'
module.exports = buildGroupTest(group, test)

@ -4,7 +4,7 @@ import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done) {
init(browser, done)
},
@ -12,18 +12,24 @@ module.exports = {
'@sources': function () {
return sources
},
'Should launch solidity unit test plugin and create test files in FE': function (browser: NightwatchBrowser) {
'open SUT plugin': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.clickLaunchIcon('filePanel')
.addFile('simple_storage.sol', sources[0]['simple_storage.sol'])
.addFile('ks2a.sol', sources[0]['ks2a.sol'])
.clickLaunchIcon('pluginManager')
.scrollAndClick('*[data-id="pluginManagerComponentActivateButtonsolidityUnitTesting"]')
.click('*[data-id="verticalIconsKindsolidityUnitTesting"]')
.waitForElementPresent('*[data-id="sidePanelSwapitTitle"]')
.assert.containsText('*[data-id="sidePanelSwapitTitle"]', 'SOLIDITY UNIT TESTING')
.clickLaunchIcon('filePanel')
.waitForElementPresent('[data-id="treeViewDivtreeViewItemtests"]')
.click('[data-id="treeViewDivtreeViewItemtests"]')
.clickLaunchIcon('pluginManager')
},
'Should launch solidity unit test plugin and create test files in FE #group1 #group2': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.clickLaunchIcon('filePanel')
.addFile('simple_storage.sol', sources[0]['simple_storage.sol'])
.addFile('ks2a.sol', sources[0]['ks2a.sol'])
.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')
@ -34,22 +40,19 @@ module.exports = {
.getEditorValue((content) => browser.assert.ok(content.indexOf('library TestsAccounts {') !== -1))
},
'Should generate test file': function (browser: NightwatchBrowser) {
'Should generate test file #group1': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.clickLaunchIcon('filePanel')
.openFile('simple_storage.sol')
.click('*[data-id="verticalIconsKindsolidityUnitTesting"]')
.waitForElementPresent('*[data-id="testTabGenerateTestFile"]')
.click('*[data-id="testTabGenerateTestFile"]')
.waitForElementPresent('*[title="default_workspace/tests/simple_storage_test.sol"]')
.clickLaunchIcon('filePanel')
.waitForElementPresent('[data-id="treeViewDivtreeViewItemtests"]')
.click('[data-id="treeViewDivtreeViewItemtests"]')
.openFile('tests/simple_storage_test.sol')
.waitForElementPresent('*[title="default_workspace/tests/simple_storage_test.sol"]')
.removeFile('tests/simple_storage_test.sol', 'default_workspace')
},
'Should run simple unit test `simple_storage_test.sol` ': function (browser: NightwatchBrowser) {
'Should run simple unit test `simple_storage_test.sol` #group1': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/simple_storage_test.sol', sources[0]['tests/simple_storage_test.sol'])
.click('*[data-id="verticalIconsKindsolidityUnitTesting"]')
@ -66,14 +69,14 @@ module.exports = {
.waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'FAIL MyTest (tests/simple_storage_test.sol)', 120000)
},
'Should run advance unit test using natspec and experimental ABIEncoderV2 `ks2b_test.sol` ': function (browser: NightwatchBrowser) {
'Should run advance unit test using natspec and experimental ABIEncoderV2 `ks2b_test.sol` #group2': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.clickLaunchIcon('filePanel')
.addFile('tests/ks2b_test.sol', sources[0]['tests/ks2b_test.sol'])
.click('*[data-id="verticalIconsKindsolidityUnitTesting"]')
.waitForElementPresent('*[data-id="testTabCheckAllTests"]')
.click('*[data-id="testTabCheckAllTests"]')
.clickElementAtPosition('.singleTestLabel', 2)
.clickElementAtPosition('.singleTestLabel', 1)
.scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]')
.waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'tests/ks2b_test.sol', 120000)
.waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '✓ Check project exists', 120000)
@ -86,11 +89,10 @@ module.exports = {
.waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'wrong value', 120000)
},
'Should stop unit tests during test execution` ': function (browser: NightwatchBrowser) {
'Should stop unit tests during test execution` #group2': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.waitForElementPresent('*[data-id="testTabRunTestsTabRunAction"]')
.clickElementAtPosition('.singleTestLabel', 0)
.clickElementAtPosition('.singleTestLabel', 1)
.scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]')
.pause(2000)
.click('*[data-id="testTabRunTestsTabStopAction"]')
@ -100,14 +102,15 @@ module.exports = {
.waitForElementContainsText('*[data-id="testTabTestsExecutionStopped"]', 'The test execution has been stopped', 60000)
},
'Should fail on compilation, open file on error click, not disappear error': function (browser: NightwatchBrowser) {
'Should fail on compilation, open file on error click, not disappear error #group2': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/compilationError_test.sol', sources[0]['compilationError_test.sol'])
.click('div[title="default_workspace/tests/compilationError_test.sol"] span[class="close-tabs"]')
.clickLaunchIcon('solidityUnitTesting')
.pause(2000)
.click('*[data-id="testTabCheckAllTests"]')
.clickElementAtPosition('.singleTestLabel', 3)
// .click('#singleTesttests/compilationError_test.sol')
.clickElementAtPosition('.singleTestLabel', 2)
.scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]')
.waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'SyntaxError: No visibility specified', 120000)
.waitForElementContainsText('*[data-id="testTabTestsExecutionStoppedError"]', 'The test execution has been stopped because of error(s) in your test file', 120000)
@ -119,31 +122,31 @@ module.exports = {
.verify.elementPresent('#solidityUnittestsOutput *[data-id="tests/compilationError_test.sol"]')
},
'Should fail on deploy': function (browser: NightwatchBrowser) {
'Should fail on deploy #group3': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/deployError_test.sol', sources[0]['tests/deployError_test.sol'])
.clickLaunchIcon('filePanel')
.openFile('tests/deployError_test.sol')
.clickLaunchIcon('solidityUnitTesting')
.click('*[data-id="testTabCheckAllTests"]')
.clickElementAtPosition('.singleTestLabel', 4)
.clickElementAtPosition('.singleTestLabel', 1)
.scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]')
.waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'contract deployment failed after trying twice', 120000)
},
'Should fail when parameters are passed to method in test contract': function (browser: NightwatchBrowser) {
'Should fail when parameters are passed to method in test contract #group3': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/methodFailure_test.sol', sources[0]['tests/methodFailure_test.sol'])
.clickLaunchIcon('filePanel')
.openFile('tests/methodFailure_test.sol')
.clickLaunchIcon('solidityUnitTesting')
.click('*[data-id="testTabCheckAllTests"]')
.clickElementAtPosition('.singleTestLabel', 5)
.clickElementAtPosition('.singleTestLabel', 2)
.scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]')
.waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'Method \'add\' can not have parameters inside a test contract', 120000)
},
'Changing current path': function (browser: NightwatchBrowser) {
'Changing current path #group3': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('myTests/simple_storage_test.sol', sources[0]['tests/simple_storage_test.sol'])
@ -159,7 +162,7 @@ module.exports = {
.click('*[data-id="testTabGenerateTestFolder"]')
},
'Changing current path when workspace changed and checking test files creation': function (browser: NightwatchBrowser) {
'Changing current path when workspace changed and checking test files creation #group4': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.clickLaunchIcon('settings')
@ -191,7 +194,7 @@ module.exports = {
.verify.attributeEquals('*[data-id="uiPathInput"]', 'value', 'tests')
},
'Solidity Unit tests Basic': function (browser: NightwatchBrowser) {
'Solidity Unit tests Basic #group4': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.clickLaunchIcon('filePanel')
@ -209,7 +212,7 @@ module.exports = {
.waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winnin proposal with return value', 60000)
},
'Solidity Unit tests with hardhat console log': function (browser: NightwatchBrowser) {
'Solidity Unit tests with hardhat console log #group4': function (browser: NightwatchBrowser) {
const runtimeBrowser = browser.options.desiredCapabilities.browserName
browser
@ -241,7 +244,7 @@ module.exports = {
.removeFile('tests/hhLogs_test.sol', 'workspace_new')
},
'Solidity Unit tests with hardhat console log for EVM revert': function (browser: NightwatchBrowser) {
'Solidity Unit tests with hardhat console log for EVM revert #group5': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/ballotFailedLog_test.sol', sources[0]['tests/ballotFailedLog_test.sol'])
@ -252,13 +255,13 @@ module.exports = {
.pause(2000)
.waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000)
.waitForElementContainsText('#solidityUnittestsOutput', 'tests/ballotFailedLog_test.sol', 60000)
.assert.containsText('#journal > div:nth-child(5) > span', 'Check winning proposal:')
.assert.containsText('#journal > div:nth-child(5) > span', 'Inside checkWinningProposal')
.assert.containsText('#journal', 'Check winning proposal:')
.assert.containsText('#journal', 'Inside checkWinningProposal')
.openFile('tests/ballotFailedLog_test.sol')
.removeFile('tests/ballotFailedLog_test.sol', 'workspace_new')
},
'Debug tests using debugger': function (browser: NightwatchBrowser) {
'Debug tests using debugger #group5': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/ballotFailedDebug_test.sol', sources[0]['tests/ballotFailedDebug_test.sol'])
@ -275,6 +278,7 @@ module.exports = {
.click('#Check_winning_proposal_failed')
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalFailed()', 60000)
.waitForElementVisible('*[data-id="dropdownPanelSolidityLocals"]').pause(1000)
.click('*[data-id="dropdownPanelSolidityLocals"]')
.waitForElementContainsText('*[data-id="solidityLocals"]', 'no locals', 60000)
// eslint-disable-next-line dot-notation
@ -320,10 +324,12 @@ module.exports = {
.removeFile('tests/ballotFailedDebug_test.sol', 'workspace_new')
},
'Basic Solidity Unit tests with local compiler': function (browser: NightwatchBrowser) {
'Basic Solidity Unit tests with local compiler #group6': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('solidity')
.setSolidityCompilerVersion('builtin')
.clickLaunchIcon('filePanel')
.click('*[data-id="treeViewLitreeViewItemcontracts"]')
.openFile('contracts/3_Ballot.sol')
.clickLaunchIcon('pluginManager')
.scrollAndClick('[data-id="pluginManagerComponentDeactivateButtonsolidityUnitTesting"]')

@ -3,6 +3,7 @@ import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
// this test suite also contribute testing https://github.com/ethereum/remix/pull/1497 and https://github.com/ethereum/remix-ide/pull/2898
// quick explanation:
@ -17,7 +18,7 @@ module.exports = {
return sources
},
'Use special functions receive/fallback - both are declared, sending data': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - both are declared, sending data #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('receiveAndFallback.sol', sources[0]['receiveAndFallback.sol'], ['CheckSpecials']) // compile
.clickLaunchIcon('udapp')
@ -37,7 +38,7 @@ module.exports = {
})
},
'Use special functions receive/fallback - both are declared, failing sending data < 1 byte': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - both are declared, failing sending data < 1 byte #group1': function (browser: NightwatchBrowser) {
// don't need to redeploy it, same contract
browser.perform((done) => {
browser.getAddressAtPosition(0, (address) => {
@ -49,7 +50,7 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - both are declared, failing sending data with odd number of digits': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - both are declared, failing sending data with odd number of digits #group1': function (browser: NightwatchBrowser) {
// don't need to redeploy it, same contract
browser.perform((done) => {
browser.getAddressAtPosition(0, (address) => {
@ -61,7 +62,7 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - both are declared - receive called, sending wei': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - both are declared - receive called, sending wei #group1': function (browser: NightwatchBrowser) {
// don't need to redeploy it, same contract
browser.perform((done) => {
browser.getAddressAtPosition(0, (address) => {
@ -74,7 +75,7 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - both are declared - fallback should fail cause not payable, sending data and wei': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - both are declared - fallback should fail cause not payable, sending data and wei #group1': function (browser: NightwatchBrowser) {
// don't need to redeploy it, same contract
browser.perform((done) => {
browser.getAddressAtPosition(0, (address) => {
@ -86,15 +87,15 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - only receive is declared, sending wei': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - only receive is declared, sending wei #group2': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('receiveOnly.sol', sources[1]['receiveOnly.sol'], ['CheckSpecials'])
.clickLaunchIcon('udapp')
.selectContract('CheckSpecials')
.createContract('')
.clickInstance(1)
.clickInstance(0)
.perform((done) => {
browser.getAddressAtPosition(1, (address) => {
browser.getAddressAtPosition(0, (address) => {
browser.sendLowLevelTx(address, '1', '')
.pause(1000)
.journalLastChildIncludes('to: CheckSpecials.(receive)')
@ -104,10 +105,10 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - only receive is declared, failing, fallback is not declared, sending data': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - only receive is declared, failing, fallback is not declared, sending data #group2': function (browser: NightwatchBrowser) {
// don't need to redeploy it, same contract
browser.perform((done) => {
browser.getAddressAtPosition(1, (address) => {
browser.getAddressAtPosition(0, (address) => {
browser.sendLowLevelTx(address, '0', '0xaa')
.pause(1000)
.waitForElementVisible(`#instance${address} label[id="deployAndRunLLTxError"]`)
@ -116,15 +117,15 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - only fallback declared and is payable, sending wei': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - only fallback declared and is payable, sending wei #group3': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('fallbackOnlyPayable.sol', sources[2]['fallbackOnlyPayable.sol'], ['CheckSpecials'])
.clickLaunchIcon('udapp')
.selectContract('CheckSpecials')
.createContract('')
.clickInstance(2)
.clickInstance(0)
.perform((done) => {
browser.getAddressAtPosition(2, (address) => {
browser.getAddressAtPosition(0, (address) => {
browser.sendLowLevelTx(address, '1', '')
.pause(1000)
.journalLastChildIncludes('to: CheckSpecials.(fallback)')
@ -134,10 +135,10 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - only fallback is diclared and is payable, sending data and wei': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - only fallback is diclared and is payable, sending data and wei #group3': function (browser: NightwatchBrowser) {
// don't need to redeploy it, same contract
browser.perform((done) => {
browser.getAddressAtPosition(2, (address) => {
browser.getAddressAtPosition(0, (address) => {
browser.sendLowLevelTx(address, '1', '0xaa')
.pause(1000)
.journalLastChildIncludes('to: CheckSpecials.(fallback)')
@ -147,15 +148,15 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - only fallback is declared, fallback should fail cause not payable, sending wei': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - only fallback is declared, fallback should fail cause not payable, sending wei #group4': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('fallbackOnlyNotPayable.sol', sources[3]['fallbackOnlyNotPayable.sol'], ['CheckSpecials'])
.clickLaunchIcon('udapp')
.selectContract('CheckSpecials')
.createContract('')
.clickInstance(3)
.clickInstance(0)
.perform((done) => {
browser.getAddressAtPosition(3, (address) => {
browser.getAddressAtPosition(0, (address) => {
browser.sendLowLevelTx(address, '1', '')
.pause(1000)
.waitForElementVisible(`#instance${address} label[id="deployAndRunLLTxError"]`)
@ -164,7 +165,7 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - receive and fallback are declared, sending data and wei': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - receive and fallback are declared, sending data and wei #group4': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('receiveAndFallbackBothPayable.sol', sources[4]['receiveAndFallbackBothPayable.sol'], ['CheckSpecials'])
.clickLaunchIcon('udapp')
@ -173,10 +174,10 @@ module.exports = {
.clearValue('#value')
.setValue('#value', '0')
.createContract('')
.clickInstance(4)
.clickInstance(1)
.pause(1000)
.perform((done) => {
browser.getAddressAtPosition(4, (address) => {
browser.getAddressAtPosition(1, (address) => {
browser.sendLowLevelTx(address, '999999998765257135', '0xaa')
.pause(1000)
.journalLastChildIncludes('to: CheckSpecials.(fallback)')
@ -186,9 +187,9 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - receive and fallback are declared and payable, sending wei': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - receive and fallback are declared and payable, sending wei #group4': function (browser: NightwatchBrowser) {
browser.perform((done) => {
browser.getAddressAtPosition(4, (address) => {
browser.getAddressAtPosition(1, (address) => {
browser.sendLowLevelTx(address, '1', '')
.pause(1000)
.journalLastChildIncludes('to: CheckSpecials.(receive)')
@ -198,7 +199,7 @@ module.exports = {
})
})
},
'Use special functions receive/fallback - receive and fallback are not declared, sending nothing': function (browser: NightwatchBrowser) {
'Use special functions receive/fallback - receive and fallback are not declared, sending nothing #group5': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('notSpecial.sol', sources[5]['notSpecial.sol'], ['CheckSpecials'])
.clickLaunchIcon('udapp')
@ -207,10 +208,10 @@ module.exports = {
.clearValue('#value')
.setValue('#value', '0')
.createContract('')
.clickInstance(5)
.clickInstance(0)
.pause(1000)
.perform((done) => {
browser.getAddressAtPosition(5, (address) => {
browser.getAddressAtPosition(0, (address) => {
browser.sendLowLevelTx(address, '0', '')
.pause(1000)
.waitForElementVisible(`#instance${address} label[id="deployAndRunLLTxError"]`)

@ -3,11 +3,12 @@ import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, 'http://127.0.0.1:8080?plugins=solidity,udapp', false)
},
'Should execution a simple console command': function (browser: NightwatchBrowser) {
'Should execution a simple console command #group1 #group999': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="terminalCli"]', 10000)
.executeScript('console.log(1 + 1)')
@ -15,7 +16,7 @@ module.exports = {
.waitForElementContainsText('*[data-id="terminalJournal"]', '2', 60000)
},
'Should clear console': function (browser: NightwatchBrowser) {
'Should clear console #group1': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="terminalCli"]')
.journalChildIncludes('Welcome to Remix')
@ -23,40 +24,29 @@ module.exports = {
.waitForElementContainsText('*[data-id="terminalJournal"]', '', 60000)
},
'Should display auto-complete menu': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="terminalCli"]')
.click('*[data-id="terminalCli"]')
.sendKeys('*[data-id="terminalCliInput"]', 'remix.')
.assert.visible('*[data-id="autoCompletePopUpAutoCompleteItem"]')
},
'Async/Await Script': function (browser: NightwatchBrowser) {
'Async/Await Script #group1': function (browser: NightwatchBrowser) {
browser
.addFile('asyncAwait.js', { content: asyncAwait })
.openFile('asyncAwait.js')
.executeScript('remix.execute("asyncAwait.js")')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Waiting Promise', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'result - ', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Promise Resolved', 60000)
},
'Call Remix File Manager from a script': function (browser: NightwatchBrowser) {
'Call Remix File Manager from a script #group2': function (browser: NightwatchBrowser) {
browser
.addFile('asyncAwaitWithFileManagerAccess.js', { content: asyncAwaitWithFileManagerAccess })
.openFile('asyncAwaitWithFileManagerAccess.js')
.pause(5000)
.executeScript('remix.execute(\'asyncAwaitWithFileManagerAccess.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'contract Ballot {', 60000)
},
'Call web3.eth.getAccounts() using JavaScript VM': function (browser: NightwatchBrowser) {
'Call web3.eth.getAccounts() using JavaScript VM #group2': function (browser: NightwatchBrowser) {
browser
.executeScript('web3.eth.getAccounts()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '["0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2","0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db","0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB","0x617F2E2fD72FD9D5503197092aC168c91465E7f2","0x17F6AD8Ef982297579C203069C1DbfFE4348c372","0x5c6B0f7Bf3E7ce046039Bd8FABdfD3f9F5021678","0x03C6FcED478cBbC9a4FAB34eF9f40767739D1Ff7","0x1aE0EA34a72D944a8C7603FfB3eC30a6669E454C","0x0A098Eda01Ce92ff4A4CCb7A4fFFb5A43EBC70DC","0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c","0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C","0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB","0x583031D1113aD414F02576BD6afaBfb302140225","0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]')
},
'Call web3.eth.getAccounts() using Web3 Provider': function (browser: NightwatchBrowser) {
'Call web3.eth.getAccounts() using Web3 Provider #group5': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.clickLaunchIcon('udapp')
@ -68,7 +58,7 @@ module.exports = {
.waitForElementContainsText('*[data-id="terminalJournal"]', '","', 60000)
},
'Call Remix File Resolver (external URL) from a script': function (browser: NightwatchBrowser) {
'Call Remix File Resolver (external URL) from a script #group3': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.addFile('resolveExternalUrlAndSave.js', { content: resolveExternalUrlAndSave })
@ -79,7 +69,7 @@ module.exports = {
.openFile('.deps/github/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol')
},
'Call Remix File Resolver (internal URL) from a script': function (browser: NightwatchBrowser) {
'Call Remix File Resolver (internal URL) from a script #group3': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.addFile('resolveUrl.js', { content: resolveUrl })
@ -89,7 +79,7 @@ module.exports = {
.waitForElementContainsText('*[data-id="terminalJournal"]', 'contract Ballot {', 60000)
},
'Call Remix File Resolver (internal URL) from a script and specify a path': function (browser: NightwatchBrowser) {
'Call Remix File Resolver (internal URL) from a script and specify a path #group3': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.addFile('resolveExternalUrlAndSaveToaPath.js', { content: resolveExternalUrlAndSaveToaPath })
@ -100,7 +90,7 @@ module.exports = {
.openFile('.deps/github/newFile.sol')
},
'Deploy "Owner" using an ether.js script, listen to event and check event are logged in the terminal': function (browser: NightwatchBrowser) {
'Deploy "Owner" using an ether.js script, listen to event and check event are logged in the terminal #group4': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('settings')
.clickLaunchIcon('udapp')
@ -109,12 +99,12 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="treeViewDivtreeViewItem"]') // make sure we create the file at the root folder
.addFile('deployWithEthersJs.js', { content: deployWithEthersJs })
.openFile('deployWithEthersJs.js')
// .openFile('deployWithEthersJs.js')
.pause(1000)
.click('[data-id="treeViewDivtreeViewItemcontracts"]')
.openFile('contracts/2_Owner.sol')
.clickLaunchIcon('solidity')
.click('*[data-id="compilerContainerCompileBtn"]') // compile Owner
.click('*[data-id="compilerContainerCompileBtn"]').pause(5000) // compile Owner
.executeScript('remix.execute(\'deployWithEthersJs.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Contract Address:', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd9145CCE52D386f254917e481eB44e9943F39138', 60000)
@ -130,7 +120,7 @@ module.exports = {
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd9145CCE52D386f254917e481eB44e9943F39138', 60000)
},
'Should print hardhat logs': function (browser: NightwatchBrowser) {
'Should print hardhat logs #group4': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.addFile('printHardhatlog.sol', { content: hardhatLog })
@ -153,7 +143,14 @@ module.exports = {
.clickFunction('getOwner - call')
.pause(1000)
.journalChildIncludes('inside getOwner', { shouldHaveOnlyOneOccurence: true })
.end()
},
'Should display auto-complete menu #group4': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="terminalCli"]')
.click('*[data-id="terminalCli"]')
.sendKeys('*[data-id="terminalCliInput"]', 'remix.')
.assert.visible('*[data-id="autoCompletePopUpAutoCompleteItem"]').end()
}
}

@ -3,6 +3,7 @@ import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
@ -10,7 +11,7 @@ module.exports = {
return sources
},
'Execute Simple Contract and Test Terminal': function (browser: NightwatchBrowser) {
'Execute Simple Contract and Test Terminal #group1': function (browser: NightwatchBrowser) {
browser.testContracts('Untitled.sol', sources[0]['Untitled.sol'], ['TestContract'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
@ -41,7 +42,7 @@ module.exports = {
.click('*[data-id="deployAndRunClearInstances"]')
},
'Test Complex Return Values': function (browser: NightwatchBrowser) {
'Test Complex Return Values #group1': function (browser: NightwatchBrowser) {
browser.testContracts('returnValues.sol', sources[1]['returnValues.sol'], ['testReturnValues'])
.clickLaunchIcon('udapp')
.click('#runTabView button[class^="instanceButton"]')
@ -86,7 +87,7 @@ module.exports = {
}).click('*[data-id="deployAndRunClearInstances"]')
},
'Test Complex Input Values': function (browser: NightwatchBrowser) {
'Test Complex Input Values #group2': function (browser: NightwatchBrowser) {
browser.testContracts('inputValues.sol', sources[2]['inputValues.sol'], ['test'])
.clickLaunchIcon('udapp')
.click('#runTabView button[class^="instanceButton"]')
@ -112,7 +113,7 @@ module.exports = {
},
logs: [
{
from: '0x8c1eD7e19abAa9f23c476dA86Dc1577F1Ef401f5',
from: '0xd9145CCE52D386f254917e481eB44e9943F39138',
topic: '0xd30981760edbf605bda8689e945f622877f230c9a77cbfbd448aa4b7d8ac6e7f',
event: 'event1',
args: {
@ -131,21 +132,21 @@ module.exports = {
.click('*[data-id="deployAndRunClearInstances"]')
},
'Should Compile and Deploy a contract which has an event declaring a function as parameter': function (browser: NightwatchBrowser) {
'Should Compile and Deploy a contract which has an event declaring a function as parameter #group2': function (browser: NightwatchBrowser) {
browser.testContracts('eventFunctionInput.sol', sources[3]['eventFunctionInput.sol'], ['C'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.click('#runTabView button[class^="instanceButton"]')
.waitForElementPresent('.instance:nth-of-type(2)')
.click('*[data-id="deployAndRunClearInstances"]')
},
'Should Compile and Deploy a contract which define a custom error, the error should be logged in the terminal': function (browser: NightwatchBrowser) {
'Should Compile and Deploy a contract which define a custom error, the error should be logged in the terminal #group3': function (browser: NightwatchBrowser) {
browser.testContracts('customError.sol', sources[4]['customError.sol'], ['C'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.click('#runTabView button[class^="instanceButton"]')
.waitForElementPresent('.instance:nth-of-type(3)')
.click('.instance:nth-of-type(3) > div > button')
.clickInstance(0)
.clickFunction('g - transact (not payable)')
.pause(5000)
.journalLastChildIncludes('Error provided by the contract:')
@ -158,15 +159,17 @@ module.exports = {
.journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"')
.journalLastChildIncludes('Debug the transaction to get more information.')
.click('*[data-id="deployAndRunClearInstances"]')
},
'Should Compile and Deploy a contract which define a custom error, the error should be logged in the terminal , using London VM Fork': function (browser: NightwatchBrowser) {
'Should Compile and Deploy a contract which define a custom error, the error should be logged in the terminal , using London VM Fork #group3': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('udapp')
.clearTransactions()
.click('*[data-id="settingsVMLondonMode"]') // switch to London fork
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.click('#runTabView button[class^="instanceButton"]')
.waitForElementPresent('.instance:nth-of-type(2)')
.click('.instance:nth-of-type(2) > div > button')
.clickInstance(0)
.clickFunction('g - transact (not payable)')
.journalLastChildIncludes('Error provided by the contract:')
.journalLastChildIncludes('CustomError : error description')
@ -178,6 +181,25 @@ module.exports = {
.journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"')
.journalLastChildIncludes('Debug the transaction to get more information.')
},
'Should Compile and Deploy a contract which define a custom error in a library, the error should be logged in the terminal #group3': function (browser: NightwatchBrowser) {
browser.testContracts('customErrorLib.sol', sources[5]['customErrorLib.sol'], ['D'])
.clickLaunchIcon('udapp')
.click('#runTabView button[class^="instanceButton"]')
.clickInstance(1)
.clickFunction('h - transact (not payable)')
.pause(5000)
.journalLastChildIncludes('Error provided by the contract:')
.journalLastChildIncludes('CustomError : error description from library')
.journalLastChildIncludes('Parameters:')
.journalLastChildIncludes('"value": "48"')
.journalLastChildIncludes('"value": "46"')
.journalLastChildIncludes('"value": "error_string_from_library"')
.journalLastChildIncludes('"documentation": "param1 from library"')
.journalLastChildIncludes('"documentation": "param2 from library"')
.journalLastChildIncludes('"documentation": "param3 from library"')
.journalLastChildIncludes('Debug the transaction to get more information.')
.end()
}
}
@ -281,5 +303,29 @@ contract C {
}
}`
}
},
{
'customErrorLib.sol': {
content: `// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.7;
library lib {
/// error description from library
/// @param a param1 from library
/// @param b param2 from library
/// @param c param3 from library
error CustomError(uint a, uint b, string c);
function set() public {
revert CustomError(48, 46, "error_string_from_library");
}
}
contract D {
function h() public {
lib.set();
}
}`
}
}
]

@ -59,6 +59,8 @@ declare module 'nightwatch' {
currentWorkspaceIs(name: string): NightwatchBrowser
addLocalPlugin(this: NightwatchBrowser, profile: Profile & LocationProfile & ExternalProfile): NightwatchBrowser
acceptAndRemember (this: NightwatchBrowser, remember: boolean, accept: boolean): NightwatchBrowser
clearConsole (this: NightwatchBrowser): NightwatchBrowser
clearTransactions (this: NightwatchBrowser): NightwatchBrowser
}
export interface NightwatchBrowser {

@ -7,7 +7,7 @@ echo "$BUILD_ID"
TEST_EXITCODE=0
npm run ganache-cli &
npm run serve &
npm run serve:production &
echo 'sharing folder: ' $PWD '/apps/remix-ide/contracts' &
npm run remixd &
@ -15,9 +15,9 @@ sleep 5
npm run build:e2e
TESTFILES=$(circleci tests glob "dist/apps/remix-ide-e2e/src/tests/**/*.test.js" | circleci tests split --split-by=timings)
TESTFILES=$(grep -IRiL "disabled" "dist/apps/remix-ide-e2e/src/tests" | grep "\.spec\|\.test" | sort | circleci tests split )
for TESTFILE in $TESTFILES; do
npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $TESTFILE --env=chrome || TEST_EXITCODE=1
npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $TESTFILE --env=$1 || TEST_EXITCODE=1
done
echo "$TEST_EXITCODE"

@ -22,7 +22,7 @@ setupRemixd
sleep 5
npm run nightwatch_parallel || TEST_EXITCODE=1
TESTFILES=$(circleci tests glob "./apps/remix-ide/test-browser/tests/**/*.test.js" | circleci tests split --split-by=timings)
TESTFILES=$(circleci tests glob "./apps/remix-ide/test-browser/tests/**/*.test.js" | circleci tests split )
for TESTFILE in $TESTFILES; do
./node_modules/.bin/nightwatch --config ./apps/remix-ide/nightwatch.js --env chrome $TESTFILE || TEST_EXITCODE=1
done

@ -1,27 +0,0 @@
#!/usr/bin/env bash
set -e
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
TEST_EXITCODE=0
npm run ganache-cli &
npm run serve &
echo 'sharing folder: ' $PWD '/apps/remix-ide/contracts' &
npm run remixd &
sleep 5
npm run build:e2e
TESTFILES=$(circleci tests glob "dist/apps/remix-ide-e2e/src/tests/**/*.spec.js" | circleci tests split --split-by=timings)
for TESTFILE in $TESTFILES; do
npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $TESTFILE --env=chrome || TEST_EXITCODE=1
done
echo "$TEST_EXITCODE"
if [ "$TEST_EXITCODE" -eq 1 ]
then
exit 1
fi

@ -1,27 +0,0 @@
#!/usr/bin/env bash
set -e
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
TEST_EXITCODE=0
npm run ganache-cli &
npm run serve &
echo 'sharing folder: ' $PWD '/apps/remix-ide/contracts' &
npm run remixd &
sleep 5
npm run build:e2e
TESTFILES=$(circleci tests glob "dist/apps/remix-ide-e2e/src/tests/**/*.test.js" | circleci tests split --split-by=timings)
for TESTFILE in $TESTFILES; do
npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $TESTFILE --env=firefox || TEST_EXITCODE=1
done
echo "$TEST_EXITCODE"
if [ "$TEST_EXITCODE" -eq 1 ]
then
exit 1
fi

@ -1,27 +0,0 @@
#!/usr/bin/env bash
set -e
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
TEST_EXITCODE=0
npm run ganache-cli &
npm run serve &
echo 'sharing folder: ' $PWD '/apps/remix-ide/contracts' &
npm run remixd &
sleep 5
npm run build:e2e
TESTFILES=$(circleci tests glob "dist/apps/remix-ide-e2e/src/tests/**/*.spec.js" | circleci tests split --split-by=timings)
for TESTFILE in $TESTFILES; do
npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $TESTFILE --env=firefox || TEST_EXITCODE=1
done
echo "$TEST_EXITCODE"
if [ "$TEST_EXITCODE" -eq 1 ]
then
exit 1
fi

@ -6,13 +6,17 @@ BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
TEST_EXITCODE=0
npm run serve &
npm run serve:production &
npx nx serve remix-ide-e2e-src-local-plugin &
sleep 5
npm run build:e2e
npm run nightwatch_local_pluginApi || TEST_EXITCODE=1
TESTFILES=$(grep -IRiL "disabled" "dist/apps/remix-ide-e2e/src/tests" | grep "plugin_api" | sort | circleci tests split )
for TESTFILE in $TESTFILES; do
npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $TESTFILE --env=chrome || TEST_EXITCODE=1
done
echo "$TEST_EXITCODE"
if [ "$TEST_EXITCODE" -eq 1 ]

@ -1,21 +0,0 @@
#!/usr/bin/env bash
set -e
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
TEST_EXITCODE=0
npm run ganache-cli &
npm run serve &
sleep 5
npm run build:e2e
npm run nightwatch_local_runAndDeploy || TEST_EXITCODE=1
echo "$TEST_EXITCODE"
if [ "$TEST_EXITCODE" -eq 1 ]
then
exit 1
fi

@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -e
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
TEST_EXITCODE=0
KEYS=$(jq -r '.projects | keys' workspace.json | tr -d '[],"')
(for row in $KEYS; do
if [ "$row" != "debugger" ]
then
echo ${row}
fi
done) | circleci tests split | { while read i;do npm run lint $i; done }
echo "$TEST_EXITCODE"
if [ "$TEST_EXITCODE" -eq 1 ]
then
exit 1
fi

@ -2,8 +2,7 @@
const IpfsHttpClient = require('ipfs-http-client')
const { globSource } = IpfsHttpClient
console.log('current folder', process.cwd())
const folder = process.cwd() + '/temp_publish_docker';
const folder = process.cwd() + '/dist/apps/remix-ide';
(async () => {
const host = 'ipfs.remixproject.org'
@ -11,9 +10,7 @@ const folder = process.cwd() + '/temp_publish_docker';
try {
let result = await ipfs.add(globSource(folder, { recursive: true}), { pin: false })
const hash = result.cid.toString()
console.log('ipfs://' + hash)
console.log('https://ipfs.remixproject.org/ipfs/' + hash)
console.log('https://gateway.ipfs.io/ipfs/' + hash)
console.log(hash)
} catch (e) {
console.log(e)
}

@ -1,13 +1,7 @@
'use strict'
import { basicLogo } from './app/ui/svgLogo'
import { RunTab, makeUdapp } from './app/udapp'
import PanelsResize from './lib/panels-resize'
import { RemixEngine } from './remixEngine'
import { RemixAppManager } from './remixAppManager'
import { FramingService } from './framingService'
import { WalkthroughService } from './walkthroughService'
import { MainView } from './app/panels/main-view'
import { ThemeModule } from './app/tabs/theme-module'
import { NetworkModule } from './app/tabs/network-module'
@ -17,14 +11,16 @@ import { HiddenPanel } from './app/components/hidden-panel'
import { VerticalIcons } from './app/components/vertical-icons'
import { LandingPage } from './app/ui/landing-page/landing-page'
import { MainPanel } from './app/components/main-panel'
import { FramingService } from './framingService'
import { WalkthroughService } from './walkthroughService'
import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports } from '@remix-project/core-plugin'
import migrateFileSystem from './migrateFileSystem'
const isElectron = require('is-electron')
const csjs = require('csjs-inject')
const yo = require('yo-yo')
const remixLib = require('@remix-project/remix-lib')
const registry = require('./global/registry')
@ -33,8 +29,7 @@ const Storage = remixLib.Storage
const RemixDProvider = require('./app/files/remixDProvider')
const HardhatProvider = require('./app/tabs/hardhat-provider')
const Config = require('./config')
const modalDialogCustom = require('./app/ui/modal-dialog-custom')
const modalDialog = require('./app/ui/modaldialog')
const FileManager = require('./app/files/fileManager')
const FileProvider = require('./app/files/fileProvider')
const DGitProvider = require('./app/files/dgitProvider')
@ -54,92 +49,13 @@ const FilePanel = require('./app/panels/file-panel')
const Editor = require('./app/editor/editor')
const Terminal = require('./app/panels/terminal')
const ContextualListener = require('./app/editor/contextualListener')
const _paq = window._paq = window._paq || []
const css = csjs`
html { box-sizing: border-box; }
*, *:before, *:after { box-sizing: inherit; }
body {
/* font: 14px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; */
font-size : .8rem;
}
pre {
overflow-x: auto;
}
.remixIDE {
width : 100vw;
height : 100vh;
overflow : hidden;
flex-direction : row;
display : flex;
}
.mainpanel {
display : flex;
flex-direction : column;
overflow : hidden;
flex : 1;
}
.iconpanel {
display : flex;
flex-direction : column;
overflow : hidden;
width : 50px;
user-select : none;
}
.sidepanel {
display : flex;
flex-direction : row-reverse;
width : 320px;
}
.highlightcode {
position : absolute;
z-index : 20;
background-color : var(--info);
}
.highlightcode_fullLine {
position : absolute;
z-index : 20;
background-color : var(--info);
opacity : 0.5;
}
.centered {
position : fixed;
top : 20%;
left : 45%;
width : 200px;
height : 200px;
}
.centered svg path {
fill: var(--secondary);
}
.centered svg polygon {
fill : var(--secondary);
}
.onboarding {
color : var(--text-info);
background-color : var(--info);
}
.matomoBtn {
width : 100px;
}
`
class App {
class AppComponent {
constructor (api = {}, events = {}, opts = {}) {
var self = this
const self = this
self.appManager = new RemixAppManager({})
self._components = {}
self._view = {}
self._view.splashScreen = yo`
<div class=${css.centered}>
${basicLogo()}
<div class="info-secondary" style="text-align:center">
REMIX IDE
</div>
</div>
`
document.body.appendChild(self._view.splashScreen)
self.registry = registry
// setup storage
const configStorage = new Storage('config-v0.8:')
@ -161,67 +77,22 @@ class App {
migrateFileSystem(self._components.filesProviders.browser)
}
init () {
this.run().catch(console.error)
}
render () {
var self = this
if (self._view.el) return self._view.el
// not resizable
self._view.iconpanel = yo`
<div id="icon-panel" data-id="remixIdeIconPanel" class="${css.iconpanel} bg-light">
${''}
</div>
`
// center panel, resizable
self._view.sidepanel = yo`
<div id="side-panel" data-id="remixIdeSidePanel" style="min-width: 320px;" class="${css.sidepanel} border-right border-left">
${''}
</div>
`
// handle the editor + terminal
self._view.mainpanel = yo`
<div id="main-panel" data-id="remixIdeMainPanel" class=${css.mainpanel}>
${''}
</div>
`
self._components.resizeFeature = new PanelsResize(self._view.sidepanel)
self._view.el = yo`
<div style="visibility:hidden" class=${css.remixIDE} data-id="remixIDE">
${self._view.iconpanel}
${self._view.sidepanel}
${self._components.resizeFeature.render()}
${self._view.mainpanel}
</div>
`
return self._view.el
}
async run () {
var self = this
// check the origin and warn message
if (window.location.hostname === 'yann300.github.io') {
modalDialogCustom.alert('This UNSTABLE ALPHA branch of Remix has been moved to http://ethereum.github.io/remix-live-alpha.')
} else if (window.location.hostname === 'remix-alpha.ethereum.org' ||
(window.location.hostname === 'ethereum.github.io' && window.location.pathname.indexOf('/remix-live-alpha') === 0)) {
modalDialogCustom.alert('Welcome to the Remix alpha instance. Please use it to try out latest features. But use preferably https://remix.ethereum.org for any production work.')
} else if (window.location.protocol.indexOf('http') === 0 &&
window.location.hostname !== 'remix.ethereum.org' &&
window.location.hostname !== 'localhost' &&
window.location.hostname !== '127.0.0.1') {
modalDialogCustom.alert(`The Remix IDE has moved to http://remix.ethereum.org.\n
This instance of Remix you are visiting WILL NOT BE UPDATED.\n
Please make a backup of your contracts and start using http://remix.ethereum.org`)
}
if (window.location.protocol.indexOf('https') === 0) {
toolTip('You are using an `https` connection. Please switch to `http` if you are using Remix against an `http Web3 provider` or allow Mixed Content in your browser.')
const self = this
// APP_MANAGER
const appManager = self.appManager
const pluginLoader = self.appManager.pluginLoader
self.workspace = pluginLoader.get()
self.engine = new RemixEngine()
self.engine.register(appManager)
const matomoDomains = {
'remix-alpha.ethereum.org': 27,
'remix-beta.ethereum.org': 25,
'remix.ethereum.org': 23
}
self.showMatamo = (matomoDomains[window.location.hostname] && !registry.get('config').api.exists('settings/matomo-analytics'))
self.walkthroughService = new WalkthroughService(appManager, self.showMatamo)
const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080']
// workaround for Electron support
@ -232,23 +103,11 @@ class App {
}
}
// APP_MANAGER
const appManager = self.appManager
const pluginLoader = appManager.pluginLoader
const workspace = pluginLoader.get()
const engine = new RemixEngine()
engine.register(appManager)
// SERVICES
// ----------------- theme service ---------------------------------
const themeModule = new ThemeModule(registry)
registry.put({ api: themeModule, name: 'themeModule' })
themeModule.initTheme(() => {
setTimeout(() => {
document.body.removeChild(self._view.splashScreen)
self._view.el.style.visibility = 'visible'
}, 1500)
})
self.themeModule = new ThemeModule(registry)
registry.put({ api: self.themeModule, name: 'themeModule' })
// ----------------- editor service ----------------------------
const editor = new Editor() // wrapper around ace editor
registry.put({ api: editor, name: 'editor' })
@ -288,10 +147,10 @@ class App {
{ appManager, blockchain },
{
getPosition: (event) => {
var limitUp = 36
var limitDown = 20
var height = window.innerHeight
var newpos = (event.pageY < limitUp) ? limitUp : event.pageY
const limitUp = 36
const limitDown = 20
const height = window.innerHeight
let newpos = (event.pageY < limitUp) ? limitUp : event.pageY
newpos = (newpos < height - limitDown) ? newpos : height - limitDown
return height - newpos
}
@ -299,10 +158,10 @@ class App {
)
const contextualListener = new ContextualListener({ editor })
engine.register([
self.engine.register([
blockchain,
contentImport,
themeModule,
self.themeModule,
editor,
fileManager,
compilerMetadataGenerator,
@ -314,110 +173,44 @@ class App {
web3Provider,
fetchAndCompile,
dGitProvider,
hardhatProvider
hardhatProvider,
self.walkthroughService
])
// LAYOUT & SYSTEM VIEWS
const appPanel = new MainPanel()
const mainview = new MainView(contextualListener, editor, appPanel, fileManager, appManager, terminal)
registry.put({ api: mainview, name: 'mainview' })
self.mainview = new MainView(contextualListener, editor, appPanel, fileManager, appManager, terminal)
registry.put({ api: self.mainview, name: 'mainview' })
engine.register([
self.engine.register([
appPanel,
mainview.tabProxy
self.mainview.tabProxy
])
// those views depend on app_manager
const menuicons = new VerticalIcons(appManager)
const sidePanel = new SidePanel(appManager, menuicons)
const hiddenPanel = new HiddenPanel()
const pluginManagerComponent = new PluginManagerComponent(appManager, engine)
self.menuicons = new VerticalIcons(appManager)
self.sidePanel = new SidePanel(appManager, self.menuicons)
self.hiddenPanel = new HiddenPanel()
const pluginManagerComponent = new PluginManagerComponent(appManager, self.engine)
const filePanel = new FilePanel(appManager)
const landingPage = new LandingPage(appManager, menuicons, fileManager, filePanel, contentImport)
const settings = new SettingsTab(
const landingPage = new LandingPage(appManager, self.menuicons, fileManager, filePanel, contentImport)
self.settings = new SettingsTab(
registry.get('config').api,
editor,
appManager
)
// adding Views to the DOM
self._view.mainpanel.appendChild(mainview.render())
self._view.iconpanel.appendChild(menuicons.render())
self._view.sidepanel.appendChild(sidePanel.render())
document.body.appendChild(hiddenPanel.render()) // Hidden Panel is display none, it can be directly on body
engine.register([
menuicons,
self.engine.register([
self.menuicons,
landingPage,
hiddenPanel,
sidePanel,
self.hiddenPanel,
self.sidePanel,
filePanel,
pluginManagerComponent,
settings
self.settings
])
const queryParams = new QueryParams()
const params = queryParams.get()
const onAcceptMatomo = () => {
_paq.push(['forgetUserOptOut'])
// @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used
document.cookie = 'mtm_consent_removed=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
settings.updateMatomoAnalyticsChoice(true)
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
startWalkthroughService()
}
const onDeclineMatomo = () => {
settings.updateMatomoAnalyticsChoice(false)
_paq.push(['optUserOut'])
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
startWalkthroughService()
}
const startWalkthroughService = () => {
const walkthroughService = new WalkthroughService(localStorage)
if (!params.code && !params.url && !params.minimizeterminal && !params.gist && !params.minimizesidepanel) {
walkthroughService.start()
}
}
// Ask to opt in to Matomo for remix, remix-alpha and remix-beta
const matomoDomains = {
'remix-alpha.ethereum.org': 27,
'remix-beta.ethereum.org': 25,
'remix.ethereum.org': 23
}
if (matomoDomains[window.location.hostname] && !registry.get('config').api.exists('settings/matomo-analytics')) {
modalDialog(
'Help us to improve Remix IDE',
yo`
<div>
<p>An Opt-in version of <a href="https://matomo.org" target="_blank">Matomo</a>, an open source data analytics platform is being used to improve Remix IDE.</p>
<p>We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.</p>
<p>All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public: <a href="https://matomo.ethereum.org/index.php?module=MultiSites&action=index&idSite=23&period=day&date=yesterday" target="_blank">take a look</a>.</p>
<p>We do not collect nor store any personally identifiable information (PII).</p>
<p>For more info, see: <a href="https://medium.com/p/66ef69e14931/" target="_blank">Matomo Analyitcs on Remix iDE</a>.</p>
<p>You can change your choice in the Settings panel anytime.</p>
<div class="d-flex justify-content-around pt-3 border-top">
<button class="btn btn-primary ${css.matomoBtn}" onclick=${() => onAcceptMatomo()}>Sure</button>
<button class="btn btn-secondary ${css.matomoBtn}" onclick=${() => onDeclineMatomo()}>Decline</button>
</div>
</div>`,
{
label: '',
fn: null
},
{
label: '',
fn: null
}
)
} else {
startWalkthroughService()
}
// CONTENT VIEWS & DEFAULT PLUGINS
const compileTab = new CompileTab(registry.get('config').api, registry.get('filemanager').api)
const run = new RunTab(
@ -428,7 +221,7 @@ class App {
filePanel,
registry.get('compilersartefacts').api,
networkModule,
mainview,
self.mainview,
registry.get('fileproviders/browser').api
)
const analysis = new AnalysisTab(registry)
@ -442,7 +235,7 @@ class App {
contentImport
)
engine.register([
self.engine.register([
compileTab,
run,
debug,
@ -453,47 +246,55 @@ class App {
filePanel.hardhatHandle,
filePanel.slitherHandle
])
}
async activate () {
const queryParams = new QueryParams()
const params = queryParams.get()
const self = this
if (isElectron()) {
appManager.activatePlugin('remixd')
self.appManager.activatePlugin('remixd')
}
try {
engine.register(await appManager.registeredPlugins())
self.engine.register(await self.appManager.registeredPlugins())
} catch (e) {
console.log('couldn\'t register iframe plugins', e.message)
}
await appManager.activatePlugin(['editor'])
await appManager.activatePlugin(['theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter'])
await appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])
await appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await appManager.activatePlugin(['home'])
await appManager.activatePlugin(['settings'])
await appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport'])
await self.appManager.activatePlugin(['editor'])
await self.appManager.activatePlugin(['theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter'])
await self.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])
await self.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await self.appManager.activatePlugin(['home'])
await self.appManager.activatePlugin(['settings'])
await self.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport'])
await self.appManager.activatePlugin(['settings'])
await self.appManager.activatePlugin(['walkthrough'])
appManager.on('filePanel', 'workspaceInitializationCompleted', async () => {
await appManager.registerContextMenuItems()
self.appManager.on('filePanel', 'workspaceInitializationCompleted', async () => {
await self.appManager.registerContextMenuItems()
})
await appManager.activatePlugin(['filePanel'])
await self.appManager.activatePlugin(['filePanel'])
// Set workspace after initial activation
appManager.on('editor', 'editorMounted', () => {
if (Array.isArray(workspace)) {
appManager.activatePlugin(workspace).then(async () => {
self.appManager.on('editor', 'editorMounted', () => {
if (Array.isArray(self.workspace)) {
self.appManager.activatePlugin(self.workspace).then(async () => {
try {
if (params.deactivate) {
await appManager.deactivatePlugin(params.deactivate.split(','))
await self.appManager.deactivatePlugin(params.deactivate.split(','))
}
} catch (e) {
console.log(e)
}
if (params.code) {
// if code is given in url we focus on solidity plugin
menuicons.select('solidity')
self.menuicons.select('solidity')
} else {
// If plugins are loaded from the URL params, we focus on the last one.
if (pluginLoader.current === 'queryParams' && workspace.length > 0) menuicons.select(workspace[workspace.length - 1])
if (self.appManager.pluginLoader.current === 'queryParams' && self.workspace.length > 0) self.menuicons.select(self.workspace[self.workspace.length - 1])
}
if (params.call) {
@ -501,22 +302,20 @@ class App {
if (callDetails.length > 1) {
toolTip(`initiating ${callDetails[0]} ...`)
// @todo(remove the timeout when activatePlugin is on 0.3.0)
appManager.call(...callDetails).catch(console.error)
self.appManager.call(...callDetails).catch(console.error)
}
}
}).catch(console.error)
} else {
// activate solidity plugin
appManager.activatePlugin(['solidity', 'udapp'])
}
})
// activate solidity plugin
self.appManager.activatePlugin(['solidity', 'udapp'])
// Load and start the service who manager layout and frame
const framingService = new FramingService(sidePanel, menuicons, mainview, this._components.resizeFeature)
const framingService = new FramingService(self.sidePanel, self.menuicons, self.mainview, null)
if (params.embed) framingService.embed()
framingService.start(params)
}
}
module.exports = App
export default AppComponent

@ -1,13 +1,14 @@
import * as packageJson from '../../../../../package.json'
// eslint-disable-next-line no-unused-vars
import { basicLogo } from '../ui/svgLogo'
var yo = require('yo-yo')
var csjs = require('csjs-inject')
var helper = require('../../lib/helper')
import ReactDOM from 'react-dom'
import React from 'react' // eslint-disable-line
// eslint-disable-next-line no-unused-vars
import { RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel'
// var helper = require('../../lib/helper')
const globalRegistry = require('../../global/registry')
const contextMenu = require('../ui/contextMenu')
const { Plugin } = require('@remixproject/engine')
const EventEmitter = require('events')
let VERTICALMENU_HANDLE
const profile = {
name: 'menuicons',
@ -23,170 +24,57 @@ export class VerticalIcons extends Plugin {
super(profile)
this.events = new EventEmitter()
this.appManager = appManager
this.htmlElement = document.createElement('div')
this.htmlElement.setAttribute('id', 'icon-panel')
this.icons = {}
this.iconKind = {}
this.iconStatus = {}
this.defaultProfile = profile
this.targetProfileForChange = {}
this.targetProfileForRemoval = {}
this.registry = globalRegistry
this.keys = ['succeed', 'edited', 'none', 'loading', 'failed']
this.types = ['error', 'warning', 'success', 'info', '']
}
renderComponent () {
ReactDOM.render(
<RemixUiVerticalIconsPanel
verticalIconsPlugin={this}
/>,
this.htmlElement)
}
const themeModule = globalRegistry.get('themeModule').api
themeModule.events.on('themeChanged', (theme) => {
this.onThemeChanged(theme.quality)
})
onActivation () {
this.renderComponent()
}
linkContent (profile) {
if (!profile.icon) return
this.addIcon(profile)
if (!profile.kind) profile.kind = 'none'
this.targetProfileForChange[profile.name] = profile
this.listenOnStatus(profile)
this.renderComponent()
}
unlinkContent (profile) {
this.targetProfileForRemoval = profile
this.removeIcon(profile)
}
listenOnStatus (profile) {
// the list of supported keys. 'none' will remove the status
const keys = ['edited', 'succeed', 'none', 'loading', 'failed']
const types = ['error', 'warning', 'success', 'info', '']
const fn = (status) => {
if (!types.includes(status.type) && status.type) throw new Error(`type should be ${keys.join()}`)
if (status.key === undefined) throw new Error('status key should be defined')
if (typeof status.key === 'string' && (!keys.includes(status.key))) {
throw new Error('key should contain either number or ' + keys.join())
}
this.setIconStatus(profile.name, status)
}
this.iconStatus[profile.name] = fn
this.on(profile.name, 'statusChanged', this.iconStatus[profile.name])
}
/**
* Add an icon to the map
* @param {ModuleProfile} profile The profile of the module
*/
addIcon ({ kind, name, icon, displayName, tooltip, documentation }) {
let title = (tooltip || displayName || name)
title = title.replace(/^\w/, c => c.toUpperCase())
this.icons[name] = yo`
<div
class="${css.icon} m-2"
onclick="${() => { this.toggle(name) }}"
plugin="${name}"
title="${title}"
oncontextmenu="${(e) => this.itemContextMenu(e, name, documentation)}"
data-id="verticalIconsKind${name}"
id="verticalIconsKind${name}"
>
<img class="image" src="${icon}" alt="${name}" />
</div>`
this.iconKind[kind || 'none'].appendChild(this.icons[name])
}
/**
* resolve a classes list for @arg key
* @param {Object} key
* @param {Object} type
*/
resolveClasses (key, type) {
let classes = css.status
switch (key) {
case 'succeed':
classes += ' fas fa-check-circle text-' + type + ' ' + css.statusCheck
break
case 'edited':
classes += ' fas fa-sync text-' + type + ' ' + css.statusCheck
break
case 'loading':
classes += ' fas fa-spinner text-' + type + ' ' + css.statusCheck
break
case 'failed':
classes += ' fas fa-exclamation-triangle text-' + type + ' ' + css.statusCheck
break
default: {
classes += ' badge badge-pill badge-' + type
}
}
return classes
}
/**
* Set a new status for the @arg name
* @param {String} name
* @param {Object} status
*/
setIconStatus (name, status) {
const el = this.icons[name]
if (!el) return
const statusEl = el.querySelector('i')
if (statusEl) {
el.removeChild(statusEl)
}
if (status.key === 'none') return // remove status
let text = ''
let key = ''
if (typeof status.key === 'number') {
key = status.key.toString()
text = key
} else key = helper.checkSpecialChars(status.key) ? '' : status.key
let type = ''
if (status.type === 'error') {
type = 'danger' // to use with bootstrap
} else type = helper.checkSpecialChars(status.type) ? '' : status.type
const title = helper.checkSpecialChars(status.title) ? '' : status.title
el.appendChild(yo`<i
title="${title}"
class="${this.resolveClasses(key, type)}"
aria-hidden="true"
>
${text}
</i>`)
el.classList.add(`${css.icon}`)
}
/**
* Remove an icon from the map
* @param {ModuleProfile} profile The profile of the module
*/
removeIcon ({ kind, name }) {
if (this.icons[name]) this.iconKind[kind || 'none'].removeChild(this.icons[name])
}
/**
* Remove active for the current activated icons
*/
removeActive () {
// reset filters
const images = this.view.querySelectorAll('.image')
images.forEach(function (im) {
im.style.setProperty('filter', 'invert(0.5)')
})
// remove active
const currentActive = this.view.querySelector('.active')
if (currentActive) {
currentActive.classList.remove('active')
}
}
/**
* Add active for the new activated icon
* @param {string} name Name of profile of the module to activate
*/
addActive (name) {
if (name === 'home') return
const themeType = globalRegistry.get('themeModule').api.currentTheme().quality
const invert = themeType === 'dark' ? 1 : 0
const brightness = themeType === 'dark' ? '150' : '0' // should be >100 for icons with color
const nextActive = this.view.querySelector(`[plugin="${name}"]`)
if (nextActive) {
const image = nextActive.querySelector('.image')
nextActive.classList.add('active')
image.style.setProperty('filter', `invert(${invert}) grayscale(1) brightness(${brightness}%)`)
}
removeIcon ({ name }) {
if (this.targetProfileForChange[name]) delete this.targetProfileForChange[name]
setTimeout(() => {
this.renderComponent()
}, 150)
}
/**
@ -194,28 +82,11 @@ export class VerticalIcons extends Plugin {
* @param {string} name Name of profile of the module to activate
*/
select (name) {
this.updateActivations(name)
// TODO: Only keep `this.emit` (issue#2210)
this.emit('showContent', name)
this.events.emit('showContent', name)
}
/**
* Toggles the side panel for plugin
* @param {string} name Name of profile of the module to activate
*/
toggle (name) {
this.updateActivations(name)
// TODO: Only keep `this.emit` (issue#2210)
this.emit('toggleContent', name)
this.events.emit('toggleContent', name)
}
updateActivations (name) {
this.removeActive()
this.addActive(name)
}
onThemeChanged (themeType) {
const invert = themeType === 'dark' ? 1 : 0
const active = this.view.querySelector('.active')
@ -225,131 +96,17 @@ export class VerticalIcons extends Plugin {
}
}
async itemContextMenu (e, name, documentation) {
const actions = {}
if (await this.appManager.canDeactivatePlugin(profile, { name })) {
actions.Deactivate = () => {
// this.call('manager', 'deactivatePlugin', name)
this.appManager.deactivatePlugin(name)
if (e.target.parentElement.classList.contains('active')) {
this.select('filePanel')
}
}
}
const links = {}
if (documentation) {
links.Documentation = documentation
}
if (Object.keys(actions).length || Object.keys(links).length) {
VERTICALMENU_HANDLE && VERTICALMENU_HANDLE.hide(null, true)
VERTICALMENU_HANDLE = contextMenu(e, actions, links)
}
e.preventDefault()
e.stopPropagation()
/**
* Toggles the side panel for plugin
* @param {string} name Name of profile of the module to activate
*/
toggle (name) {
// TODO: Only keep `this.emit` (issue#2210)
this.emit('toggleContent', name)
this.events.emit('toggleContent', name)
}
render () {
const home = yo`
<div
class="m-1 mt-2 ${css.homeIcon}"
onclick="${async () => {
await this.appManager.activatePlugin('home')
this.call('tabs', 'focus', 'home')
}}"
plugin="home" title="Home"
data-id="verticalIconsHomeIcon"
id="verticalIconsHomeIcon"
>
${basicLogo()}
</div>
`
this.iconKind.fileexplorer = yo`<div id='fileExplorerIcons' data-id="verticalIconsFileExplorerIcons"></div>`
this.iconKind.compiler = yo`<div id='compileIcons'></div>`
this.iconKind.udapp = yo`<div id='runIcons'></div>`
this.iconKind.testing = yo`<div id='testingIcons'></div>`
this.iconKind.analysis = yo`<div id='analysisIcons'></div>`
this.iconKind.debugging = yo`<div id='debuggingIcons' data-id="verticalIconsDebuggingIcons"></div>`
this.iconKind.none = yo`<div id='otherIcons'></div>`
this.iconKind.settings = yo`<div id='settingsIcons' data-id="verticalIconsSettingsIcons"></div>`
this.view = yo`
<div class="h-100">
<div class=${css.icons}>
${home}
${this.iconKind.fileexplorer}
${this.iconKind.compiler}
${this.iconKind.udapp}
${this.iconKind.testing}
${this.iconKind.analysis}
${this.iconKind.debugging}
${this.iconKind.none}
${this.iconKind.settings}
</div>
</div>
`
return this.view
}
}
const css = csjs`
.homeIcon {
display: block;
width: 42px;
height: 42px;
margin-bottom: 20px;
cursor: pointer;
}
.homeIcon svg path {
fill: var(--primary);
}
.homeIcon svg polygon {
fill: var(--primary);
}
.icons {
}
.icon {
cursor: pointer;
margin-bottom: 12px;
width: 36px;
height: 36px;
padding: 3px;
position: relative;
border-radius: 8px;
}
.icon img {
width: 28px;
height: 28px;
padding: 4px;
filter: invert(0.5);
}
.image {
}
.icon svg {
width: 28px;
height: 28px;
padding: 4px;
}
.icon[title='Settings'] {
position: absolute;
bottom: 0;
}
.status {
position: absolute;
bottom: 0;
right: 0;
}
.statusCheck {
font-size: 1.2em;
return this.htmlElement
}
.statusWithBG
border-radius: 8px;
background-color: var(--danger);
color: var(--light);
font-size: 12px;
height: 15px;
text-align: center;
font-weight: bold;
padding-left: 5px;
padding-right: 5px;
}
`

@ -82,7 +82,7 @@ class Editor extends Plugin {
ReactDOM.render(
<EditorUI
editorAPI={this.api}
theme={this.currentTheme}
themeType={this.currentThemeType}
currentFile={this.currentFile}
sourceAnnotationsPerFile={this.sourceAnnotationsPerFile}
markerPerFile={this.markerPerFile}
@ -107,13 +107,12 @@ class Editor extends Plugin {
this.clearAllDecorationsFor(name)
})
const translateTheme = (theme) => this._themes[theme.name === 'Dark' ? 'remixDark' : theme.quality]
this.on('theme', 'themeLoaded', (theme) => {
this.currentTheme = translateTheme(theme)
this.currentThemeType = theme.quality
this.renderComponent()
})
try {
this.currentTheme = translateTheme(await this.call('theme', 'currentTheme'))
this.currentThemeType = (await this.call('theme', 'currentTheme')).quality
} catch (e) {
console.log('unable to select the theme ' + e.message)
}
@ -156,6 +155,7 @@ class Editor extends Plugin {
}
_switchSession (path) {
if (path === this.currentFile) return
this.triggerEvent('sessionSwitched', [])
this.currentFile = path
this.renderComponent()

@ -141,6 +141,7 @@ class FileManager extends Plugin {
const provider = this.fileProviderOf('/')
// emit rootFolderChanged so that File Explorer reloads the file tree
provider.event.emit('rootFolderChanged', provider.workspace || '/')
this.emit('rootFolderChanged', provider.workspace || '/')
}
/**

@ -8,7 +8,8 @@ const profile = {
methods: ['analyse'],
description: 'Using Remixd daemon, run slither static analysis',
kind: 'other',
version: packageJson.version
version: packageJson.version,
documentation: 'https://remix-ide.readthedocs.io/en/latest/slither.html'
}
export class SlitherHandle extends WebsocketPlugin {

@ -310,10 +310,10 @@ class ContractDropdownUI {
const data = self.runView.compilersArtefacts.getCompilerAbstract(contractObject.contract.file)
self.runView.compilersArtefacts.addResolvedContract(helper.addressToString(address), data)
if (self.ipfsCheckedState) {
_paq.push(['trackEvent', 'udapp', 'DeployAndPublish', this.networkName, this.networkId])
_paq.push(['trackEvent', 'udapp', 'DeployAndPublish', this.networkName + '_' + this.networkId])
publishToStorage('ipfs', self.runView.fileProvider, self.runView.fileManager, selectedContract)
} else {
_paq.push(['trackEvent', 'udapp', 'DeployOnly', this.networkName, this.networkId])
_paq.push(['trackEvent', 'udapp', 'DeployOnly', this.networkName + '_' + this.networkId])
}
}
@ -347,7 +347,7 @@ class ContractDropdownUI {
}
deployContract (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) {
_paq.push(['trackEvent', 'udapp', 'DeployContractTo', this.networkName, this.networkId])
_paq.push(['trackEvent', 'udapp', 'DeployContractTo', this.networkName + '_' + this.networkId])
const { statusCb } = callbacks
if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) {
return this.blockchain.deployContractAndLibraries(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb)

@ -2,7 +2,6 @@ import { Plugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import QueryParams from '../../lib/query-params'
import * as packageJson from '../../../../../package.json'
import yo from 'yo-yo'
const _paq = window._paq = window._paq || []
const themes = [
@ -37,10 +36,12 @@ export class ThemeModule extends Plugin {
theme.url = window.location.origin + window.location.pathname + theme.url
return { ...acc, [theme.name]: theme }
}, {})
this._paq = _paq
let queryTheme = (new QueryParams()).get().theme
queryTheme = this.themes[queryTheme] ? queryTheme : null
let currentTheme = this._deps.config.get('settings/theme')
currentTheme = this.themes[currentTheme] ? currentTheme : null
this.currentThemeState = { queryTheme, currentTheme }
this.active = queryTheme || currentTheme || 'Dark'
this.forced = !!queryTheme
}
@ -58,11 +59,16 @@ export class ThemeModule extends Plugin {
/**
* Init the theme
*/
initTheme (callback) {
initTheme (callback) { // callback is setTimeOut in app.js which is always passed
if (callback) this.initCallback = callback
if (this.active) {
const nextTheme = this.themes[this.active] // Theme
document.documentElement.style.setProperty('--theme', nextTheme.quality)
const theme = yo`<link rel="stylesheet" href="${nextTheme.url}" id="theme-link"/>`
const theme = document.createElement('link')
theme.setAttribute('rel', 'stylesheet')
theme.setAttribute('href', nextTheme.url)
theme.setAttribute('id', 'theme-link')
theme.addEventListener('load', () => {
if (callback) callback()
})
@ -79,12 +85,16 @@ export class ThemeModule extends Plugin {
throw new Error(`Theme ${themeName} doesn't exist`)
}
const next = themeName || this.active // Name
if (next === this.active) return
if (next === this.active) return // --> exit out of this method
_paq.push(['trackEvent', 'themeModule', 'switchTo', next])
const nextTheme = this.themes[next] // Theme
if (!this.forced) this._deps.config.set('settings/theme', next)
document.getElementById('theme-link').remove()
const theme = yo`<link rel="stylesheet" href="${nextTheme.url}" id="theme-link"/>`
const theme = document.createElement('link')
theme.setAttribute('rel', 'stylesheet')
theme.setAttribute('href', nextTheme.url)
theme.setAttribute('id', 'theme-link')
theme.addEventListener('load', () => {
this.emit('themeLoaded', nextTheme)
this.events.emit('themeLoaded', nextTheme)

@ -2,12 +2,12 @@
:root {
--blue: #28282D;
--indigo: #6610f2;
--purple: #6f42c1;
--pink: #e83e8c;
--purple: #9e77f6;
--pink: #f38abb;
--red: #823a3a;
--orange: #8a5026;
--orange: #e46b15;
--yellow: #ffc107;
--green: #366a57;
--green: #065337;
--teal: #20c997;
--cyan: #053c64;
--white: #d5d5d5;
@ -17,10 +17,11 @@
--secondary: #3d3e44;
--success: #366a57;
--info: #086CB5;
--warning: #8a5026;
--warning: #c26829;
--danger: #823a3a;
--light: #1f2020;
--dark: #1a1a1a;
--text: #babbcc;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;

@ -5,8 +5,8 @@
--pink: #e83e8c;
--red: #dc3545;
--orange: #fd7e14;
--yellow: #ffc107;
--green: #28a745;
--yellow: #cdae02;
--green: #0c8a29;
--teal: #20c997;
--cyan: #17a2b8;
--white: #fff;
@ -14,12 +14,13 @@
--gray-dark: #343a40;
--primary: #fc58a3;
--secondary: #e2f5f2;
--success: #84e5c2;
--success: #24b882;
--info: #69c7e9;
--warning: #fbdf9f;
--warning: #fabe33;
--danger: #f80b0b;
--light: #fff;
--dark: #645fb5;
--text: #11556c;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;

@ -2,12 +2,12 @@
:root {
--blue: #007aa6;
--indigo: #6610f2;
--purple: #6f42c1;
--pink: #e83e8c;
--purple: #9e77f6;
--pink: #f38abb;
--red: #b84040;
--orange: #c97539;
--orange: #e46b15;
--yellow: #ffc107;
--green: #32ba89;
--green: #219451;
--teal: #20c997;
--cyan: #355f7d;
--white: #fff;
@ -21,6 +21,8 @@
--danger: #b84040;
--light: #2a2c3f;
--dark: #222336;
--text: #babbcc;
--text-background: #222336;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
@ -5649,7 +5651,7 @@ button.bg-success:hover {
background-color: #27926b !important;
}
.bg-info {
background-color: #355f7d !important;
background-color: #274458 !important;
}
a.bg-info:focus,
a.bg-info:hover,

@ -1,11 +1,11 @@
:root {
--blue: #007bff;
--indigo: #6610f2;
--purple: #6f42c1;
--purple: #7c47b9;
--pink: #e83e8c;
--red: #dc3545;
--orange: #fd7e14;
--yellow: #ffc107;
--yellow: #cdae02;
--green: #28a745;
--teal: #20c997;
--cyan: #17a2b8;
@ -13,13 +13,14 @@
--gray: #6c757d;
--gray-dark: #343a40;
--primary: #007aa6;
--secondary: #a8b3bc;
--secondary: #b3bcc483;
--success: #32ba89;
--info: #007aa6;
--warning: #c97539;
--danger: #b84040;
--light: #fff;
--dark: #f8fafe;
--text: #3b445e;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;

@ -4,8 +4,8 @@
--purple: #6f42c1;
--pink: #e83e8c;
--red: #dc3545;
--orange: #fd7e14;
--yellow: #ffc107;
--orange: #fd7e17;
--yellow: #cdae02;
--green: #28a745;
--teal: #20c997;
--cyan: #17a2b8;
@ -16,10 +16,11 @@
--secondary: #e2f5f2;
--success: #01670f;
--info: #69c7e9;
--warning: #edc464;
--warning: #f5ba30;
--danger: #E64F29;
--light: #eeede9;
--dark: #01414E;
--text: #11556c;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;

@ -524,7 +524,8 @@ class Blockchain extends Plugin {
if (execResult) {
// if it's not the VM, we don't have return value. We only have the transaction, and it does not contain the return value.
returnValue = execResult ? execResult.returnValue : toBuffer(addHexPrefix(txResult.result) || '0x0000000000000000000000000000000000000000000000000000000000000000')
const vmError = txExecution.checkVMError(execResult, args.data.contractABI, args.data.contract)
const compiledContracts = await this.call('compilerArtefacts', 'getAllContractDatas')
const vmError = txExecution.checkVMError(execResult, compiledContracts)
if (vmError.error) {
return cb(vmError.message)
}

@ -8,16 +8,6 @@ export class FramingService {
}
start (params) {
this.sidePanel.events.on('toggle', () => {
this.resizeFeature.panel.clientWidth !== 0 ? this.resizeFeature.hidePanel() : this.resizeFeature.showPanel()
})
this.sidePanel.events.on('showing', () => {
if (this.resizeFeature.panel.clientWidth === 0) this.resizeFeature.showPanel()
})
this.mainPanel.events.on('toggle', () => {
this.resizeFeature.showPanel()
})
this.verticalIcons.select('filePanel')
document.addEventListener('keypress', (e) => {

@ -56,6 +56,7 @@
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.7.0/introjs.min.css">
</head>
<body>
<div id="root"></div>
<script>
function urlParams () {
var qs = window.location.hash.substr(1)

@ -1,10 +0,0 @@
'use strict'
// require('@babel/polyfill')
var App = require('./app.js')
var app = new App({})
document.body.appendChild(app.render())
app.init() // @TODO: refactor to remove

@ -0,0 +1,16 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import ReactDOM from 'react-dom'
import AppComponent from './app'
// eslint-disable-next-line no-unused-vars
import { RemixApp } from '@remix-ui/app'
const appComponent = new AppComponent()
appComponent.run()
ReactDOM.render(
<React.StrictMode>
<RemixApp app={appComponent}></RemixApp>
</React.StrictMode>,
document.getElementById('root')
)

@ -56,6 +56,7 @@
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.7.0/introjs.min.css">
</head>
<body>
<div id="root"></div>
<script>
function urlParams () {
var qs = window.location.hash.substr(1)

@ -11,7 +11,7 @@ const requiredModules = [ // services + layout views + system views
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons',
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic']
const dependentModules = ['git', 'hardhat'] // module which shouldn't be manually activated (e.g git is activated by remixd)
const dependentModules = ['git', 'hardhat', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd)
export function isNative (name) {
const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting']

@ -1,11 +1,26 @@
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
const introJs = require('intro.js')
export class WalkthroughService {
constructor (params) {
this.params = params
const profile = {
name: 'walkthrough',
displayName: 'Walkthrough',
description: '',
version: packageJson.version,
methods: ['start']
}
start (params) {
export class WalkthroughService extends Plugin {
constructor (appManager, showMatamo) {
super(profile)
appManager.event.on('activate', (plugin) => {
if (plugin.name === 'udapp' && !showMatamo) {
this.start()
}
})
}
start () {
if (!localStorage.getItem('hadTour_initial')) {
introJs().setOptions({
steps: [{
@ -24,7 +39,7 @@ export class WalkthroughService {
},
{
title: 'Deploy your contract',
element: document.querySelector('#runIcons'),
element: document.querySelector('#verticalIconsKindudapp'),
intro: 'Choose a chain, deploy a contract and play with your functions.',
tooltipClass: 'bg-light text-dark',
position: 'right'
@ -48,7 +63,4 @@ export class WalkthroughService {
localStorage.setItem('hadTour_initial', true)
}
}
startFeatureTour () {
}
}

@ -34,6 +34,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head>
<body>
<div id="root"></div>
<script>
function urlParams () {
var qs = window.location.hash.substr(1)

@ -5,7 +5,8 @@
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"types": ["node", "jest"]
"types": ["node", "jest"],
"module": "es6",
},
"files": [
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",

@ -1,5 +1,6 @@
const nxWebpack = require('@nrwl/react/plugins/webpack')
const TerserPlugin = require('terser-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = config => {
const nxWebpackConfig = nxWebpack(config)
@ -12,7 +13,15 @@ module.exports = config => {
net: 'empty',
module: 'empty',
child_process: 'empty'
}
},
plugins: [
...nxWebpackConfig.plugins,
new CopyWebpackPlugin({
patterns: [
{ from: '../../../node_modules/monaco-editor/dev/vs/', to: 'assets/js/monaco-editor/dev/vs' }
].filter(Boolean)
})
]
}
if (process.env.NODE_ENV === 'production') {

@ -1,4 +1,5 @@
import React, { useState, useEffect } from 'react';
/* eslint-disable no-use-before-define */
import React from 'react'
import { SolidityCompiler } from '@remix-ui/solidity-compiler' // eslint-disable-line
@ -11,7 +12,7 @@ export const App = () => {
<div>
<SolidityCompiler api={remix} />
</div>
);
};
)
}
export default App;
export default App

@ -7,6 +7,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
contractMap: {
file: string
} | Record<string, any>
compileErrors: any
compileTabLogic: CompileTabLogic
contractsDetails: Record<string, any>
@ -143,7 +144,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
// This function is used for passing the compiler configuration to 'remix-tests'
getCurrentCompilerConfig () {
const compilerState = this.getCompilerState()
let compilerDetails: any = {
const compilerDetails: any = {
currentVersion: compilerState.currentVersion,
evmVersion: compilerState.evmVersion,
optimize: compilerState.optimize,
@ -292,7 +293,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
// Run the compiler instead of trying to save the website
this.data.eventHandlers.onKeyDown = (e) => {
// ctrl+s or command+s
if ((e.metaKey || e.ctrlKey) && e.keyCode === 83) {
if ((e.metaKey || e.ctrlKey) && e.keyCode === 83 && this.currentFile !== '') {
e.preventDefault()
this.compileTabLogic.runCompiler(this.getAppParameter('hardhat-compilation'))
}

@ -1,5 +1,7 @@
import { PluginClient } from "@remixproject/plugin";
import { createClient } from "@remixproject/plugin-webview";
/* eslint-disable no-undef */
/* eslint-disable no-unused-vars */
import { PluginClient } from '@remixproject/plugin'
import { createClient } from '@remixproject/plugin-webview'
import { CompilerApiMixin } from './compiler-api'
import { ICompilerApi } from '@remix-project/remix-lib-ts'
import { CompileTabLogic } from '@remix-ui/solidity-compiler'
@ -42,11 +44,11 @@ export class CompilerClientApi extends CompilerApiMixin(PluginClient) implements
getCompilerParameters () {
const params = {
runs: localStorage.getItem('runs') || defaultCompilerParameters['runs'],
optimize: localStorage.getItem('optimize') === 'true' ? true : false,
version: localStorage.getItem('version') || defaultCompilerParameters['version'],
evmVersion: localStorage.getItem('evmVersion') || defaultCompilerParameters['evmVersion'], // default
language: localStorage.getItem('language') || defaultCompilerParameters['language']
runs: localStorage.getItem('runs') || defaultCompilerParameters.runs,
optimize: localStorage.getItem('optimize') === 'true',
version: localStorage.getItem('version') || defaultCompilerParameters.version,
evmVersion: localStorage.getItem('evmVersion') || defaultCompilerParameters.evmVersion, // default
language: localStorage.getItem('language') || defaultCompilerParameters.language
}
return params
}

@ -1,3 +1,3 @@
export const environment = {
production: true
};
}

@ -3,4 +3,4 @@
export const environment = {
production: false
};
}

@ -1 +1 @@
export * from './app/compiler-api';
export * from './app/compiler-api'

@ -1,11 +1,12 @@
import React from 'react';
import ReactDOM from 'react-dom';
// eslint-disable-next-line no-use-before-define
import React from 'react'
import ReactDOM from 'react-dom'
import App from './app/app';
import App from './app/app'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
)

@ -3,5 +3,5 @@
*
* See: https://github.com/zloirock/core-js#babel
*/
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import 'core-js/stable'
import 'regenerator-runtime/runtime'

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-analyzer",
"version": "0.5.17",
"version": "0.5.18",
"description": "Tool to perform static analysis on Solidity smart contracts",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -22,11 +22,12 @@
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.38",
"@remix-project/remix-lib": "^0.5.8",
"@remix-project/remix-astwalker": "^0.0.39",
"@remix-project/remix-lib": "^0.5.9",
"async": "^2.6.2",
"ethereumjs-util": "^7.0.10",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
"string-similarity": "^4.0.4",
"web3": "^1.5.1"
},
@ -51,5 +52,5 @@
"typescript": "^3.7.5"
},
"typings": "src/index.d.ts",
"gitHead": "13f961dadacea374de4d79a70b1aa4acf243b18b"
"gitHead": "8c5ee47b5a7d05ebd435ff9d443b57ea439eaf78"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-astwalker",
"version": "0.0.38",
"version": "0.0.39",
"description": "Tool to walk through Solidity AST",
"main": "src/index.js",
"scripts": {
@ -37,11 +37,12 @@
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.8",
"@remix-project/remix-lib": "^0.5.9",
"@types/tape": "^4.2.33",
"async": "^2.6.2",
"ethereumjs-util": "^7.0.10",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
"nyc": "^13.3.0",
"string-similarity": "^4.0.4",
"tape": "^4.10.1",
@ -53,5 +54,5 @@
"tap-spec": "^5.0.0"
},
"typings": "src/index.d.ts",
"gitHead": "13f961dadacea374de4d79a70b1aa4acf243b18b"
"gitHead": "8c5ee47b5a7d05ebd435ff9d443b57ea439eaf78"
}

@ -4,7 +4,7 @@ import { CompilerAbstract } from '@remix-project/remix-solidity'
const profile = {
name: 'compilerArtefacts',
methods: ['get', 'addResolvedContract', 'getCompilerAbstract'],
methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas'],
events: [],
version: '0.0.1'
}

@ -67,11 +67,9 @@ export class FetchAndCompile extends Plugin {
}
}
let name = network.name.toLowerCase()
name = name === 'main' ? 'mainnet' : name // source-verifier api expect "mainnet" and not "main"
let data
try {
data = await this.call('source-verification', 'fetchByNetwork', contractAddress, name.toLowerCase())
data = await this.call('source-verification', 'fetchByNetwork', contractAddress, network.id)
} catch (e) {
setTimeout(_ => this.emit('notFound', contractAddress), 0) // plugin framework returns a time out error although it actually didn't find the source...
this.unresolvedAddresses.push(contractAddress)
@ -84,7 +82,7 @@ export class FetchAndCompile extends Plugin {
}
// set the solidity contract code using metadata
await this.call('fileManager', 'setFile', `${targetPath}/${name}/${contractAddress}/metadata.json`, JSON.stringify(data.metadata, null, '\t'))
await this.call('fileManager', 'setFile', `${targetPath}/${network.id}/${contractAddress}/metadata.json`, JSON.stringify(data.metadata, null, '\t'))
const compilationTargets = {}
for (let file in data.metadata.sources) {
const urls = data.metadata.sources[file].urls
@ -96,7 +94,7 @@ export class FetchAndCompile extends Plugin {
// nothing to do, the compiler callback will handle those
} else {
file = file.replace('browser/', '') // should be fixed in the remix IDE end.
const path = `${targetPath}/${name}/${contractAddress}/${file}`
const path = `${targetPath}/${network.id}/${contractAddress}/${file}`
await this.call('fileManager', 'setFile', path, source.content)
compilationTargets[path] = { content: source.content }
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-debug",
"version": "0.5.8",
"version": "0.5.9",
"description": "Tool to debug Ethereum transactions",
"contributors": [
{
@ -22,9 +22,9 @@
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.38",
"@remix-project/remix-lib": "^0.5.8",
"@remix-project/remix-simulator": "^0.2.8",
"@remix-project/remix-astwalker": "^0.0.39",
"@remix-project/remix-lib": "^0.5.9",
"@remix-project/remix-simulator": "^0.2.9",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"color-support": "^1.1.3",
@ -32,6 +32,7 @@
"deep-equal": "^1.0.1",
"ethereumjs-util": "^7.0.10",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
"express-ws": "^4.0.0",
"merge": "^2.1.1",
"string-similarity": "^4.0.4",
@ -67,5 +68,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts",
"gitHead": "13f961dadacea374de4d79a70b1aa4acf243b18b"
"gitHead": "8c5ee47b5a7d05ebd435ff9d443b57ea439eaf78"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-lib",
"version": "0.5.8",
"version": "0.5.9",
"description": "Library to various Remix tools",
"contributors": [
{
@ -54,5 +54,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts",
"gitHead": "13f961dadacea374de4d79a70b1aa4acf243b18b"
"gitHead": "8c5ee47b5a7d05ebd435ff9d443b57ea439eaf78"
}

@ -57,7 +57,7 @@ export function callFunction (from, to, data, value, gasLimit, funAbi, txRunner,
* @param {Object} execResult - execution result given by the VM
* @return {Object} - { error: true/false, message: DOMNode }
*/
export function checkVMError (execResult, abi, contract) {
export function checkVMError (execResult, compiledContracts) {
const errorCode = {
OUT_OF_GAS: 'out of gas',
STACK_UNDERFLOW: 'stack underflow',
@ -91,9 +91,12 @@ export function checkVMError (execResult, abi, contract) {
const returnData = execResult.returnValue
const returnDataHex = returnData.slice(0, 4).toString('hex')
let customError
if (abi) {
if (compiledContracts) {
let decodedCustomErrorInputsClean
for (const item of abi) {
for (const file of Object.keys(compiledContracts)) {
for (const contractName of Object.keys(compiledContracts[file])) {
const contract = compiledContracts[file][contractName]
for (const item of contract.abi) {
if (item.type === 'error') {
// ethers doesn't crash anymore if "error" type is specified, but it doesn't extract the errors. see:
// https://github.com/ethers-io/ethers.js/commit/bd05aed070ac9e1421a3e2bff2ceea150bedf9b7
@ -114,13 +117,13 @@ export function checkVMError (execResult, abi, contract) {
const functionSignature = Object.keys(fn.functions)[0]
// we check in the 'devdoc' if there's a developer documentation for this error
try {
devdoc = (contract.object.devdoc.errors && contract.object.devdoc.errors[functionSignature][0]) || {}
devdoc = (contract.devdoc.errors && contract.devdoc.errors[functionSignature][0]) || {}
} catch (e) {
console.error(e.message)
}
// we check in the 'userdoc' if there's an user documentation for this error
try {
const userdoc = (contract.object.userdoc.errors && contract.object.userdoc.errors[functionSignature][0]) || {}
const userdoc = (contract.userdoc.errors && contract.userdoc.errors[functionSignature][0]) || {}
if (userdoc && (userdoc as any).notice) customError += ' : ' + (userdoc as any).notice // we append the user doc if any
} catch (e) {
console.error(e.message)
@ -143,6 +146,8 @@ export function checkVMError (execResult, abi, contract) {
}
}
}
}
}
if (decodedCustomErrorInputsClean) {
msg = '\tThe transaction has been reverted to the initial state.\nError provided by the contract:'
msg += `\n${customError}`

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-simulator",
"version": "0.2.8",
"version": "0.2.9",
"description": "Ethereum IDE and tools for the web",
"contributors": [
{
@ -18,7 +18,7 @@
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.8",
"@remix-project/remix-lib": "^0.5.9",
"ansi-gray": "^0.1.1",
"async": "^3.1.0",
"body-parser": "^1.18.2",
@ -27,6 +27,7 @@
"cors": "^2.8.5",
"ethereumjs-util": "^7.0.10",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
"express": "^4.16.3",
"express-ws": "^4.0.0",
"merge": "^1.2.0",
@ -66,5 +67,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts",
"gitHead": "13f961dadacea374de4d79a70b1aa4acf243b18b"
"gitHead": "8c5ee47b5a7d05ebd435ff9d443b57ea439eaf78"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-solidity",
"version": "0.4.8",
"version": "0.4.9",
"description": "Tool to load and run Solidity compiler",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -18,11 +18,12 @@
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.8",
"@remix-project/remix-lib": "^0.5.9",
"async": "^2.6.2",
"eslint-scope": "^5.0.0",
"ethereumjs-util": "^7.0.10",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
"minixhr": "^3.2.2",
"semver": "^6.3.0",
"solc": "^0.7.4",
@ -61,5 +62,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts",
"gitHead": "13f961dadacea374de4d79a70b1aa4acf243b18b"
"gitHead": "8c5ee47b5a7d05ebd435ff9d443b57ea439eaf78"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-tests",
"version": "0.2.8",
"version": "0.2.9",
"description": "Tool to test Solidity smart contracts",
"main": "src/index.js",
"types": "./src/index.d.ts",
@ -39,9 +39,9 @@
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.8",
"@remix-project/remix-simulator": "^0.2.8",
"@remix-project/remix-solidity": "^0.4.8",
"@remix-project/remix-lib": "^0.5.9",
"@remix-project/remix-simulator": "^0.2.9",
"@remix-project/remix-solidity": "^0.4.9",
"ansi-gray": "^0.1.1",
"async": "^2.6.0",
"axios": ">=0.21.1",
@ -51,6 +51,7 @@
"commander": "^2.13.0",
"ethereumjs-util": "^7.0.10",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
"express-ws": "^4.0.0",
"merge": "^1.2.0",
"signale": "^1.4.0",
@ -77,5 +78,5 @@
"typescript": "^3.3.1"
},
"typings": "src/index.d.ts",
"gitHead": "13f961dadacea374de4d79a70b1aa4acf243b18b"
"gitHead": "8c5ee47b5a7d05ebd435ff9d443b57ea439eaf78"
}

@ -0,0 +1,4 @@
{
"presets": ["@nrwl/react/babel"],
"plugins": []
}

@ -0,0 +1,248 @@
{
"rules": {
"array-callback-return": "warn",
"dot-location": ["warn", "property"],
"eqeqeq": ["warn", "smart"],
"new-parens": "warn",
"no-caller": "warn",
"no-cond-assign": ["warn", "except-parens"],
"no-const-assign": "warn",
"no-control-regex": "warn",
"no-delete-var": "warn",
"no-dupe-args": "warn",
"no-dupe-keys": "warn",
"no-duplicate-case": "warn",
"no-empty-character-class": "warn",
"no-empty-pattern": "warn",
"no-eval": "warn",
"no-ex-assign": "warn",
"no-extend-native": "warn",
"no-extra-bind": "warn",
"no-extra-label": "warn",
"no-fallthrough": "warn",
"no-func-assign": "warn",
"no-implied-eval": "warn",
"no-invalid-regexp": "warn",
"no-iterator": "warn",
"no-label-var": "warn",
"no-labels": ["warn", { "allowLoop": true, "allowSwitch": false }],
"no-lone-blocks": "warn",
"no-loop-func": "warn",
"no-mixed-operators": [
"warn",
{
"groups": [
["&", "|", "^", "~", "<<", ">>", ">>>"],
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
],
"allowSamePrecedence": false
}
],
"no-multi-str": "warn",
"no-native-reassign": "warn",
"no-negated-in-lhs": "warn",
"no-new-func": "warn",
"no-new-object": "warn",
"no-new-symbol": "warn",
"no-new-wrappers": "warn",
"no-obj-calls": "warn",
"no-octal": "warn",
"no-octal-escape": "warn",
"no-redeclare": "warn",
"no-regex-spaces": "warn",
"no-restricted-syntax": ["warn", "WithStatement"],
"no-script-url": "warn",
"no-self-assign": "warn",
"no-self-compare": "warn",
"no-sequences": "warn",
"no-shadow-restricted-names": "warn",
"no-sparse-arrays": "warn",
"no-template-curly-in-string": "warn",
"no-this-before-super": "warn",
"no-throw-literal": "warn",
"no-restricted-globals": [
"error",
"addEventListener",
"blur",
"close",
"closed",
"confirm",
"defaultStatus",
"defaultstatus",
"event",
"external",
"find",
"focus",
"frameElement",
"frames",
"history",
"innerHeight",
"innerWidth",
"length",
"location",
"locationbar",
"menubar",
"moveBy",
"moveTo",
"name",
"onblur",
"onerror",
"onfocus",
"onload",
"onresize",
"onunload",
"open",
"opener",
"opera",
"outerHeight",
"outerWidth",
"pageXOffset",
"pageYOffset",
"parent",
"print",
"removeEventListener",
"resizeBy",
"resizeTo",
"screen",
"screenLeft",
"screenTop",
"screenX",
"screenY",
"scroll",
"scrollbars",
"scrollBy",
"scrollTo",
"scrollX",
"scrollY",
"self",
"status",
"statusbar",
"stop",
"toolbar",
"top"
],
"no-unexpected-multiline": "warn",
"no-unreachable": "warn",
"no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true,
"allowTaggedTemplates": true
}
],
"no-unused-labels": "warn",
"no-useless-computed-key": "warn",
"no-useless-concat": "warn",
"no-useless-escape": "warn",
"no-useless-rename": [
"warn",
{
"ignoreDestructuring": false,
"ignoreImport": false,
"ignoreExport": false
}
],
"no-with": "warn",
"no-whitespace-before-property": "warn",
"react-hooks/exhaustive-deps": "warn",
"require-yield": "warn",
"rest-spread-spacing": ["warn", "never"],
"strict": ["warn", "never"],
"unicode-bom": ["warn", "never"],
"use-isnan": "warn",
"valid-typeof": "warn",
"no-restricted-properties": [
"error",
{
"object": "require",
"property": "ensure",
"message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting"
},
{
"object": "System",
"property": "import",
"message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting"
}
],
"getter-return": "warn",
"import/first": "error",
"import/no-amd": "error",
"import/no-webpack-loader-syntax": "error",
"react/forbid-foreign-prop-types": ["warn", { "allowInPropTypes": true }],
"react/jsx-no-comment-textnodes": "warn",
"react/jsx-no-duplicate-props": "warn",
"react/jsx-no-target-blank": "warn",
"react/jsx-no-undef": "error",
"react/jsx-pascal-case": ["warn", { "allowAllCaps": true, "ignore": [] }],
"react/jsx-uses-react": "warn",
"react/jsx-uses-vars": "warn",
"react/no-danger-with-children": "warn",
"react/no-direct-mutation-state": "warn",
"react/no-is-mounted": "warn",
"react/no-typos": "error",
"react/react-in-jsx-scope": "error",
"react/require-render-return": "error",
"react/style-prop-object": "warn",
"react/jsx-no-useless-fragment": "warn",
"jsx-a11y/accessible-emoji": "warn",
"jsx-a11y/alt-text": "warn",
"jsx-a11y/anchor-has-content": "warn",
"jsx-a11y/anchor-is-valid": [
"warn",
{ "aspects": ["noHref", "invalidHref"] }
],
"jsx-a11y/aria-activedescendant-has-tabindex": "warn",
"jsx-a11y/aria-props": "warn",
"jsx-a11y/aria-proptypes": "warn",
"jsx-a11y/aria-role": "warn",
"jsx-a11y/aria-unsupported-elements": "warn",
"jsx-a11y/heading-has-content": "warn",
"jsx-a11y/iframe-has-title": "warn",
"jsx-a11y/img-redundant-alt": "warn",
"jsx-a11y/no-access-key": "warn",
"jsx-a11y/no-distracting-elements": "warn",
"jsx-a11y/no-redundant-roles": "warn",
"jsx-a11y/role-has-required-aria-props": "warn",
"jsx-a11y/role-supports-aria-props": "warn",
"jsx-a11y/scope": "warn",
"react-hooks/rules-of-hooks": "error",
"default-case": "off",
"no-dupe-class-members": "off",
"no-undef": "off",
"@typescript-eslint/consistent-type-assertions": "warn",
"no-array-constructor": "off",
"@typescript-eslint/no-array-constructor": "warn",
"@typescript-eslint/no-namespace": "error",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": [
"warn",
{
"functions": false,
"classes": false,
"variables": false,
"typedefs": false
}
],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{ "args": "none", "ignoreRestSiblings": true }
],
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": "warn"
},
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"jest": true,
"node": true
},
"settings": { "react": { "version": "detect" } },
"plugins": ["import", "jsx-a11y", "react", "react-hooks"],
"extends": ["../../../.eslintrc"],
"ignorePatterns": ["!**/*"]
}

@ -0,0 +1 @@
export { default as RemixApp } from './lib/remix-app/remix-app'

@ -0,0 +1,5 @@
import React from 'react'
const AppContext = React.createContext(null)
export default AppContext

@ -0,0 +1,26 @@
/* dragbar UI */
.dragbar {
display : block;
height : 100%;
position : absolute;
left: 0px;
top: 0px;
width: 0.3em;
z-index: 9999;
}
.overlay {
position: absolute;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
display: block;
z-index: 9998;
}
.dragbar:hover, .dragbar.ondrag{
background-color: var(--secondary);
cursor:col-resize;
}

@ -0,0 +1,53 @@
import React, { useEffect, useState } from 'react'
import Draggable from 'react-draggable'
import './dragbar.css'
interface IRemixDragBarUi {
refObject: React.MutableRefObject<any>;
setHideStatus: (hide: boolean) => void;
hidden: boolean
minWidth: number
}
const DragBar = (props: IRemixDragBarUi) => {
const [dragState, setDragState] = useState<boolean>(false)
const [dragBarPosX, setDragBarPosX] = useState<number>(0)
const [offset, setOffSet] = useState<number>(0)
const nodeRef = React.useRef(null) // fix for strictmode
useEffect(() => {
// arbitrary time out to wait the the UI to be completely done
setTimeout(() => {
setOffSet(props.refObject.current.offsetLeft)
setDragBarPosX(offset + props.refObject.current.offsetWidth)
}, 1000)
}, [])
useEffect(() => {
setDragBarPosX(offset + (props.hidden ? 0 : props.refObject.current.offsetWidth))
}, [props.hidden, offset])
function stopDrag (e: MouseEvent, data: any) {
setDragState(false)
if (data.x < props.minWidth) {
setDragBarPosX(offset)
props.setHideStatus(true)
} else {
props.refObject.current.style.width = (data.x - offset) + 'px'
props.setHideStatus(false)
setDragBarPosX(offset + props.refObject.current.offsetWidth)
}
}
function startDrag () {
setDragState(true)
}
return <>
<div className={`overlay ${dragState ? '' : 'd-none'}`} ></div>
<Draggable nodeRef={nodeRef} position={{ x: dragBarPosX, y: 0 }} onStart={startDrag} onStop={stopDrag} axis="x">
<div ref={nodeRef} className={`dragbar ${dragState ? 'ondrag' : ''}`}></div>
</Draggable>
</>
}
export default DragBar

@ -0,0 +1,43 @@
import React, { useEffect, useState } from 'react'
import { ModalDialog } from '@remix-ui/modal-dialog'
const AlertModal = () => {
const [visible, setVisible] = useState<boolean>(true)
const [content, setContent] = useState<string>('')
useEffect(() => {
// check the origin and warn message
if (window.location.hostname === 'yann300.github.io') {
setContent('This UNSTABLE ALPHA branch of Remix has been moved to http://ethereum.github.io/remix-live-alpha.')
} else if (window.location.hostname === 'remix-alpha.ethereum.org' ||
(window.location.hostname === 'ethereum.github.io' && window.location.pathname.indexOf('/remix-live-alpha') === 0)) {
setContent('Welcome to the Remix alpha instance. Please use it to try out latest features. But use preferably https://remix.ethereum.org for any production work.')
} else if (window.location.protocol.indexOf('http') === 0 &&
window.location.hostname !== 'remix.ethereum.org' &&
window.location.hostname !== 'localhost' &&
window.location.hostname !== '127.0.0.1') {
setContent(`The Remix IDE has moved to http://remix.ethereum.org.\n
This instance of Remix you are visiting WILL NOT BE UPDATED.\n
Please make a backup of your contracts and start using http://remix.ethereum.org`)
}
setVisible(content !== '')
}, [])
const closeModal = async () => {
setVisible(false)
}
const handleModalOkClick = async () => {
setVisible(false)
}
return (<ModalDialog
handleHide={closeModal}
id="appAlert"
hide={!visible}
title="Alert"
okLabel="Ok"
okFn={ handleModalOkClick }
cancelLabel=""
cancelFn={closeModal}>{content}</ModalDialog>)
}
export default AlertModal

@ -0,0 +1,51 @@
import React, { useContext, useEffect, useState } from 'react'
import { ModalDialog } from '@remix-ui/modal-dialog'
import AppContext from '../context/context'
const _paq = window._paq = window._paq || []
const MatomoDialog = (props) => {
const { settings, showMatamo, appManager } = useContext(AppContext)
const [visible, setVisible] = useState<boolean>(props.hide)
useEffect(() => {
if (showMatamo) {
setVisible(true)
} else {
setVisible(false)
}
}, [])
const declineModal = async () => {
settings.updateMatomoAnalyticsChoice(false)
_paq.push(['optUserOut'])
appManager.call('walkthrough', 'start')
setVisible(false)
}
const hideModal = async () => {
setVisible(false)
}
const handleModalOkClick = async () => {
_paq.push(['forgetUserOptOut'])
// @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used
document.cookie = 'mtm_consent_removed=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
settings.updateMatomoAnalyticsChoice(true)
appManager.call('walkthrough', 'start')
setVisible(false)
}
return (<ModalDialog
handleHide={hideModal}
id="matomoDialog"
hide={!visible}
title="Help us to improve Remix IDE"
okLabel="Accept"
okFn={ handleModalOkClick }
cancelLabel="Decline"
cancelFn={declineModal}>
<p>An Opt-in version of <a href="https://matomo.org" target="_blank" rel="noreferrer">Matomo</a>, an open source data analytics platform is being used to improve Remix IDE.</p>
<p>We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.</p>
<p>All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public: <a href="https://matomo.ethereum.org/index.php?module=MultiSites&action=index&idSite=23&period=day&date=yesterday" target="_blank" rel="noreferrer">take a look</a>.</p>
<p>We do not collect nor store any personally identifiable information (PII).</p>
<p>For more info, see: <a href="https://medium.com/p/66ef69e14931/" target="_blank" rel="noreferrer">Matomo Analyitcs on Remix iDE</a>.</p>
<p>You can change your choice in the Settings panel anytime.</p>
</ModalDialog>)
}
export default MatomoDialog

@ -0,0 +1,16 @@
import React from 'react'
const RemixSplashScreen = (props) => {
return (<> <div style={{ display: props.hide ? 'none' : 'block' }} className='centered'>
<svg id="Ebene_2" data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105 100">
<path d="M91.84,35a.09.09,0,0,1-.1-.07,41,41,0,0,0-79.48,0,.09.09,0,0,1-.1.07C9.45,35,1,35.35,1,42.53c0,8.56,1,16,6,20.32,2.16,1.85,5.81,2.3,9.27,2.22a44.4,44.4,0,0,0,6.45-.68.09.09,0,0,0,.06-.15A34.81,34.81,0,0,1,17,45c0-.1,0-.21,0-.31a35,35,0,0,1,70,0c0,.1,0,.21,0,.31a34.81,34.81,0,0,1-5.78,19.24.09.09,0,0,0,.06.15,44.4,44.4,0,0,0,6.45.68c3.46.08,7.11-.37,9.27-2.22,5-4.27,6-11.76,6-20.32C103,35.35,94.55,35,91.84,35Z"/>
<path d="M52,74,25.4,65.13a.1.1,0,0,0-.1.17L51.93,91.93a.1.1,0,0,0,.14,0L78.7,65.3a.1.1,0,0,0-.1-.17L52,74A.06.06,0,0,1,52,74Z"/>
<path d="M75.68,46.9,82,45a.09.09,0,0,0,.08-.09,29.91,29.91,0,0,0-.87-6.94.11.11,0,0,0-.09-.08l-6.43-.58a.1.1,0,0,1-.06-.18l4.78-4.18a.13.13,0,0,0,0-.12,30.19,30.19,0,0,0-3.65-6.07.09.09,0,0,0-.11,0l-5.91,2a.1.1,0,0,1-.12-.14L72.19,23a.11.11,0,0,0,0-.12,29.86,29.86,0,0,0-5.84-4.13.09.09,0,0,0-.11,0l-4.47,4.13a.1.1,0,0,1-.17-.07l.09-6a.1.1,0,0,0-.07-.1,30.54,30.54,0,0,0-7-1.47.1.1,0,0,0-.1.07l-2.38,5.54a.1.1,0,0,1-.18,0l-2.37-5.54a.11.11,0,0,0-.11-.06,30,30,0,0,0-7,1.48.12.12,0,0,0-.07.1l.08,6.05a.09.09,0,0,1-.16.07L37.8,18.76a.11.11,0,0,0-.12,0,29.75,29.75,0,0,0-5.83,4.13.11.11,0,0,0,0,.12l2.59,5.6a.11.11,0,0,1-.13.14l-5.9-2a.11.11,0,0,0-.12,0,30.23,30.23,0,0,0-3.62,6.08.11.11,0,0,0,0,.12l4.79,4.19a.1.1,0,0,1-.06.17L23,37.91a.1.1,0,0,0-.09.07A29.9,29.9,0,0,0,22,44.92a.1.1,0,0,0,.07.1L28.4,47a.1.1,0,0,1,0,.18l-5.84,3.26a.16.16,0,0,0,0,.11,30.17,30.17,0,0,0,2.1,6.76c.32.71.67,1.4,1,2.08a.1.1,0,0,0,.06,0L52,68.16H52l26.34-8.78a.1.1,0,0,0,.06-.05,30.48,30.48,0,0,0,3.11-8.88.1.1,0,0,0-.05-.11l-5.83-3.26A.1.1,0,0,1,75.68,46.9Z"/>
</svg>
<div className="info-secondary splash">
REMIX IDE
</div>
</div></>)
}
export default RemixSplashScreen

@ -0,0 +1,90 @@
import React, { useContext, useEffect, useRef, useState } from 'react'
import './style/remix-app.css'
import RemixSplashScreen from './modals/splashscreen'
import MatomoDialog from './modals/matomo'
import AlertModal from './modals/alert'
import AppContext from './context/context'
import DragBar from './dragbar/dragbar'
interface IRemixAppUi {
app: any
}
const RemixApp = (props: IRemixAppUi) => {
const [appReady, setAppReady] = useState<boolean>(false)
const [hideSidePanel, setHideSidePanel] = useState<boolean>(false)
const sidePanelRef = useRef(null)
const mainPanelRef = useRef(null)
const iconPanelRef = useRef(null)
const hiddenPanelRef = useRef(null)
useEffect(() => {
if (sidePanelRef.current) {
if (props.app.sidePanel) {
sidePanelRef.current.appendChild(props.app.sidePanel.render())
}
}
if (mainPanelRef.current) {
if (props.app.mainview) {
mainPanelRef.current.appendChild(props.app.mainview.render())
}
}
if (iconPanelRef.current) {
if (props.app.menuicons) {
iconPanelRef.current.appendChild(props.app.menuicons.render())
}
}
if (hiddenPanelRef.current) {
if (props.app.hiddenPanel) {
hiddenPanelRef.current.appendChild(props.app.hiddenPanel.render())
}
}
async function activateApp () {
props.app.themeModule.initTheme(() => {
setAppReady(true)
props.app.activate()
setListeners()
})
}
if (props.app) {
activateApp()
}
}, [])
function setListeners () {
props.app.sidePanel.events.on('toggle', () => {
setHideSidePanel(prev => {
return !prev
})
})
props.app.sidePanel.events.on('showing', () => {
setHideSidePanel(false)
})
}
const components = {
iconPanel: <div ref={iconPanelRef} id="icon-panel" data-id="remixIdeIconPanel" className="iconpanel bg-light"></div>,
sidePanel: <div ref={sidePanelRef} id="side-panel" data-id="remixIdeSidePanel" className={`sidepanel border-right border-left ${hideSidePanel ? 'd-none' : ''}`}></div>,
mainPanel: <div ref={mainPanelRef} id="main-panel" data-id="remixIdeMainPanel" className='mainpanel'></div>,
hiddenPanel: <div ref={hiddenPanelRef}></div>
}
return (
<AppContext.Provider value={{ settings: props.app.settings, showMatamo: props.app.showMatamo, appManager: props.app.appManager }}>
<RemixSplashScreen hide={appReady}></RemixSplashScreen>
<AlertModal></AlertModal>
<MatomoDialog hide={!appReady}></MatomoDialog>
<div className={`remixIDE ${appReady ? '' : 'd-none'}`} data-id="remixIDE">
{components.iconPanel}
{components.sidePanel}
<DragBar minWidth={250} refObject={sidePanelRef} hidden={hideSidePanel} setHideStatus={setHideSidePanel}></DragBar>
{components.mainPanel}
</div>
{components.hiddenPanel}
</AppContext.Provider>
)
}
export default RemixApp

@ -0,0 +1,71 @@
html { box-sizing: border-box; }
*, *:before, *:after { box-sizing: inherit; }
body {
/* font: 14px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; */
font-size : .8rem;
}
pre {
overflow-x: auto;
}
.remixIDE {
width : 100vw;
height : 100vh;
overflow : hidden;
flex-direction : row;
display : flex;
}
.mainpanel {
display : flex;
flex-direction : column;
overflow : hidden;
flex : 1;
min-width : 320px;
}
.iconpanel {
display : flex;
flex-direction : column;
overflow : hidden;
width : 50px;
user-select : none;
}
.sidepanel {
display : flex;
flex-direction : row-reverse;
width: 320px;
}
.highlightcode {
position : absolute;
z-index : 20;
background-color : var(--info);
}
.highlightcode_fullLine {
position : absolute;
z-index : 20;
background-color : var(--info);
opacity : 0.5;
}
.centered {
position : fixed;
top : 20%;
left : 45%;
width : 200px;
height : 200px;
}
.centered svg path {
fill: var(--secondary);
}
.centered svg polygon {
fill : var(--secondary);
}
.onboarding {
color : var(--text-info);
background-color : var(--info);
}
.matomoBtn {
width : 100px;
}
.splash {
text-align: center;
}

@ -0,0 +1,19 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

@ -0,0 +1,13 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../../node_modules/@nrwl/react/typings/image.d.ts"
],
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}

@ -0,0 +1,15 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"**/*.spec.ts",
"**/*.spec.tsx",
"**/*.spec.js",
"**/*.spec.jsx",
"**/*.d.ts"
]
}

@ -9,4 +9,4 @@ module.exports = {
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
coverageDirectory: '../../../coverage/libs/remix-ui/clipboard'
};
}

@ -1 +1 @@
export * from './lib/copy-to-clipboard/copy-to-clipboard';
export * from './lib/copy-to-clipboard/copy-to-clipboard'

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save