From 80587dd670ab2bdb3c132378b8acf963258b2fec Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Mon, 30 Aug 2021 15:34:48 +0530 Subject: [PATCH 01/21] return web3 for failed tests --- libs/remix-tests/src/testRunner.ts | 6 ++++-- libs/remix-tests/src/types.ts | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/remix-tests/src/testRunner.ts b/libs/remix-tests/src/testRunner.ts index ffc2cecde4..dca4a5f748 100644 --- a/libs/remix-tests/src/testRunner.ts +++ b/libs/remix-tests/src/testRunner.ts @@ -322,7 +322,8 @@ export function runTest (testName: string, testObject: any, contractDetails: Com assertMethod, returned: testEvent[3], expected: testEvent[4], - location + location, + web3 } if (hhLogs) resp.hhLogs = hhLogs testCallback(undefined, resp) @@ -373,7 +374,8 @@ export function runTest (testName: string, testObject: any, contractDetails: Com filename: testObject.filename, time: time, errMsg: err.message, - context: testName + context: testName, + web3 } testCallback(undefined, resp) failureNum += 1 diff --git a/libs/remix-tests/src/types.ts b/libs/remix-tests/src/types.ts index 649ee921df..b0d4145dbf 100644 --- a/libs/remix-tests/src/types.ts +++ b/libs/remix-tests/src/types.ts @@ -37,6 +37,7 @@ export interface TestResultInterface { expected?: string | number location?: string hhLogs?: [] + web3?: any } export interface TestCbInterface { (error: Error | null | undefined, result: TestResultInterface) : void; From 48662e068f92e6a256fd7ae6e9e48388ac513b61 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Wed, 1 Sep 2021 13:18:00 +0530 Subject: [PATCH 02/21] sample implementation --- apps/debugger/src/app/debugger-api.ts | 5 +++-- apps/remix-ide/src/app/tabs/test-tab.js | 3 +++ libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx | 12 ++++++------ libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/apps/debugger/src/app/debugger-api.ts b/apps/debugger/src/app/debugger-api.ts index ae75599bec..5e22bf03f7 100644 --- a/apps/debugger/src/app/debugger-api.ts +++ b/apps/debugger/src/app/debugger-api.ts @@ -121,9 +121,10 @@ export const DebuggerApiMixin = (Base) => class extends Base { return await debug.debugger.traceManager.getTrace(hash) } - debug (hash) { + debug (hash, web3?) { this.debugHash = hash - if (this.onDebugRequestedListener) this.onDebugRequestedListener(hash) + if(web3) remixDebug.init.extendWeb3(web3) + if (this.onDebugRequestedListener) this.onDebugRequestedListener(hash, web3) } onActivation () { diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index 030745e5d1..368128823e 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -240,6 +240,9 @@ module.exports = class TestTab extends ViewPlugin { `) } else if (result.type === 'testFailure') { + const txHash = JSON.parse(result.errMsg.replace('Transaction has been reverted by the EVM:', '')).transactionHash + this.call('menuicons', 'select', 'debugger') + this.call('debugger', 'debug', txHash, result.web3) if (result.hhLogs && result.hhLogs.length) this.printHHLogs(result.hhLogs, result.value) if (!result.assertMethod) { this.testsOutput.appendChild(yo` diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx index e79ad8910c..9324e2e409 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -39,8 +39,8 @@ export const DebuggerUI = (props: DebuggerUIProps) => { return unLoad() }, []) - debuggerModule.onDebugRequested((hash) => { - if (hash) debug(hash) + debuggerModule.onDebugRequested((hash, web3?) => { + if (hash) debug(hash, web3) }) debuggerModule.onRemoveHighlights(async () => { @@ -162,7 +162,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { } }) } - const startDebugging = async (blockNumber, txNumber, tx) => { + const startDebugging = async (blockNumber, txNumber, tx, optWeb3?) => { if (state.debugger) unLoad() if (!txNumber) return setState(prevState => { @@ -181,7 +181,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { return } - const web3 = state.opt.debugWithLocalNode ? await debuggerModule.web3() : await debuggerModule.getDebugWeb3() + const web3 = state.opt.debugWithLocalNode ? await debuggerModule.web3() : ( optWeb3 ? optWeb3 : await debuggerModule.getDebugWeb3()) try { const networkId = await web3.eth.net.getId() _paq.push(['trackEvent', 'debugger', 'startDebugging', networkId]) @@ -259,7 +259,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { } } - const debug = (txHash) => { + const debug = (txHash, web3?) => { setState(prevState => { return { ...prevState, @@ -267,7 +267,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { txNumber: txHash } }) - startDebugging(null, txHash, null) + startDebugging(null, txHash, null, web3) } const stepManager = { diff --git a/libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts b/libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts index 2e57aff5a6..5fa07cb4e8 100644 --- a/libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts +++ b/libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts @@ -45,7 +45,7 @@ export interface TransactionReceipt { export type onBreakpointClearedListener = (params: string, row: number) => void export type onBreakpointAddedListener = (params: string, row: number) => void export type onEditorContentChanged = () => void -export type onDebugRequested = (hash: string) => void +export type onDebugRequested = (hash: string, web3?: any) => void export type onEnvChangedListener = (provider: string) => void export interface IDebuggerApi { From 9cc039ec697cdcc0a82118c3d8758326c3172664 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Wed, 1 Sep 2021 17:28:09 +0530 Subject: [PATCH 03/21] linting fix --- libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx index 9324e2e409..34c355591e 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -181,7 +181,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { return } - const web3 = state.opt.debugWithLocalNode ? await debuggerModule.web3() : ( optWeb3 ? optWeb3 : await debuggerModule.getDebugWeb3()) + const web3 = state.opt.debugWithLocalNode ? await debuggerModule.web3() : (optWeb3 || await debuggerModule.getDebugWeb3()) try { const networkId = await web3.eth.net.getId() _paq.push(['trackEvent', 'debugger', 'startDebugging', networkId]) From 55b30baf5c2e99f3e38afb64d4e55a464c029ead Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Thu, 2 Sep 2021 13:00:50 +0530 Subject: [PATCH 04/21] debug button --- apps/remix-ide/src/app/tabs/test-tab.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index 368128823e..cd4bc81838 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -192,6 +192,13 @@ module.exports = class TestTab extends ViewPlugin { } } + async startDebug (result) { + const txHash = JSON.parse(result.errMsg.replace('Transaction has been reverted by the EVM:', '')).transactionHash + if (!await this.appManager.isActive('debugger')) await this.appManager.activatePlugin('debugger') + this.call('menuicons', 'select', 'debugger') + this.call('debugger', 'debug', txHash, result.web3) + } + printHHLogs (logsArr, testName) { let finalLogs = `${testName}:\n` for (const log of logsArr) { @@ -240,9 +247,6 @@ module.exports = class TestTab extends ViewPlugin { `) } else if (result.type === 'testFailure') { - const txHash = JSON.parse(result.errMsg.replace('Transaction has been reverted by the EVM:', '')).transactionHash - this.call('menuicons', 'select', 'debugger') - this.call('debugger', 'debug', txHash, result.web3) if (result.hhLogs && result.hhLogs.length) this.printHHLogs(result.hhLogs, result.value) if (!result.assertMethod) { this.testsOutput.appendChild(yo` @@ -252,6 +256,13 @@ module.exports = class TestTab extends ViewPlugin { onclick=${() => this.highlightLocation(result.location, runningTests, result.filename)} > ✘ ${result.value} + Error Message: "${result.errMsg}" From 1e9b3fc1015daca37d7e57467f9bf02432c128cd Mon Sep 17 00:00:00 2001 From: lianahus Date: Thu, 2 Sep 2021 13:15:38 +0200 Subject: [PATCH 05/21] debug button in SUT UI --- .../src/app/tabs/styles/test-tab-styles.js | 2 -- apps/remix-ide/src/app/tabs/test-tab.js | 22 ++++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/remix-ide/src/app/tabs/styles/test-tab-styles.js b/apps/remix-ide/src/app/tabs/styles/test-tab-styles.js index b6cce75aeb..2f0ddab770 100644 --- a/apps/remix-ide/src/app/tabs/styles/test-tab-styles.js +++ b/apps/remix-ide/src/app/tabs/styles/test-tab-styles.js @@ -31,8 +31,6 @@ var css = csjs` border-radius: 4px; padding: 1% 1% 1% 5%; } - .testFailure { - } .testFailureSummary { } .title { diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index cd4bc81838..811b668772 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -251,18 +251,20 @@ module.exports = class TestTab extends ViewPlugin { if (!result.assertMethod) { this.testsOutput.appendChild(yo`
this.highlightLocation(result.location, runningTests, result.filename)} > - ✘ ${result.value} - +
+ ✘ ${result.value} +
this.startDebug(result)} + > + +
+
Error Message: "${result.errMsg}"
@@ -273,7 +275,7 @@ module.exports = class TestTab extends ViewPlugin { const expected = result.assertMethod === 'ok' ? '\'true\'' : result.expected this.testsOutput.appendChild(yo`
this.highlightLocation(result.location, runningTests, result.filename)} > From 6edbb46be84c831a41be2135fb43f26cf3e7a544 Mon Sep 17 00:00:00 2001 From: lianahus Date: Thu, 2 Sep 2021 13:43:06 +0200 Subject: [PATCH 06/21] fixed 2 line case --- apps/remix-ide/src/app/tabs/test-tab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index 811b668772..affb22adcc 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -255,7 +255,7 @@ module.exports = class TestTab extends ViewPlugin { id="UTContext${result.context}" onclick=${() => this.highlightLocation(result.location, runningTests, result.filename)} > -
+
✘ ${result.value}
Date: Fri, 3 Sep 2021 12:49:04 +0530 Subject: [PATCH 07/21] save compiler artifacts to show data on debugging --- apps/remix-ide/src/app/tabs/test-tab.js | 15 +- .../src/lib/compiler-artefacts.ts | 5 + libs/remix-tests/src/compiler.ts | 1 + libs/remix-tests/src/index.ts | 2 +- libs/remix-tests/src/lib/eventManager.ts | 68 ++++++ libs/remix-tests/src/runTestSources.ts | 227 +++++++++--------- 6 files changed, 205 insertions(+), 113 deletions(-) create mode 100644 libs/remix-tests/src/lib/eventManager.ts diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index affb22adcc..5d1e62a914 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -7,7 +7,7 @@ var async = require('async') var tooltip = require('../ui/tooltip') var Renderer = require('../ui/renderer') var css = require('./styles/test-tab-styles') -var remixTests = require('@remix-project/remix-tests') +var { UnitTestRunner } = require('@remix-project/remix-tests') const TestTabLogic = require('./testTab/testTab') @@ -33,6 +33,7 @@ module.exports = class TestTab extends ViewPlugin { this.data = {} this.appManager = appManager this.renderer = new Renderer(this) + this.testRunner = new UnitTestRunner() this.hasBeenStopped = false this.runningTestsNumber = 0 this.readyTestsNumber = 0 @@ -95,6 +96,14 @@ module.exports = class TestTab extends ViewPlugin { this.setCurrentPath(this.defaultPath) }) + this.testRunner.event.register('compilationFinished', (success, data, source) => { + if (success) { + // forwarding the event to the appManager infra + // This is listened by compilerArtefacts to show data while debugging + this.emit('compilationFinished', source.target, source, 'soljson', data) + } + }) + this.fileManager.events.on('noFileSelected', () => { }) @@ -462,7 +471,7 @@ module.exports = class TestTab extends ViewPlugin { usingWorker: canUseWorker(currentVersion), runs } - remixTests.runTestSources(runningTest, compilerConfig, () => {}, () => {}, (error, result) => { + this.testRunner.runTestSources(runningTest, compilerConfig, () => {}, () => {}, (error, result) => { if (error) return reject(error) resolve(result) }, (url, cb) => { @@ -489,7 +498,7 @@ module.exports = class TestTab extends ViewPlugin { usingWorker: canUseWorker(currentVersion), runs } - remixTests.runTestSources( + this.testRunner.runTestSources( runningTests, compilerConfig, (result) => this.testCallback(result, runningTests), diff --git a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts index 47eb1d519b..da22ffb39e 100644 --- a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts +++ b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts @@ -52,6 +52,11 @@ export class CompilerArtefacts extends Plugin { this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) saveCompilationPerFileResult(file, source, languageVersion, data) }) + + this.on('solidityUnitTesting', 'compilationFinished', (file, source, languageVersion, data) => { + this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) + saveCompilationPerFileResult(file, source, languageVersion, data) + }) } getAllContractDatas () { diff --git a/libs/remix-tests/src/compiler.ts b/libs/remix-tests/src/compiler.ts index 3cf91bd9fb..3e3c8b85d4 100644 --- a/libs/remix-tests/src/compiler.ts +++ b/libs/remix-tests/src/compiler.ts @@ -205,6 +205,7 @@ export function compileContractSources (sources: SrcIfc, compilerConfig: Compile function doCompilation (next) { // @ts-ignore compiler.event.register('compilationFinished', this, (success, data, source) => { + if (opts && opts.event) opts.event.trigger('compilationFinished', [success, data, source]) next(null, data) }) compiler.compile(sources, filepath) diff --git a/libs/remix-tests/src/index.ts b/libs/remix-tests/src/index.ts index 854db0dcad..9552d5b5ee 100644 --- a/libs/remix-tests/src/index.ts +++ b/libs/remix-tests/src/index.ts @@ -1,5 +1,5 @@ export { runTestFiles } from './runTestFiles' -export { runTestSources } from './runTestSources' +export { UnitTestRunner } from './runTestSources' export { runTest } from './testRunner' export * from './types' export const assertLibCode = require('../sol/tests.sol') diff --git a/libs/remix-tests/src/lib/eventManager.ts b/libs/remix-tests/src/lib/eventManager.ts new file mode 100644 index 0000000000..8282e09b6c --- /dev/null +++ b/libs/remix-tests/src/lib/eventManager.ts @@ -0,0 +1,68 @@ +'use strict' + +export default class EventManager { + registered: any = {} // eslint-disable-line + anonymous: any = {} // eslint-disable-line + + /* + * Unregister a listener. + * Note that if obj is a function. the unregistration will be applied to the dummy obj {}. + * + * @param {String} eventName - the event name + * @param {Object or Func} obj - object that will listen on this event + * @param {Func} func - function of the listeners that will be executed + */ + unregister (eventName: any, obj: any, func: any): void { // eslint-disable-line + if (!this.registered[eventName]) { + return + } + if (obj instanceof Function) { + func = obj + obj = this.anonymous + } + for (const reg in this.registered[eventName]) { + if (this.registered[eventName][reg].obj === obj && this.registered[eventName][reg].func === func) { + this.registered[eventName].splice(reg, 1) + } + } + } + + /* + * Register a new listener. + * Note that if obj is a function, the function registration will be associated with the dummy object {} + * + * @param {String} eventName - the event name + * @param {Object or Func} obj - object that will listen on this event + * @param {Func} func - function of the listeners that will be executed + */ + register (eventName: any, obj: any, func: any): void { // eslint-disable-line + if (!this.registered[eventName]) { + this.registered[eventName] = [] + } + if (obj instanceof Function) { + func = obj + obj = this.anonymous + } + this.registered[eventName].push({ + obj: obj, + func: func + }) + } + + /* + * trigger event. + * Every listener have their associated function executed + * + * @param {String} eventName - the event name + * @param {Array}j - argument that will be passed to the executed function. + */ + trigger (eventName: any, args: any): void { // eslint-disable-line + if (!this.registered[eventName]) { + return + } + for (const listener in this.registered[eventName]) { + const l = this.registered[eventName][listener] + if (l.func) l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) + } + } +} diff --git a/libs/remix-tests/src/runTestSources.ts b/libs/remix-tests/src/runTestSources.ts index 1393148272..78f4b11e69 100644 --- a/libs/remix-tests/src/runTestSources.ts +++ b/libs/remix-tests/src/runTestSources.ts @@ -5,6 +5,7 @@ import { deployAll } from './deployer' import { runTest } from './testRunner' import Web3 from 'web3' +import EventManager from './lib/eventManager' import { Provider, extend } from '@remix-project/remix-simulator' import { FinalResult, SrcIfc, compilationInterface, ASTInterface, Options, @@ -12,126 +13,134 @@ import { } from './types' require('colors') -const createWeb3Provider = async function () { - const web3 = new Web3() - const provider: any = new Provider() - await provider.init() - web3.setProvider(provider) - extend(web3) - return web3 -} +export class UnitTestRunner { + event -/** - * @dev Run tests from source of a test contract file (used for IDE) - * @param contractSources Sources of contract - * @param compilerConfig current compiler configuration - * @param testCallback Test callback - * @param resultCallback Result Callback - * @param finalCallback Final Callback - * @param importFileCb Import file callback - * @param opts Options - */ -export async function runTestSources (contractSources: SrcIfc, compilerConfig: CompilerConfiguration, testCallback, resultCallback, finalCallback: any, importFileCb, opts: Options) { - opts = opts || {} - const sourceASTs: any = {} - const web3 = opts.web3 || await createWeb3Provider() - let accounts: string[] | null = opts.accounts || null - async.waterfall([ - function getAccountList (next) { - if (accounts) return next() - web3.eth.getAccounts((_err, _accounts) => { - accounts = _accounts - next() - }) - }, - function compile (next) { - compileContractSources(contractSources, compilerConfig, importFileCb, { accounts }, next) - }, - function deployAllContracts (compilationResult: compilationInterface, asts: ASTInterface, next) { - for (const filename in asts) { - if (filename.endsWith('_test.sol')) { sourceASTs[filename] = asts[filename].ast } - } - deployAll(compilationResult, web3, false, (err, contracts) => { - if (err) { - // If contract deployment fails because of 'Out of Gas' error, try again with double gas - // This is temporary, should be removed when remix-tests will have a dedicated UI to - // accept deployment params from UI - if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) { - deployAll(compilationResult, web3, true, (error, contracts) => { - if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.message, severity: 'error' }]) // IDE expects errors in array - else next(null, compilationResult, contracts) - }) - } else { next([{ message: 'contract deployment failed: ' + err.message, severity: 'error' }]) } // IDE expects errors in array - } else { next(null, compilationResult, contracts) } - }) - }, - function determineTestContractsToRun (compilationResult: compilationInterface, contracts: any, next) { - const contractsToTest: string[] = [] - const contractsToTestDetails: any[] = [] + constructor() { + this.event = new EventManager() + } + + async createWeb3Provider () { + const web3 = new Web3() + const provider: any = new Provider() + await provider.init() + web3.setProvider(provider) + extend(web3) + return web3 + } - for (const filename in compilationResult) { - if (!filename.endsWith('_test.sol')) { - continue + /** + * @dev Run tests from source of a test contract file (used for IDE) + * @param contractSources Sources of contract + * @param compilerConfig current compiler configuration + * @param testCallback Test callback + * @param resultCallback Result Callback + * @param finalCallback Final Callback + * @param importFileCb Import file callback + * @param opts Options + */ + async runTestSources (contractSources: SrcIfc, compilerConfig: CompilerConfiguration, testCallback, resultCallback, finalCallback: any, importFileCb, opts: Options) { + opts = opts || {} + const sourceASTs: any = {} + const web3 = opts.web3 || await this.createWeb3Provider() + let accounts: string[] | null = opts.accounts || null + async.waterfall([ + function getAccountList (next) { + if (accounts) return next() + web3.eth.getAccounts((_err, _accounts) => { + accounts = _accounts + next() + }) + }, + (next) => { + compileContractSources(contractSources, compilerConfig, importFileCb, { accounts, event: this.event}, next) + }, + function deployAllContracts (compilationResult: compilationInterface, asts: ASTInterface, next) { + for (const filename in asts) { + if (filename.endsWith('_test.sol')) { sourceASTs[filename] = asts[filename].ast } } - Object.keys(compilationResult[filename]).forEach(contractName => { - contractsToTestDetails.push(compilationResult[filename][contractName]) - contractsToTest.push(contractName) + deployAll(compilationResult, web3, false, (err, contracts) => { + if (err) { + // If contract deployment fails because of 'Out of Gas' error, try again with double gas + // This is temporary, should be removed when remix-tests will have a dedicated UI to + // accept deployment params from UI + if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) { + deployAll(compilationResult, web3, true, (error, contracts) => { + if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.message, severity: 'error' }]) // IDE expects errors in array + else next(null, compilationResult, contracts) + }) + } else { next([{ message: 'contract deployment failed: ' + err.message, severity: 'error' }]) } // IDE expects errors in array + } else { next(null, compilationResult, contracts) } }) - } - next(null, contractsToTest, contractsToTestDetails, contracts) - }, - function runTests (contractsToTest: string[], contractsToTestDetails: any[], contracts: any, next) { - let totalPassing = 0 - let totalFailing = 0 - let totalTime = 0 - const errors: any[] = [] - // eslint-disable-next-line handle-callback-err - const _testCallback = function (err: Error | null | undefined, result: TestResultInterface) { - if (result.type === 'testFailure') { - errors.push(result) + }, + function determineTestContractsToRun (compilationResult: compilationInterface, contracts: any, next) { + const contractsToTest: string[] = [] + const contractsToTestDetails: any[] = [] + + for (const filename in compilationResult) { + if (!filename.endsWith('_test.sol')) { + continue + } + Object.keys(compilationResult[filename]).forEach(contractName => { + contractsToTestDetails.push(compilationResult[filename][contractName]) + contractsToTest.push(contractName) + }) + } + next(null, contractsToTest, contractsToTestDetails, contracts) + }, + function runTests (contractsToTest: string[], contractsToTestDetails: any[], contracts: any, next) { + let totalPassing = 0 + let totalFailing = 0 + let totalTime = 0 + const errors: any[] = [] + // eslint-disable-next-line handle-callback-err + const _testCallback = function (err: Error | null | undefined, result: TestResultInterface) { + if (result.type === 'testFailure') { + errors.push(result) + } + testCallback(result) } - testCallback(result) - } - const _resultsCallback = function (_err, result, cb) { - resultCallback(_err, result, () => {}) // eslint-disable-line @typescript-eslint/no-empty-function - totalPassing += result.passingNum - totalFailing += result.failureNum - totalTime += result.timePassed - cb() - } + const _resultsCallback = function (_err, result, cb) { + resultCallback(_err, result, () => {}) // eslint-disable-line @typescript-eslint/no-empty-function + totalPassing += result.passingNum + totalFailing += result.failureNum + totalTime += result.timePassed + cb() + } - async.eachOfLimit(contractsToTest, 1, (contractName: string, index: string | number, cb: ErrorCallback) => { - const fileAST: AstNode = sourceASTs[contracts[contractName]['filename']] - runTest(contractName, contracts[contractName], contractsToTestDetails[index], fileAST, { accounts, web3 }, _testCallback, (err, result) => { + async.eachOfLimit(contractsToTest, 1, (contractName: string, index: string | number, cb: ErrorCallback) => { + const fileAST: AstNode = sourceASTs[contracts[contractName]['filename']] + runTest(contractName, contracts[contractName], contractsToTestDetails[index], fileAST, { accounts, web3 }, _testCallback, (err, result) => { + if (err) { + return cb(err) + } + _resultsCallback(null, result, cb) + }) + }, function (err) { if (err) { - return cb(err) + return next(err) } - _resultsCallback(null, result, cb) - }) - }, function (err) { - if (err) { - return next(err) - } - const finalResults: FinalResult = { - totalPassing: 0, - totalFailing: 0, - totalTime: 0, - errors: [] - } + const finalResults: FinalResult = { + totalPassing: 0, + totalFailing: 0, + totalTime: 0, + errors: [] + } - finalResults.totalPassing = totalPassing || 0 - finalResults.totalFailing = totalFailing || 0 - finalResults.totalTime = totalTime || 0 - finalResults.errors = [] + finalResults.totalPassing = totalPassing || 0 + finalResults.totalFailing = totalFailing || 0 + finalResults.totalTime = totalTime || 0 + finalResults.errors = [] - errors.forEach((error, _index) => { - finalResults.errors.push({ context: error.context, value: error.value, message: error.errMsg }) - }) + errors.forEach((error, _index) => { + finalResults.errors.push({ context: error.context, value: error.value, message: error.errMsg }) + }) - next(null, finalResults) - }) - } - ], finalCallback) + next(null, finalResults) + }) + } + ], finalCallback) + } } From e7b55b6a10cf6c67de151559e62cb9562b88c66b Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Fri, 3 Sep 2021 13:51:01 +0530 Subject: [PATCH 08/21] button improved --- apps/remix-ide/src/app/tabs/test-tab.js | 27 ++++++++++++++++--------- libs/remix-tests/src/runTestSources.ts | 4 ++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index 5d1e62a914..df01998cfd 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -201,11 +201,10 @@ module.exports = class TestTab extends ViewPlugin { } } - async startDebug (result) { - const txHash = JSON.parse(result.errMsg.replace('Transaction has been reverted by the EVM:', '')).transactionHash + async startDebug (txHash, web3) { if (!await this.appManager.isActive('debugger')) await this.appManager.activatePlugin('debugger') this.call('menuicons', 'select', 'debugger') - this.call('debugger', 'debug', txHash, result.web3) + this.call('debugger', 'debug', txHash, web3) } printHHLogs (logsArr, testName) { @@ -258,6 +257,20 @@ module.exports = class TestTab extends ViewPlugin { } else if (result.type === 'testFailure') { if (result.hhLogs && result.hhLogs.length) this.printHHLogs(result.hhLogs, result.value) if (!result.assertMethod) { + let debugBtn = yo`` + if(result.errMsg.includes('Transaction has been reverted by the EVM')) { + const txHash = JSON.parse(result.errMsg.replace('Transaction has been reverted by the EVM:', '')).transactionHash + const { web3 } = result + debugBtn = yo`
this.startDebug(txHash, web3)} + > + +
` + debugBtn.style.visibility = 'visible' + debugBtn.style.cursor = 'pointer' + } else debugBtn.style.visibility = 'hidden' this.testsOutput.appendChild(yo`
✘ ${result.value} -
this.startDebug(result)} - > - -
+ ${debugBtn}
Error Message: "${result.errMsg}" diff --git a/libs/remix-tests/src/runTestSources.ts b/libs/remix-tests/src/runTestSources.ts index 78f4b11e69..1a3e59dce9 100644 --- a/libs/remix-tests/src/runTestSources.ts +++ b/libs/remix-tests/src/runTestSources.ts @@ -16,7 +16,7 @@ require('colors') export class UnitTestRunner { event - constructor() { + constructor () { this.event = new EventManager() } @@ -53,7 +53,7 @@ export class UnitTestRunner { }) }, (next) => { - compileContractSources(contractSources, compilerConfig, importFileCb, { accounts, event: this.event}, next) + compileContractSources(contractSources, compilerConfig, importFileCb, { accounts, event: this.event }, next) }, function deployAllContracts (compilationResult: compilationInterface, asts: ASTInterface, next) { for (const filename in asts) { From b92f1456219907b3e321240e0759d898eceb321d Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Fri, 3 Sep 2021 14:01:07 +0530 Subject: [PATCH 09/21] linting fix --- apps/remix-ide/src/app/tabs/test-tab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index df01998cfd..95d12ad269 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -258,7 +258,7 @@ module.exports = class TestTab extends ViewPlugin { if (result.hhLogs && result.hhLogs.length) this.printHHLogs(result.hhLogs, result.value) if (!result.assertMethod) { let debugBtn = yo`` - if(result.errMsg.includes('Transaction has been reverted by the EVM')) { + if (result.errMsg.includes('Transaction has been reverted by the EVM')) { const txHash = JSON.parse(result.errMsg.replace('Transaction has been reverted by the EVM:', '')).transactionHash const { web3 } = result debugBtn = yo`
Date: Fri, 3 Sep 2021 14:03:21 +0530 Subject: [PATCH 10/21] remix-tests tests fixed --- libs/remix-tests/tests/testRunner.spec.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/remix-tests/tests/testRunner.spec.ts b/libs/remix-tests/tests/testRunner.spec.ts index b025fbfc0c..351daf23f4 100644 --- a/libs/remix-tests/tests/testRunner.spec.ts +++ b/libs/remix-tests/tests/testRunner.spec.ts @@ -131,7 +131,7 @@ describe('testRunner', () => { { type: 'testPass', value: 'Ok pass test', filename: __dirname + '/examples_0/assert_ok_test.sol', context: 'AssertOkTest', hhLogs: hhLogs1 }, { type: 'testFailure', value: 'Ok fail test', filename: __dirname + '/examples_0/assert_ok_test.sol', errMsg: 'okFailTest fails', context: 'AssertOkTest', hhLogs: hhLogs2, assertMethod: 'ok', location: '370:36:0', expected: 'true', returned: 'false'}, - ], ['time']) + ], ['time', 'web3']) }) }) @@ -170,7 +170,7 @@ describe('testRunner', () => { { type: 'testFailure', value: 'Equal bytes32 fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalBytes32FailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1670:48:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6979000000000000000000000000000000000000000000000000000000'}, { type: 'testPass', value: 'Equal string pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' }, { type: 'testFailure', value: 'Equal string fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalStringFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1916:81:0', expected: 'remix-tests', returned: 'remix'} - ], ['time']) + ], ['time', 'web3']) }) }) @@ -209,7 +209,7 @@ describe('testRunner', () => { { type: 'testFailure', value: 'Not equal bytes32 fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualBytes32FailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '1756:54:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6978000000000000000000000000000000000000000000000000000000'}, { type: 'testPass', value: 'Not equal string pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' }, { type: 'testFailure', value: 'Not equal string fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualStringFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '2026:81:0', expected: 'remix', returned: 'remix'}, - ], ['time']) + ], ['time', 'web3']) }) }) @@ -243,7 +243,7 @@ describe('testRunner', () => { { type: 'testFailure', value: 'Greater than uint int fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanUintIntFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '845:71:0', expected: '2', returned: '1'}, { type: 'testPass', value: 'Greater than int uint pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' }, { type: 'testFailure', value: 'Greater than int uint fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanIntUintFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '1125:76:0', expected: '115792089237316195423570985008687907853269984665640564039457584007913129639836', returned: '100'} - ], ['time']) + ], ['time', 'web3']) }) }) @@ -278,7 +278,7 @@ describe('testRunner', () => { { type: 'testFailure', value: 'Lesser than uint int fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanUintIntFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '826:71:0', expected: '-1', returned: '115792089237316195423570985008687907853269984665640564039457584007913129639935'}, { type: 'testPass', value: 'Lesser than int uint pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' }, { type: 'testFailure', value: 'Lesser than int uint fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanIntUintFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '1105:69:0', expected: '1', returned: '1'}, - ], ['time']) + ], ['time', 'web3']) }) }) @@ -309,7 +309,7 @@ describe('testRunner', () => { { type: 'testPass', value: 'Initial value should not be200', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' }, { type: 'testFailure', value: 'Should trigger one fail', filename: __dirname + '/examples_1/simple_storage_test.sol', errMsg: 'uint test 1 fails', context: 'MyTest', assertMethod: 'equal', location: '532:51:1', expected: '2', returned: '1'}, { type: 'testPass', value: 'Should trigger one pass', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' } - ], ['time']) + ], ['time', 'web3']) }) }) @@ -338,7 +338,7 @@ describe('testRunner', () => { { type: 'contract', value: 'MyTest', filename: __dirname + '/examples_2/simple_storage_test.sol' }, { type: 'testPass', value: 'Initial value should be100', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' }, { type: 'testPass', value: 'Value is set200', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' } - ], ['time']) + ], ['time', 'web3']) }) }) @@ -364,7 +364,7 @@ describe('testRunner', () => { { type: 'contract', value: 'StringTest', filename: __dirname + '/examples_3/simple_string_test.sol' }, { type: 'testPass', value: 'Initial value should be hello world', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' }, { type: 'testPass', value: 'Value should not be hello wordl', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' } - ], ['time']) + ], ['time', 'web3']) }) }) @@ -391,7 +391,7 @@ describe('testRunner', () => { { type: 'testPass', value: 'Initial value should be100', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' }, { type: 'testPass', value: 'Check if even', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' }, { type: 'testPass', value: 'Check if odd', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' } - ], ['time']) + ], ['time', 'web3']) }) }) From c17cdb2fba8b257ab0252d033aca9b7a4bd0b162 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Fri, 3 Sep 2021 18:50:14 +0530 Subject: [PATCH 11/21] do not clear test results on file change while debugging --- apps/remix-ide/src/app/tabs/test-tab.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index 95d12ad269..0119425b8e 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -40,6 +40,8 @@ module.exports = class TestTab extends ViewPlugin { this.areTestsRunning = false this.defaultPath = 'tests' this.offsetToLineColumnConverter = offsetToLineColumnConverter + this.allFilesInvolved = [] + this.isDebugging = false appManager.event.on('activate', (name) => { if (name === 'solidity') this.updateRunAction() @@ -98,6 +100,7 @@ module.exports = class TestTab extends ViewPlugin { this.testRunner.event.register('compilationFinished', (success, data, source) => { if (success) { + this.allFilesInvolved = Object.keys(data.sources) // forwarding the event to the appManager infra // This is listened by compilerArtefacts to show data while debugging this.emit('compilationFinished', source.target, source, 'soljson', data) @@ -111,6 +114,9 @@ module.exports = class TestTab extends ViewPlugin { } async updateForNewCurrent (file) { + // if current file is changed while debugging and one of the files imported in test file are opened + // do not clear the test results in SUT plugin + if (this.isDebugging && this.allFilesInvolved.includes(file)) return this.data.allTests = [] this.updateTestFileList() this.clearResults() @@ -202,6 +208,7 @@ module.exports = class TestTab extends ViewPlugin { } async startDebug (txHash, web3) { + this.isDebugging = true if (!await this.appManager.isActive('debugger')) await this.appManager.activatePlugin('debugger') this.call('menuicons', 'select', 'debugger') this.call('debugger', 'debug', txHash, web3) @@ -488,6 +495,7 @@ module.exports = class TestTab extends ViewPlugin { } runTest (testFilePath, callback) { + this.isDebugging = false if (this.hasBeenStopped) { this.updateFinalResult() return From 5064a654dca2db649c548fd89e921b4ff05a3bbc Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Mon, 6 Sep 2021 11:59:01 +0530 Subject: [PATCH 12/21] fix for reopening same file in two tabs in editor --- apps/remix-ide/src/app/tabs/testTab/testTab.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/tabs/testTab/testTab.js b/apps/remix-ide/src/app/tabs/testTab/testTab.js index 7b6e1fd4fc..93cb49516b 100644 --- a/apps/remix-ide/src/app/tabs/testTab/testTab.js +++ b/apps/remix-ide/src/app/tabs/testTab/testTab.js @@ -68,7 +68,8 @@ class TestTabLogic { cb(e.message) } for (var file in files) { - if (/.(_test.sol)$/.exec(file)) tests.push(provider.type + '/' + file) + const filepath = provider && provider.type ? provider.type + '/' + file : file + if (/.(_test.sol)$/.exec(file)) tests.push(filepath) } cb(null, tests, this.currentPath) } From 50def26d133544b0f320670ee8e55e51e98e163d Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Mon, 6 Sep 2021 13:16:46 +0530 Subject: [PATCH 13/21] e2e fixes --- .../src/tests/solidityUnittests.spec.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts index a46781eaea..bc65f76fa2 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts @@ -47,13 +47,13 @@ module.exports = { .click('*[data-id="testTabCheckAllTests"]') .clickElementAtPosition('.singleTestLabel', 1) .scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]') - .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'MyTest (/tests/simple_storage_test.sol)', 120000) + .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'MyTest (tests/simple_storage_test.sol)', 120000) .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '✓ Initial value should be100', 120000) .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '✓ Value is set200', 120000) .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '✘ Should fail for wrong value200', 120000) .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'Passing: 2', 120000) .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'Failing: 1', 120000) - .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'FAIL MyTest (/tests/simple_storage_test.sol)', 120000) + .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) { @@ -65,7 +65,7 @@ module.exports = { .click('*[data-id="testTabCheckAllTests"]') .clickElementAtPosition('.singleTestLabel', 2) .scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]') - .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '/tests/ks2b_test.sol', 120000) + .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'tests/ks2b_test.sol', 120000) .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '✓ Check project exists', 120000) .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '✘ Check wrong project owner', 120000) .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '✘ Check wrong sender', 120000) @@ -84,9 +84,9 @@ module.exports = { .scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]') .pause(2000) .click('*[data-id="testTabRunTestsTabStopAction"]') - .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '/tests/ks2b_test.sol', 200000) - .notContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '/tests/4_Ballot_test.sol') - .notContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '/tests/simple_storage_test.sol') + .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'tests/ks2b_test.sol', 200000) + .notContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'tests/4_Ballot_test.sol') + .notContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'tests/simple_storage_test.sol') .waitForElementContainsText('*[data-id="testTabTestsExecutionStopped"]', 'The test execution has been stopped', 60000) }, @@ -178,7 +178,7 @@ module.exports = { .scrollAndClick('#runTestsTabRunAction') .waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000) .waitForElementPresent('#solidityUnittestsOutput div[class^="testPass"]', 60000) - .waitForElementContainsText('#solidityUnittestsOutput', '/tests/4_Ballot_test.sol', 60000) + .waitForElementContainsText('#solidityUnittestsOutput', 'tests/4_Ballot_test.sol', 60000) .waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winning proposal', 60000) .waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winnin proposal with return value', 60000) }, @@ -196,7 +196,7 @@ module.exports = { .scrollAndClick('#runTestsTabRunAction') .waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000) .waitForElementPresent('#solidityUnittestsOutput div[class^="testPass"]', 60000) - .waitForElementContainsText('#solidityUnittestsOutput', '/tests/4_Ballot_test.sol', 60000) + .waitForElementContainsText('#solidityUnittestsOutput', 'tests/4_Ballot_test.sol', 60000) .waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winning proposal', 60000) .waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winnin proposal with return value', 60000) .end() From 3ef5f1b4ac241d82ebf5d385543833c824865903 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Mon, 6 Sep 2021 17:04:05 +0530 Subject: [PATCH 14/21] optWeb3 dominance --- libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx index 34c355591e..a41066e56b 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -181,7 +181,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { return } - const web3 = state.opt.debugWithLocalNode ? await debuggerModule.web3() : (optWeb3 || await debuggerModule.getDebugWeb3()) + const web3 = optWeb3 || (state.opt.debugWithLocalNode ? await debuggerModule.web3() : await debuggerModule.getDebugWeb3()) try { const networkId = await web3.eth.net.getId() _paq.push(['trackEvent', 'debugger', 'startDebugging', networkId]) From 3ead354c47f8c3ac0bda023402d66370f3e17474 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Mon, 6 Sep 2021 17:05:01 +0530 Subject: [PATCH 15/21] space after if --- apps/debugger/src/app/debugger-api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/debugger/src/app/debugger-api.ts b/apps/debugger/src/app/debugger-api.ts index 5e22bf03f7..73c49b32e9 100644 --- a/apps/debugger/src/app/debugger-api.ts +++ b/apps/debugger/src/app/debugger-api.ts @@ -123,7 +123,7 @@ export const DebuggerApiMixin = (Base) => class extends Base { debug (hash, web3?) { this.debugHash = hash - if(web3) remixDebug.init.extendWeb3(web3) + if (web3) remixDebug.init.extendWeb3(web3) if (this.onDebugRequestedListener) this.onDebugRequestedListener(hash, web3) } From 156f9ae2d1add90913ef27d907755a5bdd36b42c Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Tue, 7 Sep 2021 13:46:16 +0530 Subject: [PATCH 16/21] eventManager removed --- apps/remix-ide/src/app/tabs/test-tab.js | 2 +- libs/remix-tests/src/compiler.ts | 2 +- libs/remix-tests/src/lib/eventManager.ts | 68 ------------------------ libs/remix-tests/src/runTestSources.ts | 4 +- 4 files changed, 4 insertions(+), 72 deletions(-) delete mode 100644 libs/remix-tests/src/lib/eventManager.ts diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index 0119425b8e..95bd5d37a2 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -98,7 +98,7 @@ module.exports = class TestTab extends ViewPlugin { this.setCurrentPath(this.defaultPath) }) - this.testRunner.event.register('compilationFinished', (success, data, source) => { + this.testRunner.event.on('compilationFinished', (success, data, source) => { if (success) { this.allFilesInvolved = Object.keys(data.sources) // forwarding the event to the appManager infra diff --git a/libs/remix-tests/src/compiler.ts b/libs/remix-tests/src/compiler.ts index 3e3c8b85d4..e77fdcdcfc 100644 --- a/libs/remix-tests/src/compiler.ts +++ b/libs/remix-tests/src/compiler.ts @@ -205,7 +205,7 @@ export function compileContractSources (sources: SrcIfc, compilerConfig: Compile function doCompilation (next) { // @ts-ignore compiler.event.register('compilationFinished', this, (success, data, source) => { - if (opts && opts.event) opts.event.trigger('compilationFinished', [success, data, source]) + if (opts && opts.event) opts.event.emit('compilationFinished', success, data, source) next(null, data) }) compiler.compile(sources, filepath) diff --git a/libs/remix-tests/src/lib/eventManager.ts b/libs/remix-tests/src/lib/eventManager.ts deleted file mode 100644 index 8282e09b6c..0000000000 --- a/libs/remix-tests/src/lib/eventManager.ts +++ /dev/null @@ -1,68 +0,0 @@ -'use strict' - -export default class EventManager { - registered: any = {} // eslint-disable-line - anonymous: any = {} // eslint-disable-line - - /* - * Unregister a listener. - * Note that if obj is a function. the unregistration will be applied to the dummy obj {}. - * - * @param {String} eventName - the event name - * @param {Object or Func} obj - object that will listen on this event - * @param {Func} func - function of the listeners that will be executed - */ - unregister (eventName: any, obj: any, func: any): void { // eslint-disable-line - if (!this.registered[eventName]) { - return - } - if (obj instanceof Function) { - func = obj - obj = this.anonymous - } - for (const reg in this.registered[eventName]) { - if (this.registered[eventName][reg].obj === obj && this.registered[eventName][reg].func === func) { - this.registered[eventName].splice(reg, 1) - } - } - } - - /* - * Register a new listener. - * Note that if obj is a function, the function registration will be associated with the dummy object {} - * - * @param {String} eventName - the event name - * @param {Object or Func} obj - object that will listen on this event - * @param {Func} func - function of the listeners that will be executed - */ - register (eventName: any, obj: any, func: any): void { // eslint-disable-line - if (!this.registered[eventName]) { - this.registered[eventName] = [] - } - if (obj instanceof Function) { - func = obj - obj = this.anonymous - } - this.registered[eventName].push({ - obj: obj, - func: func - }) - } - - /* - * trigger event. - * Every listener have their associated function executed - * - * @param {String} eventName - the event name - * @param {Array}j - argument that will be passed to the executed function. - */ - trigger (eventName: any, args: any): void { // eslint-disable-line - if (!this.registered[eventName]) { - return - } - for (const listener in this.registered[eventName]) { - const l = this.registered[eventName][listener] - if (l.func) l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) - } - } -} diff --git a/libs/remix-tests/src/runTestSources.ts b/libs/remix-tests/src/runTestSources.ts index 1a3e59dce9..4894b713eb 100644 --- a/libs/remix-tests/src/runTestSources.ts +++ b/libs/remix-tests/src/runTestSources.ts @@ -5,7 +5,7 @@ import { deployAll } from './deployer' import { runTest } from './testRunner' import Web3 from 'web3' -import EventManager from './lib/eventManager' +import { EventEmitter } from 'events' import { Provider, extend } from '@remix-project/remix-simulator' import { FinalResult, SrcIfc, compilationInterface, ASTInterface, Options, @@ -17,7 +17,7 @@ export class UnitTestRunner { event constructor () { - this.event = new EventManager() + this.event = new EventEmitter() } async createWeb3Provider () { From f4352ceb0e312f24915ea1518e2912562968e9e0 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Mon, 6 Sep 2021 19:50:57 +0530 Subject: [PATCH 17/21] e2e test for SUT debugging --- .../src/tests/solidityUnittests.spec.ts | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts index bc65f76fa2..ca97028140 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts @@ -115,7 +115,7 @@ module.exports = { .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'contract deployment failed after trying twice', 120000) }, - 'Should fail when parameters are to method in test contract': function (browser: NightwatchBrowser) { + 'Should fail when parameters are passed to method in test contract': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]') .addFile('tests/methodFailure_test.sol', sources[0]['tests/methodFailure_test.sol']) .clickLaunchIcon('filePanel') @@ -183,6 +183,36 @@ module.exports = { .waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winnin proposal with return value', 60000) }, + 'Debug failed test using debugger': function (browser: NightwatchBrowser) { + browser + .waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]') + .addFile('tests/ballotFailedDebug_test.sol', sources[0]['tests/ballotFailedDebug_test.sol']) + .clickLaunchIcon('solidityUnitTesting') + .waitForElementVisible('*[id="singleTesttests/4_Ballot_test.sol"]', 60000) + .click('*[id="singleTesttests/4_Ballot_test.sol"]') + .click('#runTestsTabRunAction') + .waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000) + .waitForElementContainsText('#solidityUnittestsOutput', 'tests/ballotFailedDebug_test.sol', 60000) + .waitForElementContainsText('#solidityUnittestsOutput', '✘ Check winning proposal', 60000) + .waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winnin proposal with return value', 60000) + .click('.fa-bug') + .waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000) + .waitForElementContainsText('*[id="FunctionPanel"]', 'checkWinningProposal()', 60000) + .click('*[data-id="dropdownPanelSolidityLocals"]') + .waitForElementContainsText('*[data-id="solidityLocals"]', 'no locals', 60000) + // eslint-disable-next-line dot-notation + .execute(function () { document.getElementById('slider')['value'] = '340' }) // It only moves slider to 340 but vm traces are not updated + .setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW)) + .waitForElementContainsText('*[id="FunctionPanel"]', 'checkWinningProposal()', 60000) + .waitForElementContainsText('*[id="FunctionPanel"]', 'vote(proposal)', 60000) + .pause(2000) + .checkVariableDebug('soliditylocals', locals) + .clickLaunchIcon('filePanel') + .pause(2000) + .openFile('tests/ballotFailedDebug_test.sol') + .removeFile('tests/ballotFailedDebug_test.sol', 'default_workspace') + }, + 'Solidity Unit tests Basic Basic with local compiler': function (browser: NightwatchBrowser) { browser .clickLaunchIcon('solidity') @@ -401,6 +431,61 @@ const sources = [ } } ` + }, + 'tests/ballotFailedDebug_test.sol': { + content: `// SPDX-License-Identifier: GPL-3.0 + + pragma solidity >=0.7.0 <0.9.0; + import "remix_tests.sol"; // this import is automatically injected by Remix. + import "../contracts/3_Ballot.sol"; + + contract BallotTest { + + bytes32[] proposalNames; + + Ballot ballotToTest; + function beforeAll () public { + proposalNames.push(bytes32("candidate1")); + ballotToTest = new Ballot(proposalNames); + } + + function checkWinningProposal () public { + ballotToTest.vote(1); // This will revert the transaction + Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal"); + } + + function checkWinninProposalWithReturnValue () public view returns (bool) { + return ballotToTest.winningProposal() == 0; + } + }` } } ] + +const locals = { + "sender": { + "value": { + "weight": { + "value": "1", + "type": "uint256" + }, + "voted": { + "value": false, + "type": "bool" + }, + "delegate": { + "value": "0x0000000000000000000000000000000000000000", + "type": "address" + }, + "vote": { + "value": "0", + "type": "uint256" + } + }, + "type": "struct Ballot.Voter" + }, + "proposal": { + "value": "1", + "type": "uint256" + } +} From a0731b261e505fa62bc72dcadf515027553a9b12 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Tue, 7 Sep 2021 13:52:50 +0530 Subject: [PATCH 18/21] linting fix --- .../src/tests/solidityUnittests.spec.ts | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts index ca97028140..a8372f570a 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts @@ -463,29 +463,29 @@ const sources = [ ] const locals = { - "sender": { - "value": { - "weight": { - "value": "1", - "type": "uint256" - }, - "voted": { - "value": false, - "type": "bool" - }, - "delegate": { - "value": "0x0000000000000000000000000000000000000000", - "type": "address" - }, - "vote": { - "value": "0", - "type": "uint256" - } - }, - "type": "struct Ballot.Voter" - }, - "proposal": { - "value": "1", - "type": "uint256" - } + sender: { + value: { + weight: { + value: '1', + type: 'uint256' + }, + voted: { + value: false, + type: 'bool' + }, + delegate: { + value: '0x0000000000000000000000000000000000000000', + type: 'address' + }, + vote: { + value: '0', + type: 'uint256' + } + }, + type: 'struct Ballot.Voter' + }, + proposal: { + value: '1', + type: 'uint256' + } } From 2ce26b5a5ca1fd13ae530416e98e0ab214ac7cf5 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Tue, 7 Sep 2021 15:02:21 +0530 Subject: [PATCH 19/21] data id added --- apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts | 6 +++--- .../debugger-ui/src/lib/vm-debugger/function-panel.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts index a8372f570a..5c8539d5e9 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts @@ -197,14 +197,14 @@ module.exports = { .waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winnin proposal with return value', 60000) .click('.fa-bug') .waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000) - .waitForElementContainsText('*[id="FunctionPanel"]', 'checkWinningProposal()', 60000) + .waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposal()', 60000) .click('*[data-id="dropdownPanelSolidityLocals"]') .waitForElementContainsText('*[data-id="solidityLocals"]', 'no locals', 60000) // eslint-disable-next-line dot-notation .execute(function () { document.getElementById('slider')['value'] = '340' }) // It only moves slider to 340 but vm traces are not updated .setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW)) - .waitForElementContainsText('*[id="FunctionPanel"]', 'checkWinningProposal()', 60000) - .waitForElementContainsText('*[id="FunctionPanel"]', 'vote(proposal)', 60000) + .waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposal()', 60000) + .waitForElementContainsText('*[data-id="functionPanel"]', 'vote(proposal)', 60000) .pause(2000) .checkVariableDebug('soliditylocals', locals) .clickLaunchIcon('filePanel') diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx index 6fa7686d5f..0511765ec5 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx @@ -10,7 +10,7 @@ export const FunctionPanel = ({ data }) => { }, [data]) return ( -
+
) From 2fd5576e25d115a19eef57c20caa9c7e30c45e52 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Tue, 7 Sep 2021 19:26:52 +0530 Subject: [PATCH 20/21] trace number fix --- apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts index 5c8539d5e9..e3ec8bfea8 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts @@ -201,7 +201,7 @@ module.exports = { .click('*[data-id="dropdownPanelSolidityLocals"]') .waitForElementContainsText('*[data-id="solidityLocals"]', 'no locals', 60000) // eslint-disable-next-line dot-notation - .execute(function () { document.getElementById('slider')['value'] = '340' }) // It only moves slider to 340 but vm traces are not updated + .execute(function () { document.getElementById('slider')['value'] = '235' }) // It only moves slider to 235 but vm traces are not updated .setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW)) .waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposal()', 60000) .waitForElementContainsText('*[data-id="functionPanel"]', 'vote(proposal)', 60000) @@ -213,7 +213,7 @@ module.exports = { .removeFile('tests/ballotFailedDebug_test.sol', 'default_workspace') }, - 'Solidity Unit tests Basic Basic with local compiler': function (browser: NightwatchBrowser) { + 'Basic Solidity Unit tests with local compiler': function (browser: NightwatchBrowser) { browser .clickLaunchIcon('solidity') .setSolidityCompilerVersion('builtin') From f896e705165036b76c708d1bf87d554c6c5d5f87 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Tue, 7 Sep 2021 19:48:29 +0530 Subject: [PATCH 21/21] workspace fix --- apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts index e3ec8bfea8..c6407f4942 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts @@ -210,7 +210,7 @@ module.exports = { .clickLaunchIcon('filePanel') .pause(2000) .openFile('tests/ballotFailedDebug_test.sol') - .removeFile('tests/ballotFailedDebug_test.sol', 'default_workspace') + .removeFile('tests/ballotFailedDebug_test.sol', 'workspace_new') }, 'Basic Solidity Unit tests with local compiler': function (browser: NightwatchBrowser) {