From 8b18d1088da1808e631cb4a99340ad1ead45ce57 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 2 Aug 2022 12:21:44 +0200 Subject: [PATCH] add e2e test --- .circleci/config.yml | 54 ++++++++++- apps/remix-ide-e2e/src/helpers/init.ts | 17 +++- apps/remix-ide-e2e/src/tests/vyper_api.ts | 96 +++++++++++++++++++ .../ci/browser_tests_vyper_plugin.sh | 25 +++++ apps/remix-ide/src/remixAppManager.js | 6 +- apps/vyper/src/app/app.tsx | 6 +- .../src/app/components/CompilerButton.tsx | 2 +- apps/vyper/src/app/components/VyperResult.tsx | 4 +- workspace.json | 2 +- 9 files changed, 200 insertions(+), 12 deletions(-) create mode 100644 apps/remix-ide-e2e/src/tests/vyper_api.ts create mode 100755 apps/remix-ide/ci/browser_tests_vyper_plugin.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 988b8940ea..4c24890cab 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,10 +35,10 @@ jobs: key: v1-deps-{{ checksum "yarn.lock" }} paths: - node_modules - - run: yarn run downloadsolc_assets + - run: yarn run downloadsolc_assets - run: npx nx build remix-ide - run: npx nx build remix-ide-e2e-src-local-plugin - + - run: yarn run build:libs - run: mkdir persist && zip -r persist/dist.zip dist - persist_to_workspace: @@ -266,6 +266,50 @@ jobs: path: ./reports/tests - store_artifacts: path: ./reports/screenshots + + remix-ide-vyper-plugin: + docker: + # specify the version you desire here + - image: cimg/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: 10 + steps: + - browser-tools/install-chrome + - browser-tools/install-chromedriver + - run: + command: | + google-chrome --version + chromedriver --version + java -jar /usr/local/bin/selenium.jar --version + name: Check install + - checkout + - checkout + - attach_workspace: + at: . + - run: unzip ./persist/dist.zip + - restore_cache: + keys: + - v1-deps-{{ checksum "yarn.lock" }} + - run: yarn install + - run: + name: Start Selenium + command: java -jar /usr/local/bin/selenium.jar + background: true + - run: npx nx build vyper + - run: ./apps/remix-ide/ci/browser_tests_vyper_plugin.sh + - store_test_results: + path: ./reports/tests + - store_artifacts: + path: ./reports/screenshots remix-ide-plugin-api: docker: @@ -420,6 +464,9 @@ workflows: - remix-ide-plugin-api: requires: - build + - remix-ide-vyper-plugin: + requires: + - build - remix-ide-chrome: requires: - build @@ -433,6 +480,7 @@ workflows: - remix-ide-chrome - remix-ide-firefox - remix-ide-plugin-api + - remix-ide-vyper-plugin filters: branches: only: remix_live @@ -443,6 +491,7 @@ workflows: - remix-ide-chrome - remix-ide-firefox - remix-ide-plugin-api + - remix-ide-vyper-plugin filters: branches: only: master @@ -453,6 +502,7 @@ workflows: - remix-ide-chrome - remix-ide-firefox - remix-ide-plugin-api + - remix-ide-vyper-plugin filters: branches: only: remix_beta diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index 8b56b54b5a..8bc3ab8eda 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -2,13 +2,28 @@ import { NightwatchBrowser } from 'nightwatch' require('dotenv').config() -export default function (browser: NightwatchBrowser, callback: VoidFunction, url?: string, preloadPlugins = true): void { +type LoadPlugin = { + name: string + url: string +} + +export default function (browser: NightwatchBrowser, callback: VoidFunction, url?: string, preloadPlugins = true, loadPlugin?: LoadPlugin): void { browser .url(url || 'http://127.0.0.1:8080') .pause(6000) .switchBrowserTab(0) .waitForElementVisible('[id="remixTourSkipbtn"]') .click('[id="remixTourSkipbtn"]') + .perform((done) => { + if (!loadPlugin) return done() + browser.execute(function (loadPlugin) { // override a plugin url for testing purpose + localStorage.setItem('test-plugin-name', loadPlugin.name) + localStorage.setItem('test-plugin-url', loadPlugin.url) + }, [loadPlugin]) + .refresh() + .pause(6000) + .perform(done) + }) .maximizeWindow() .fullscreenWindow(() => { if (preloadPlugins) { diff --git a/apps/remix-ide-e2e/src/tests/vyper_api.ts b/apps/remix-ide-e2e/src/tests/vyper_api.ts new file mode 100644 index 0000000000..f168372963 --- /dev/null +++ b/apps/remix-ide-e2e/src/tests/vyper_api.ts @@ -0,0 +1,96 @@ +'use strict' +import { NightwatchBrowser } from 'nightwatch' +import init from '../helpers/init' + +declare global { + interface Window { testplugin: { name: string, url: string }; } +} + +module.exports = { + '@disabled': true, + before: function (browser: NightwatchBrowser, done: VoidFunction) { + init(browser, done, null, true, { name: 'vyper', url: 'http://127.0.0.1:5002'}) + }, + + 'Should connect to vyper plugin #group1': function (browser: NightwatchBrowser) { + browser.clickLaunchIcon('pluginManager') + .scrollAndClick('[data-id="pluginManagerComponentActivateButtonvyper"]') + .clickLaunchIcon('vyper') + .pause(5000) + // @ts-ignore + .frame(0) + }, + + 'Should add the Ballot.vy #group1': function (browser: NightwatchBrowser) { + browser.click('button[data-id="add-ballot"]') + .frameParent() + .openFile('ballot.vy') + }, + + 'Compile ballot.vy should error #group1': function (browser: NightwatchBrowser) { + browser.clickLaunchIcon('vyper') + // @ts-ignore + .frame(0) + .click('[data-id="remote-compiler"]') + .click('[data-id="compile"]') + .assert.containsText('[data-id="error-message"]', 'unexpected indent') + }, + + 'Compile test contract should success #group1': function (browser: NightwatchBrowser) { + let contractAddress + browser + .frameParent() + .addFile('test.vy', { content: testContract }) + .clickLaunchIcon('vyper') + // @ts-ignore + .frame(0) + .click('[data-id="compile"]') + .frameParent() + .clickLaunchIcon('udapp') + .createContract('') + .clickInstance(0) + .clickFunction('totalPokemonCount - call') + .getAddressAtPosition(0, (address) => { + console.log('Vyper contract ' + address) + contractAddress = address + }) + .perform((done) => { + browser.verifyCallReturnValue(contractAddress, ['0:uint256: 0']) + .perform(() => done()) + }) + } +} + +const testContract = ` +# @version >=0.2.4 <0.3.0 + +DNA_DIGITS: constant(uint256) = 16 +DNA_MODULUS: constant(uint256) = 10 ** DNA_DIGITS +# add HP_LIMIT + +struct Pokemon: + name: String[32] + dna: uint256 + HP: uint256 + matches: uint256 + wins: uint256 + +totalPokemonCount: public(uint256) +pokemonList: HashMap[uint256, Pokemon] + +@pure +@internal +def _generateRandomDNA(_name: String[32]) -> uint256: + random: uint256 = convert(keccak256(_name), uint256) + return random % DNA_MODULUS +# modify _createPokemon +@internal +def _createPokemon(_name: String[32], _dna: uint256, _HP: uint256): + self.pokemonList[self.totalPokemonCount] = Pokemon({ + name: _name, + dna: _dna, + HP: _HP, + matches: 0, + wins: 0 + }) + self.totalPokemonCount += 1` \ No newline at end of file diff --git a/apps/remix-ide/ci/browser_tests_vyper_plugin.sh b/apps/remix-ide/ci/browser_tests_vyper_plugin.sh new file mode 100755 index 0000000000..4c82c9f768 --- /dev/null +++ b/apps/remix-ide/ci/browser_tests_vyper_plugin.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -e + +BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}} +echo "$BUILD_ID" +TEST_EXITCODE=0 + +yarn run serve:production & +npx nx serve vyper & + +sleep 5 + +yarn run build:e2e + +TESTFILES=$(grep -IRiL "\'@disabled\': \?true" "dist/apps/remix-ide-e2e/src/tests" | grep "vyper_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 ] +then + exit 1 +fi diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 332b119542..1bebbc7083 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -146,9 +146,11 @@ export class RemixAppManager extends PluginManager { } } } - return plugins.map(plugin => { + const testPluginName = localStorage.getItem('test-plugin-name') + const testPluginUrl = localStorage.getItem('test-plugin-url') + return plugins.map(plugin => { + if (plugin.name === testPluginName) plugin.url = testPluginUrl return new IframePlugin(plugin) - // return new IframeReactPlugin(plugin) }) } diff --git a/apps/vyper/src/app/app.tsx b/apps/vyper/src/app/app.tsx index 2b06263214..a6ce7c9db9 100644 --- a/apps/vyper/src/app/app.tsx +++ b/apps/vyper/src/app/app.tsx @@ -59,7 +59,7 @@ const App: React.FC = () => { function compilerUrl() { return state.environment === 'remote' - ? 'https://vyper.live/compile' + ? 'https://vyper.remixproject.org/compile' : state.localUrl } @@ -85,10 +85,10 @@ const App: React.FC = () => { type="radio" value={state.environment} > - + Remote Compiler - + Local Compiler diff --git a/apps/vyper/src/app/components/CompilerButton.tsx b/apps/vyper/src/app/components/CompilerButton.tsx index 8c59abf3cb..fb0fb6ff05 100644 --- a/apps/vyper/src/app/components/CompilerButton.tsx +++ b/apps/vyper/src/app/components/CompilerButton.tsx @@ -66,7 +66,7 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) { } return ( - ) diff --git a/apps/vyper/src/app/components/VyperResult.tsx b/apps/vyper/src/app/components/VyperResult.tsx index b6fd49b69f..f550d17370 100644 --- a/apps/vyper/src/app/components/VyperResult.tsx +++ b/apps/vyper/src/app/components/VyperResult.tsx @@ -23,7 +23,7 @@ function VyperResult({ output }: VyperResultProps) { if (!output) return (

No contract compiled yet.

-
@@ -33,7 +33,7 @@ function VyperResult({ output }: VyperResultProps) { return (
-

{output.message}

+

{output.message}

) } diff --git a/workspace.json b/workspace.json index 0f76a94da2..a2eca1cee7 100644 --- a/workspace.json +++ b/workspace.json @@ -1551,7 +1551,7 @@ "builder": "@nrwl/web:dev-server", "options": { "buildTarget": "vyper:build", - "hmr": true + "port": 5002 }, "configurations": { "production": {