diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index 9351b37c05..6fd97b446a 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -8,7 +8,7 @@ import { ViewPlugin } from '@remixproject/engine-web' import helper from '../../lib/helper' import { canUseWorker, urlFromVersion } from '@remix-project/remix-solidity' -var tooltip = require('../ui/tooltip') +// var tooltip = require('../ui/tooltip') var Renderer = require('../ui/renderer') var { UnitTestRunner, assertLibCode } = require('@remix-project/remix-tests') @@ -28,10 +28,8 @@ module.exports = class TestTab extends ViewPlugin { super(profile) this.compileTab = compileTab this.contentImport = contentImport - this._view = { el: null } this.fileManager = fileManager this.filePanel = filePanel - this.data = {} this.appManager = appManager this.renderer = new Renderer(this) this.testRunner = new UnitTestRunner() @@ -56,7 +54,7 @@ module.exports = class TestTab extends ViewPlugin { async setTestFolderPath (event) { if (event.path.length > 0) { - await this.setCurrentPath(event.path[0]) + this.renderComponent(event.path[0]) } } @@ -89,7 +87,6 @@ module.exports = class TestTab extends ViewPlugin { } listenToEvents () { - this.on('filePanel', 'workspaceCreated', async () => { this.createTestLibs() }) @@ -140,9 +137,9 @@ module.exports = class TestTab extends ViewPlugin { return this.element } - renderComponent () { + renderComponent (testDirPath) { ReactDOM.render( - + , this.element) } } diff --git a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx index f3fe915579..d759fdfcfd 100644 --- a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx +++ b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx @@ -8,7 +8,7 @@ import './css/style.css' const _paq = (window as any)._paq = (window as any)._paq || [] // eslint-disable-line /* eslint-disable-next-line */ -export interface SolidityUnitTestingProps {} +export interface SolidityUnitTestingProps { } interface TestObject { fileName: string @@ -17,7 +17,7 @@ interface TestObject { export const SolidityUnitTesting = (props: Record) => { - const {helper, testTab} = props + const { helper, testTab, initialPath } = props const { testTabLogic } = testTab const [defaultPath, setDefaultPath] = useState('tests') @@ -30,14 +30,14 @@ export const SolidityUnitTesting = (props: Record) => { const [checkSelectAll, setCheckSelectAll] = useState(true) const [testsOutput, setTestsOutput] = useState([]) - + const [testsExecutionStoppedHidden, setTestsExecutionStoppedHidden] = useState(true) const [progressBarHidden, setProgressBarHidden] = useState(true) const [testsExecutionStoppedErrorHidden, setTestsExecutionStoppedErrorHidden] = useState(true) - + let [testFiles, setTestFiles] = useState([]) // eslint-disable-line const [pathOptions, setPathOptions] = useState(['']) - + const [inputPathValue, setInputPathValue] = useState('tests') let [readyTestsNumber, setReadyTestsNumber] = useState(0) // eslint-disable-line @@ -55,9 +55,9 @@ export const SolidityUnitTesting = (props: Record) => { let runningTestFileName: any const filesContent: any = {} - const testsResultByFilename:Record = {} - - const trimTestDirInput = (input:string) => { + const testsResultByFilename: Record = {} + + const trimTestDirInput = (input: string) => { if (input.includes('/')) return input.split('/').map(e => e.trim()).join('/') else return input.trim() } @@ -71,21 +71,21 @@ export const SolidityUnitTesting = (props: Record) => { } const updateForNewCurrent = async (file = null) => { - // Ensure that when someone clicks on compilation error and that opens a new file - // Test result, which is compilation error in this case, is not cleared - if (currentErrors) { - if (Array.isArray(currentErrors) && currentErrors.length > 0) { - const errFiles = currentErrors.map(err => { if (err.sourceLocation && err.sourceLocation.file) return err.sourceLocation.file }) // eslint-disable-line - if (errFiles.includes(file)) return - } else if (currentErrors.sourceLocation && currentErrors.sourceLocation.file && currentErrors.sourceLocation.file === file) return - } - // 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 (isDebugging && testTab.allFilesInvolved.includes(file)) return - allTests.current = [] - updateTestFileList() - clearResults() - try { + // Ensure that when someone clicks on compilation error and that opens a new file + // Test result, which is compilation error in this case, is not cleared + if (currentErrors) { + if (Array.isArray(currentErrors) && currentErrors.length > 0) { + const errFiles = currentErrors.map(err => { if (err.sourceLocation && err.sourceLocation.file) return err.sourceLocation.file }) // eslint-disable-line + if (errFiles.includes(file)) return + } else if (currentErrors.sourceLocation && currentErrors.sourceLocation.file && currentErrors.sourceLocation.file === file) return + } + // 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 (isDebugging && testTab.allFilesInvolved.includes(file)) return + allTests.current = [] + updateTestFileList() + clearResults() + try { testTabLogic.getTests(async (error: any, tests: any) => { // if (error) return tooltip(error) allTests.current = tests @@ -94,8 +94,8 @@ export const SolidityUnitTesting = (props: Record) => { if (!areTestsRunning) await updateRunAction(file) }) } catch (e) { - console.log(e) - } + console.log(e) + } } /** @@ -109,6 +109,10 @@ export const SolidityUnitTesting = (props: Record) => { await updateForNewCurrent() } + useEffect(() => { + if (initialPath) setCurrentPath(initialPath) + }, [initialPath]) // eslint-disable-line react-hooks/exhaustive-deps + useEffect(() => { updateDirList('/') updateForNewCurrent() @@ -132,7 +136,7 @@ export const SolidityUnitTesting = (props: Record) => { setCurrentPath(defaultPath) }) - testTab.fileManager.events.on('noFileSelected', () => {}) // eslint-disable-line + testTab.fileManager.events.on('noFileSelected', () => { }) // eslint-disable-line testTab.fileManager.events.on('currentFileChanged', (file: any, provider: any) => updateForNewCurrent(file)) }, []) // eslint-disable-line @@ -182,7 +186,7 @@ export const SolidityUnitTesting = (props: Record) => { } } - const handleEnter = async(e:any) => { + const handleEnter = async (e: any) => { let inputPath = e.target.value inputPath = helper.removeMultipleSlashes(trimTestDirInput(inputPath)) setInputPathValue(inputPath) @@ -194,7 +198,7 @@ export const SolidityUnitTesting = (props: Record) => { } } - const handleCreateFolder = async() => { + const handleCreateFolder = async () => { let inputPath = trimTestDirInput(inputPathValue) let path = helper.removeMultipleSlashes(inputPath) if (path !== '/') path = helper.removeTrailingSlashes(path) @@ -266,7 +270,7 @@ export const SolidityUnitTesting = (props: Record) => { if (withoutLabel) { const contractCard: any = (
- {contract ? contract: ''} ({filename}) + {contract ? contract : ''} ({filename})
) setTestsOutput(prevCards => ([...prevCards, contractCard])) @@ -278,7 +282,7 @@ export const SolidityUnitTesting = (props: Record) => { title="At least one contract test failed" > FAIL - ) + ) else label = (
) => { // show filename and contract renderContract(filename, contract, index) // show tests - for(const test of tests) { - if(!test.rendered) { + for (const test of tests) { + if (!test.rendered) { let debugBtn if (test.debugTxHash) { const { web3, debugTxHash } = test debugBtn = ( -
startDebug(debugTxHash, web3)}> - -
+
startDebug(debugTxHash, web3)}> + +
) - } + } if (test.type === 'testPass') { if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) const testPassCard: any = ( @@ -325,71 +329,71 @@ export const SolidityUnitTesting = (props: Record) => { >
✓ {test.value} - {debugBtn} -
+ {debugBtn} +
) setTestsOutput(prevCards => ([...prevCards, testPassCard])) test.rendered = true } else if (test.type === 'testFailure') { - if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) - if (!test.assertMethod) { - const testFailCard1: any = (
highlightLocation(test.location, test.filename)} - > -
- ✘ {test.value} - {debugBtn} -
- Error Message: - "{test.errMsg}" -
) - setTestsOutput(prevCards => ([...prevCards, testFailCard1])) - } else { - const preposition = test.assertMethod === 'equal' || test.assertMethod === 'notEqual' ? 'to' : '' - const method = test.assertMethod === 'ok' ? '' : test.assertMethod - const expected = test.assertMethod === 'ok' ? '\'true\'' : test.expected - const testFailCard2: any = (
highlightLocation(test.location, test.filename)} - > -
- ✘ {test.value} - {debugBtn} -
- Error Message: - "{test.errMsg}" - Assertion: -
- Expected value should be -
{method}
-
{preposition} {expected}
-
- Received value: - {test.returned} - Skipping the remaining tests of the function. -
) - setTestsOutput(prevCards => ([...prevCards, testFailCard2])) - } - test.rendered = true - } else if (test.type === 'logOnly') { - if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) - test.rendered = true - } + if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) + if (!test.assertMethod) { + const testFailCard1: any = (
highlightLocation(test.location, test.filename)} + > +
+ ✘ {test.value} + {debugBtn} +
+ Error Message: + "{test.errMsg}" +
) + setTestsOutput(prevCards => ([...prevCards, testFailCard1])) + } else { + const preposition = test.assertMethod === 'equal' || test.assertMethod === 'notEqual' ? 'to' : '' + const method = test.assertMethod === 'ok' ? '' : test.assertMethod + const expected = test.assertMethod === 'ok' ? '\'true\'' : test.expected + const testFailCard2: any = (
highlightLocation(test.location, test.filename)} + > +
+ ✘ {test.value} + {debugBtn} +
+ Error Message: + "{test.errMsg}" + Assertion: +
+ Expected value should be +
{method}
+
{preposition} {expected}
+
+ Received value: + {test.returned} + Skipping the remaining tests of the function. +
) + setTestsOutput(prevCards => ([...prevCards, testFailCard2])) + } + test.rendered = true + } else if (test.type === 'logOnly') { + if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) + test.rendered = true + } } } } const showTestsResult = () => { const filenames = Object.keys(testsResultByFilename) - for(const filename of filenames) { + for (const filename of filenames) { const fileTestsResult = testsResultByFilename[filename] const contracts = Object.keys(fileTestsResult) - for(const contract of contracts) { - if(contract && contract !== 'summary' && contract !== 'errors') { + for (const contract of contracts) { + if (contract && contract !== 'summary' && contract !== 'errors') { runningTestFileName = cleanFileName(filename, contract) const tests = fileTestsResult[contract] if (tests?.length) { @@ -402,19 +406,19 @@ export const SolidityUnitTesting = (props: Record) => { const errors = fileTestsResult['errors'] if (errors && errors.errors) { errors.errors.forEach((err: any) => { - const errorCard: any = + const errorCard: any = setTestsOutput(prevCards => ([...prevCards, errorCard])) }) } else if (errors && Array.isArray(errors) && (errors[0].message || errors[0].formattedMessage)) { errors.forEach((err) => { - const errorCard: any = + const errorCard: any = setTestsOutput(prevCards => ([...prevCards, errorCard])) }) } else if (errors && !errors.errors && !Array.isArray(errors)) { // To track error like this: https://github.com/ethereum/remix/pull/1438 const errorCard: any = setTestsOutput(prevCards => ([...prevCards, errorCard])) - } + } } } // show summary @@ -429,17 +433,17 @@ export const SolidityUnitTesting = (props: Record) => { setTestsOutput(prevCards => ([...prevCards, summaryCard])) fileTestsResult['summary']['rendered'] = true } - } + } } const testCallback = (result: any) => { - if(result.filename) { - if(!testsResultByFilename[result.filename]) { + if (result.filename) { + if (!testsResultByFilename[result.filename]) { testsResultByFilename[result.filename] = {} testsResultByFilename[result.filename]['summary'] = {} } - if(result.type === 'contract') { - testsResultByFilename[result.filename][result.value]= {} + if (result.type === 'contract') { + testsResultByFilename[result.filename][result.value] = {} testsResultByFilename[result.filename][result.value] = [] } else { // Set that this test is not rendered on UI @@ -469,17 +473,17 @@ export const SolidityUnitTesting = (props: Record) => { if (result) { const totalTime = parseFloat(result.totalTime).toFixed(2) const testsSummary = { filename, passed: result.totalPassing, failed: result.totalFailing, timeTaken: totalTime, rendered: false } - testsResultByFilename[filename]['summary']= testsSummary + testsResultByFilename[filename]['summary'] = testsSummary showTestsResult() } else if (_errors) { - if(!testsResultByFilename[filename]) { + if (!testsResultByFilename[filename]) { testsResultByFilename[filename] = {} } testsResultByFilename[filename]['errors'] = _errors setTestsExecutionStoppedErrorHidden(false) showTestsResult() } - + if (hasBeenStopped.current && (readyTestsNumber !== runningTestsNumber)) { // if all tests has been through before stopping no need to print this. setTestsExecutionStoppedHidden(false) @@ -557,7 +561,7 @@ export const SolidityUnitTesting = (props: Record) => { }) } - const updateRunAction = async (currentFile : any = null) => { + const updateRunAction = async (currentFile: any = null) => { const isSolidityActive = await testTab.appManager.isActive('solidity') if (!isSolidityActive || !selectedTests.current?.length) { setDisableRunButton(true) @@ -581,7 +585,7 @@ export const SolidityUnitTesting = (props: Record) => { return selectedTestsList.map(testFileObj => testFileObj.fileName) } - const toggleCheckbox = (eChecked: any, index:any) => { + const toggleCheckbox = (eChecked: any, index: any) => { testFiles[index].checked = eChecked setTestFiles(testFiles) selectedTests.current = getCurrentSelectedTests() @@ -599,10 +603,10 @@ export const SolidityUnitTesting = (props: Record) => { } const checkAll = (event: any) => { - testFiles.forEach((testFileObj) => testFileObj.checked = event.target.checked) + testFiles.forEach((testFileObj) => testFileObj.checked = event.target.checked) setTestFiles(testFiles) setCheckSelectAll(event.target.checked) - if(event.target.checked) { + if (event.target.checked) { selectedTests.current = getCurrentSelectedTests() setDisableRunButton(false) } else { @@ -612,28 +616,28 @@ export const SolidityUnitTesting = (props: Record) => { } const updateTestFileList = () => { - if(allTests.current?.length) { - testFiles = allTests.current.map((testFile: any) => { return {'fileName': testFile, 'checked': true }}) + if (allTests.current?.length) { + testFiles = allTests.current.map((testFile: any) => { return { 'fileName': testFile, 'checked': true } }) setCheckSelectAll(true) } - else + else testFiles = [] setTestFiles(testFiles) } return (
-
-

Test your smart contract in Solidity.

-

Select directory to load and generate test files.

- -
-
+
+

Test your smart contract in Solidity.

+

Select directory to load and generate test files.

+ +
+
{ pathOptions.map(function (path) { return }) - } + } ) => { name="utPath" value={inputPathValue} title="Press 'Enter' to change the path for test files." - style= {{ backgroundImage: "var(--primary)"}} - onKeyUp= {handleTestDirInput} + style={{ backgroundImage: "var(--primary)" }} + onKeyUp={handleTestDirInput} onChange={handleEnter} /> -
-
-
- - - - -
-
- - -
-
- {}} // eslint-disable-line - /> - -
-
{testFiles?.length ? testFiles.map((testFileObj: any, index) => { - const elemId = `singleTest${testFileObj.fileName}` - return ( -
- toggleCheckbox(e.target.checked, index)} type="checkbox" checked={testFileObj.checked}/> - -
- ) - }) - : "No test file available" }
-
- - - -
-
{testsOutput}
+
+
+
+ + + + +
+
+ + +
+
+ { }} // eslint-disable-line + /> + +
+
{testFiles?.length ? testFiles.map((testFileObj: any, index) => { + const elemId = `singleTest${testFileObj.fileName}` + return ( +
+ toggleCheckbox(e.target.checked, index)} type="checkbox" checked={testFileObj.checked} /> + +
+ ) + }) + : "No test file available"}
+
+ + +
+
{testsOutput}
+
) }