|
|
@ -8,7 +8,7 @@ import './css/style.css' |
|
|
|
const _paq = (window as any)._paq = (window as any)._paq || [] // eslint-disable-line
|
|
|
|
const _paq = (window as any)._paq = (window as any)._paq || [] // eslint-disable-line
|
|
|
|
|
|
|
|
|
|
|
|
/* eslint-disable-next-line */ |
|
|
|
/* eslint-disable-next-line */ |
|
|
|
export interface SolidityUnitTestingProps {} |
|
|
|
export interface SolidityUnitTestingProps { } |
|
|
|
|
|
|
|
|
|
|
|
interface TestObject { |
|
|
|
interface TestObject { |
|
|
|
fileName: string |
|
|
|
fileName: string |
|
|
@ -17,7 +17,7 @@ interface TestObject { |
|
|
|
|
|
|
|
|
|
|
|
export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
|
|
|
|
|
|
|
|
const {helper, testTab} = props |
|
|
|
const { helper, testTab, initialPath } = props |
|
|
|
const { testTabLogic } = testTab |
|
|
|
const { testTabLogic } = testTab |
|
|
|
|
|
|
|
|
|
|
|
const [defaultPath, setDefaultPath] = useState('tests') |
|
|
|
const [defaultPath, setDefaultPath] = useState('tests') |
|
|
@ -30,14 +30,14 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
|
|
|
|
|
|
|
|
const [checkSelectAll, setCheckSelectAll] = useState(true) |
|
|
|
const [checkSelectAll, setCheckSelectAll] = useState(true) |
|
|
|
const [testsOutput, setTestsOutput] = useState<Element[]>([]) |
|
|
|
const [testsOutput, setTestsOutput] = useState<Element[]>([]) |
|
|
|
|
|
|
|
|
|
|
|
const [testsExecutionStoppedHidden, setTestsExecutionStoppedHidden] = useState(true) |
|
|
|
const [testsExecutionStoppedHidden, setTestsExecutionStoppedHidden] = useState(true) |
|
|
|
const [progressBarHidden, setProgressBarHidden] = useState(true) |
|
|
|
const [progressBarHidden, setProgressBarHidden] = useState(true) |
|
|
|
const [testsExecutionStoppedErrorHidden, setTestsExecutionStoppedErrorHidden] = useState(true) |
|
|
|
const [testsExecutionStoppedErrorHidden, setTestsExecutionStoppedErrorHidden] = useState(true) |
|
|
|
|
|
|
|
|
|
|
|
let [testFiles, setTestFiles] = useState<TestObject[]>([]) // eslint-disable-line
|
|
|
|
let [testFiles, setTestFiles] = useState<TestObject[]>([]) // eslint-disable-line
|
|
|
|
const [pathOptions, setPathOptions] = useState(['']) |
|
|
|
const [pathOptions, setPathOptions] = useState(['']) |
|
|
|
|
|
|
|
|
|
|
|
const [inputPathValue, setInputPathValue] = useState('tests') |
|
|
|
const [inputPathValue, setInputPathValue] = useState('tests') |
|
|
|
|
|
|
|
|
|
|
|
let [readyTestsNumber, setReadyTestsNumber] = useState(0) // eslint-disable-line
|
|
|
|
let [readyTestsNumber, setReadyTestsNumber] = useState(0) // eslint-disable-line
|
|
|
@ -55,9 +55,9 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
let runningTestFileName: any |
|
|
|
let runningTestFileName: any |
|
|
|
const filesContent: any = {} |
|
|
|
const filesContent: any = {} |
|
|
|
|
|
|
|
|
|
|
|
const testsResultByFilename:Record<string, any> = {} |
|
|
|
const testsResultByFilename: Record<string, any> = {} |
|
|
|
|
|
|
|
|
|
|
|
const trimTestDirInput = (input:string) => { |
|
|
|
const trimTestDirInput = (input: string) => { |
|
|
|
if (input.includes('/')) return input.split('/').map(e => e.trim()).join('/') |
|
|
|
if (input.includes('/')) return input.split('/').map(e => e.trim()).join('/') |
|
|
|
else return input.trim() |
|
|
|
else return input.trim() |
|
|
|
} |
|
|
|
} |
|
|
@ -71,21 +71,21 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const updateForNewCurrent = async (file = null) => { |
|
|
|
const updateForNewCurrent = async (file = null) => { |
|
|
|
// Ensure that when someone clicks on compilation error and that opens a new file
|
|
|
|
// 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
|
|
|
|
// Test result, which is compilation error in this case, is not cleared
|
|
|
|
if (currentErrors) { |
|
|
|
if (currentErrors) { |
|
|
|
if (Array.isArray(currentErrors) && currentErrors.length > 0) { |
|
|
|
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
|
|
|
|
const errFiles = currentErrors.map(err => { if (err.sourceLocation && err.sourceLocation.file) return err.sourceLocation.file }) // eslint-disable-line
|
|
|
|
if (errFiles.includes(file)) return |
|
|
|
if (errFiles.includes(file)) return |
|
|
|
} else if (currentErrors.sourceLocation && currentErrors.sourceLocation.file && currentErrors.sourceLocation.file === 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
|
|
|
|
// 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
|
|
|
|
// do not clear the test results in SUT plugin
|
|
|
|
if (isDebugging && testTab.allFilesInvolved.includes(file)) return |
|
|
|
if (isDebugging && testTab.allFilesInvolved.includes(file)) return |
|
|
|
allTests.current = [] |
|
|
|
allTests.current = [] |
|
|
|
updateTestFileList() |
|
|
|
updateTestFileList() |
|
|
|
clearResults() |
|
|
|
clearResults() |
|
|
|
try { |
|
|
|
try { |
|
|
|
testTabLogic.getTests(async (error: any, tests: any) => { |
|
|
|
testTabLogic.getTests(async (error: any, tests: any) => { |
|
|
|
// if (error) return tooltip(error)
|
|
|
|
// if (error) return tooltip(error)
|
|
|
|
allTests.current = tests |
|
|
|
allTests.current = tests |
|
|
@ -94,8 +94,8 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
if (!areTestsRunning) await updateRunAction(file) |
|
|
|
if (!areTestsRunning) await updateRunAction(file) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e) |
|
|
|
console.log(e) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -109,6 +109,10 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
await updateForNewCurrent() |
|
|
|
await updateForNewCurrent() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
if (initialPath) setCurrentPath(initialPath) |
|
|
|
|
|
|
|
}, [initialPath]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
updateDirList('/') |
|
|
|
updateDirList('/') |
|
|
|
updateForNewCurrent() |
|
|
|
updateForNewCurrent() |
|
|
@ -132,7 +136,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
setCurrentPath(defaultPath) |
|
|
|
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)) |
|
|
|
testTab.fileManager.events.on('currentFileChanged', (file: any, provider: any) => updateForNewCurrent(file)) |
|
|
|
|
|
|
|
|
|
|
|
}, []) // eslint-disable-line
|
|
|
|
}, []) // eslint-disable-line
|
|
|
@ -182,7 +186,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleEnter = async(e:any) => { |
|
|
|
const handleEnter = async (e: any) => { |
|
|
|
let inputPath = e.target.value |
|
|
|
let inputPath = e.target.value |
|
|
|
inputPath = helper.removeMultipleSlashes(trimTestDirInput(inputPath)) |
|
|
|
inputPath = helper.removeMultipleSlashes(trimTestDirInput(inputPath)) |
|
|
|
setInputPathValue(inputPath) |
|
|
|
setInputPathValue(inputPath) |
|
|
@ -194,7 +198,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleCreateFolder = async() => { |
|
|
|
const handleCreateFolder = async () => { |
|
|
|
let inputPath = trimTestDirInput(inputPathValue) |
|
|
|
let inputPath = trimTestDirInput(inputPathValue) |
|
|
|
let path = helper.removeMultipleSlashes(inputPath) |
|
|
|
let path = helper.removeMultipleSlashes(inputPath) |
|
|
|
if (path !== '/') path = helper.removeTrailingSlashes(path) |
|
|
|
if (path !== '/') path = helper.removeTrailingSlashes(path) |
|
|
@ -266,7 +270,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
if (withoutLabel) { |
|
|
|
if (withoutLabel) { |
|
|
|
const contractCard: any = ( |
|
|
|
const contractCard: any = ( |
|
|
|
<div id={runningTestFileName} data-id="testTabSolidityUnitTestsOutputheader" className="pt-1"> |
|
|
|
<div id={runningTestFileName} data-id="testTabSolidityUnitTestsOutputheader" className="pt-1"> |
|
|
|
<span className="font-weight-bold">{contract ? contract: ''} ({filename})</span> |
|
|
|
<span className="font-weight-bold">{contract ? contract : ''} ({filename})</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
) |
|
|
|
) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, contractCard])) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, contractCard])) |
|
|
@ -278,7 +282,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
title="At least one contract test failed" |
|
|
|
title="At least one contract test failed" |
|
|
|
> |
|
|
|
> |
|
|
|
FAIL |
|
|
|
FAIL |
|
|
|
</div>)
|
|
|
|
</div>) |
|
|
|
else label = (<div |
|
|
|
else label = (<div |
|
|
|
className="alert-success d-inline-block mb-1 mr-1 p-1 passed_{runningTestFileName}" |
|
|
|
className="alert-success d-inline-block mb-1 mr-1 p-1 passed_{runningTestFileName}" |
|
|
|
title="All contract tests passed" |
|
|
|
title="All contract tests passed" |
|
|
@ -303,17 +307,17 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
// show filename and contract
|
|
|
|
// show filename and contract
|
|
|
|
renderContract(filename, contract, index) |
|
|
|
renderContract(filename, contract, index) |
|
|
|
// show tests
|
|
|
|
// show tests
|
|
|
|
for(const test of tests) { |
|
|
|
for (const test of tests) { |
|
|
|
if(!test.rendered) { |
|
|
|
if (!test.rendered) { |
|
|
|
let debugBtn |
|
|
|
let debugBtn |
|
|
|
if (test.debugTxHash) { |
|
|
|
if (test.debugTxHash) { |
|
|
|
const { web3, debugTxHash } = test |
|
|
|
const { web3, debugTxHash } = test |
|
|
|
debugBtn = ( |
|
|
|
debugBtn = ( |
|
|
|
<div id={test.value.replaceAll(' ', '_')} className="btn border btn btn-sm ml-1" style={{ cursor: 'pointer' }} title="Start debugging" onClick={() => startDebug(debugTxHash, web3)}> |
|
|
|
<div id={test.value.replaceAll(' ', '_')} className="btn border btn btn-sm ml-1" style={{ cursor: 'pointer' }} title="Start debugging" onClick={() => startDebug(debugTxHash, web3)}> |
|
|
|
<i className="fas fa-bug"></i> |
|
|
|
<i className="fas fa-bug"></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
) |
|
|
|
) |
|
|
|
}
|
|
|
|
} |
|
|
|
if (test.type === 'testPass') { |
|
|
|
if (test.type === 'testPass') { |
|
|
|
if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) |
|
|
|
if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) |
|
|
|
const testPassCard: any = ( |
|
|
|
const testPassCard: any = ( |
|
|
@ -325,71 +329,71 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
> |
|
|
|
> |
|
|
|
<div className="d-flex my-1 align-items-start justify-content-between"> |
|
|
|
<div className="d-flex my-1 align-items-start justify-content-between"> |
|
|
|
<span > ✓ {test.value}</span> |
|
|
|
<span > ✓ {test.value}</span> |
|
|
|
{debugBtn} |
|
|
|
{debugBtn} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
) |
|
|
|
) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, testPassCard])) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, testPassCard])) |
|
|
|
test.rendered = true |
|
|
|
test.rendered = true |
|
|
|
} else if (test.type === 'testFailure') { |
|
|
|
} else if (test.type === 'testFailure') { |
|
|
|
if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) |
|
|
|
if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) |
|
|
|
if (!test.assertMethod) { |
|
|
|
if (!test.assertMethod) { |
|
|
|
const testFailCard1: any = (<div |
|
|
|
const testFailCard1: any = (<div |
|
|
|
className="bg-light mb-2 px-2 testLog d-flex flex-column text-danger border-0" |
|
|
|
className="bg-light mb-2 px-2 testLog d-flex flex-column text-danger border-0" |
|
|
|
id={"UTContext" + test.context} |
|
|
|
id={"UTContext" + test.context} |
|
|
|
onClick={() => highlightLocation(test.location, test.filename)} |
|
|
|
onClick={() => highlightLocation(test.location, test.filename)} |
|
|
|
> |
|
|
|
> |
|
|
|
<div className="d-flex my-1 align-items-start justify-content-between"> |
|
|
|
<div className="d-flex my-1 align-items-start justify-content-between"> |
|
|
|
<span> ✘ {test.value}</span> |
|
|
|
<span> ✘ {test.value}</span> |
|
|
|
{debugBtn} |
|
|
|
{debugBtn} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<span className="text-dark">Error Message:</span> |
|
|
|
<span className="text-dark">Error Message:</span> |
|
|
|
<span className="pb-2 text-break">"{test.errMsg}"</span> |
|
|
|
<span className="pb-2 text-break">"{test.errMsg}"</span> |
|
|
|
</div>) |
|
|
|
</div>) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, testFailCard1])) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, testFailCard1])) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
const preposition = test.assertMethod === 'equal' || test.assertMethod === 'notEqual' ? 'to' : '' |
|
|
|
const preposition = test.assertMethod === 'equal' || test.assertMethod === 'notEqual' ? 'to' : '' |
|
|
|
const method = test.assertMethod === 'ok' ? '' : test.assertMethod |
|
|
|
const method = test.assertMethod === 'ok' ? '' : test.assertMethod |
|
|
|
const expected = test.assertMethod === 'ok' ? '\'true\'' : test.expected |
|
|
|
const expected = test.assertMethod === 'ok' ? '\'true\'' : test.expected |
|
|
|
const testFailCard2: any = (<div |
|
|
|
const testFailCard2: any = (<div |
|
|
|
className="bg-light mb-2 px-2 testLog d-flex flex-column text-danger border-0" |
|
|
|
className="bg-light mb-2 px-2 testLog d-flex flex-column text-danger border-0" |
|
|
|
id={"UTContext" + test.context} |
|
|
|
id={"UTContext" + test.context} |
|
|
|
onClick={() => highlightLocation(test.location, test.filename)} |
|
|
|
onClick={() => highlightLocation(test.location, test.filename)} |
|
|
|
> |
|
|
|
> |
|
|
|
<div className="d-flex my-1 align-items-start justify-content-between">
|
|
|
|
<div className="d-flex my-1 align-items-start justify-content-between"> |
|
|
|
<span> ✘ {test.value}</span> |
|
|
|
<span> ✘ {test.value}</span> |
|
|
|
{debugBtn} |
|
|
|
{debugBtn} |
|
|
|
</div>
|
|
|
|
</div> |
|
|
|
<span className="text-dark">Error Message:</span> |
|
|
|
<span className="text-dark">Error Message:</span> |
|
|
|
<span className="pb-2 text-break">"{test.errMsg}"</span> |
|
|
|
<span className="pb-2 text-break">"{test.errMsg}"</span> |
|
|
|
<span className="text-dark">Assertion:</span> |
|
|
|
<span className="text-dark">Assertion:</span> |
|
|
|
<div className="d-flex flex-wrap"> |
|
|
|
<div className="d-flex flex-wrap"> |
|
|
|
<span>Expected value should be</span> |
|
|
|
<span>Expected value should be</span> |
|
|
|
<div className="mx-1 font-weight-bold">{method}</div> |
|
|
|
<div className="mx-1 font-weight-bold">{method}</div> |
|
|
|
<div>{preposition} {expected}</div> |
|
|
|
<div>{preposition} {expected}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<span className="text-dark">Received value:</span> |
|
|
|
<span className="text-dark">Received value:</span> |
|
|
|
<span>{test.returned}</span> |
|
|
|
<span>{test.returned}</span> |
|
|
|
<span className="text-dark text-sm pb-2">Skipping the remaining tests of the function.</span> |
|
|
|
<span className="text-dark text-sm pb-2">Skipping the remaining tests of the function.</span> |
|
|
|
</div>) |
|
|
|
</div>) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, testFailCard2])) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, testFailCard2])) |
|
|
|
} |
|
|
|
} |
|
|
|
test.rendered = true |
|
|
|
test.rendered = true |
|
|
|
} else if (test.type === 'logOnly') { |
|
|
|
} else if (test.type === 'logOnly') { |
|
|
|
if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) |
|
|
|
if (test.hhLogs && test.hhLogs.length) printHHLogs(test.hhLogs, test.value) |
|
|
|
test.rendered = true |
|
|
|
test.rendered = true |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const showTestsResult = () => { |
|
|
|
const showTestsResult = () => { |
|
|
|
const filenames = Object.keys(testsResultByFilename) |
|
|
|
const filenames = Object.keys(testsResultByFilename) |
|
|
|
for(const filename of filenames) { |
|
|
|
for (const filename of filenames) { |
|
|
|
const fileTestsResult = testsResultByFilename[filename] |
|
|
|
const fileTestsResult = testsResultByFilename[filename] |
|
|
|
const contracts = Object.keys(fileTestsResult) |
|
|
|
const contracts = Object.keys(fileTestsResult) |
|
|
|
for(const contract of contracts) { |
|
|
|
for (const contract of contracts) { |
|
|
|
if(contract && contract !== 'summary' && contract !== 'errors') { |
|
|
|
if (contract && contract !== 'summary' && contract !== 'errors') { |
|
|
|
runningTestFileName = cleanFileName(filename, contract) |
|
|
|
runningTestFileName = cleanFileName(filename, contract) |
|
|
|
const tests = fileTestsResult[contract] |
|
|
|
const tests = fileTestsResult[contract] |
|
|
|
if (tests?.length) { |
|
|
|
if (tests?.length) { |
|
|
@ -402,19 +406,19 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
const errors = fileTestsResult['errors'] |
|
|
|
const errors = fileTestsResult['errors'] |
|
|
|
if (errors && errors.errors) { |
|
|
|
if (errors && errors.errors) { |
|
|
|
errors.errors.forEach((err: any) => { |
|
|
|
errors.errors.forEach((err: any) => { |
|
|
|
const errorCard: any = <Renderer message={err.formattedMessage || err.message} plugin={testTab} opt={{ type: err.severity, errorType: err.type }} /> |
|
|
|
const errorCard: any = <Renderer message={err.formattedMessage || err.message} plugin={testTab} opt={{ type: err.severity, errorType: err.type }} /> |
|
|
|
setTestsOutput(prevCards => ([...prevCards, errorCard])) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, errorCard])) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} else if (errors && Array.isArray(errors) && (errors[0].message || errors[0].formattedMessage)) { |
|
|
|
} else if (errors && Array.isArray(errors) && (errors[0].message || errors[0].formattedMessage)) { |
|
|
|
errors.forEach((err) => { |
|
|
|
errors.forEach((err) => { |
|
|
|
const errorCard: any = <Renderer message={err.formattedMessage || err.message} plugin={testTab} opt={{ type: err.severity, errorType: err.type }} /> |
|
|
|
const errorCard: any = <Renderer message={err.formattedMessage || err.message} plugin={testTab} opt={{ type: err.severity, errorType: err.type }} /> |
|
|
|
setTestsOutput(prevCards => ([...prevCards, errorCard])) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, errorCard])) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} else if (errors && !errors.errors && !Array.isArray(errors)) { |
|
|
|
} else if (errors && !errors.errors && !Array.isArray(errors)) { |
|
|
|
// To track error like this: https://github.com/ethereum/remix/pull/1438
|
|
|
|
// To track error like this: https://github.com/ethereum/remix/pull/1438
|
|
|
|
const errorCard: any = <Renderer message={errors.formattedMessage || errors.message} plugin={testTab} opt={{ type: 'error' }} /> |
|
|
|
const errorCard: any = <Renderer message={errors.formattedMessage || errors.message} plugin={testTab} opt={{ type: 'error' }} /> |
|
|
|
setTestsOutput(prevCards => ([...prevCards, errorCard])) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, errorCard])) |
|
|
|
}
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// show summary
|
|
|
|
// show summary
|
|
|
@ -429,17 +433,17 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
setTestsOutput(prevCards => ([...prevCards, summaryCard])) |
|
|
|
setTestsOutput(prevCards => ([...prevCards, summaryCard])) |
|
|
|
fileTestsResult['summary']['rendered'] = true |
|
|
|
fileTestsResult['summary']['rendered'] = true |
|
|
|
} |
|
|
|
} |
|
|
|
}
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const testCallback = (result: any) => { |
|
|
|
const testCallback = (result: any) => { |
|
|
|
if(result.filename) { |
|
|
|
if (result.filename) { |
|
|
|
if(!testsResultByFilename[result.filename]) { |
|
|
|
if (!testsResultByFilename[result.filename]) { |
|
|
|
testsResultByFilename[result.filename] = {} |
|
|
|
testsResultByFilename[result.filename] = {} |
|
|
|
testsResultByFilename[result.filename]['summary'] = {} |
|
|
|
testsResultByFilename[result.filename]['summary'] = {} |
|
|
|
} |
|
|
|
} |
|
|
|
if(result.type === 'contract') { |
|
|
|
if (result.type === 'contract') { |
|
|
|
testsResultByFilename[result.filename][result.value]= {} |
|
|
|
testsResultByFilename[result.filename][result.value] = {} |
|
|
|
testsResultByFilename[result.filename][result.value] = [] |
|
|
|
testsResultByFilename[result.filename][result.value] = [] |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// Set that this test is not rendered on UI
|
|
|
|
// Set that this test is not rendered on UI
|
|
|
@ -469,17 +473,17 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
if (result) { |
|
|
|
if (result) { |
|
|
|
const totalTime = parseFloat(result.totalTime).toFixed(2) |
|
|
|
const totalTime = parseFloat(result.totalTime).toFixed(2) |
|
|
|
const testsSummary = { filename, passed: result.totalPassing, failed: result.totalFailing, timeTaken: totalTime, rendered: false } |
|
|
|
const testsSummary = { filename, passed: result.totalPassing, failed: result.totalFailing, timeTaken: totalTime, rendered: false } |
|
|
|
testsResultByFilename[filename]['summary']= testsSummary |
|
|
|
testsResultByFilename[filename]['summary'] = testsSummary |
|
|
|
showTestsResult() |
|
|
|
showTestsResult() |
|
|
|
} else if (_errors) { |
|
|
|
} else if (_errors) { |
|
|
|
if(!testsResultByFilename[filename]) { |
|
|
|
if (!testsResultByFilename[filename]) { |
|
|
|
testsResultByFilename[filename] = {} |
|
|
|
testsResultByFilename[filename] = {} |
|
|
|
} |
|
|
|
} |
|
|
|
testsResultByFilename[filename]['errors'] = _errors |
|
|
|
testsResultByFilename[filename]['errors'] = _errors |
|
|
|
setTestsExecutionStoppedErrorHidden(false) |
|
|
|
setTestsExecutionStoppedErrorHidden(false) |
|
|
|
showTestsResult() |
|
|
|
showTestsResult() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (hasBeenStopped.current && (readyTestsNumber !== runningTestsNumber)) { |
|
|
|
if (hasBeenStopped.current && (readyTestsNumber !== runningTestsNumber)) { |
|
|
|
// if all tests has been through before stopping no need to print this.
|
|
|
|
// if all tests has been through before stopping no need to print this.
|
|
|
|
setTestsExecutionStoppedHidden(false) |
|
|
|
setTestsExecutionStoppedHidden(false) |
|
|
@ -557,7 +561,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const updateRunAction = async (currentFile : any = null) => { |
|
|
|
const updateRunAction = async (currentFile: any = null) => { |
|
|
|
const isSolidityActive = await testTab.appManager.isActive('solidity') |
|
|
|
const isSolidityActive = await testTab.appManager.isActive('solidity') |
|
|
|
if (!isSolidityActive || !selectedTests.current?.length) { |
|
|
|
if (!isSolidityActive || !selectedTests.current?.length) { |
|
|
|
setDisableRunButton(true) |
|
|
|
setDisableRunButton(true) |
|
|
@ -581,7 +585,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
return selectedTestsList.map(testFileObj => testFileObj.fileName) |
|
|
|
return selectedTestsList.map(testFileObj => testFileObj.fileName) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const toggleCheckbox = (eChecked: any, index:any) => { |
|
|
|
const toggleCheckbox = (eChecked: any, index: any) => { |
|
|
|
testFiles[index].checked = eChecked |
|
|
|
testFiles[index].checked = eChecked |
|
|
|
setTestFiles(testFiles) |
|
|
|
setTestFiles(testFiles) |
|
|
|
selectedTests.current = getCurrentSelectedTests() |
|
|
|
selectedTests.current = getCurrentSelectedTests() |
|
|
@ -599,10 +603,10 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const checkAll = (event: any) => { |
|
|
|
const checkAll = (event: any) => { |
|
|
|
testFiles.forEach((testFileObj) => testFileObj.checked = event.target.checked) |
|
|
|
testFiles.forEach((testFileObj) => testFileObj.checked = event.target.checked) |
|
|
|
setTestFiles(testFiles) |
|
|
|
setTestFiles(testFiles) |
|
|
|
setCheckSelectAll(event.target.checked) |
|
|
|
setCheckSelectAll(event.target.checked) |
|
|
|
if(event.target.checked) { |
|
|
|
if (event.target.checked) { |
|
|
|
selectedTests.current = getCurrentSelectedTests() |
|
|
|
selectedTests.current = getCurrentSelectedTests() |
|
|
|
setDisableRunButton(false) |
|
|
|
setDisableRunButton(false) |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -612,28 +616,28 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const updateTestFileList = () => { |
|
|
|
const updateTestFileList = () => { |
|
|
|
if(allTests.current?.length) { |
|
|
|
if (allTests.current?.length) { |
|
|
|
testFiles = allTests.current.map((testFile: any) => { return {'fileName': testFile, 'checked': true }}) |
|
|
|
testFiles = allTests.current.map((testFile: any) => { return { 'fileName': testFile, 'checked': true } }) |
|
|
|
setCheckSelectAll(true) |
|
|
|
setCheckSelectAll(true) |
|
|
|
} |
|
|
|
} |
|
|
|
else
|
|
|
|
else |
|
|
|
testFiles = [] |
|
|
|
testFiles = [] |
|
|
|
setTestFiles(testFiles) |
|
|
|
setTestFiles(testFiles) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div className="px-2" id="testView"> |
|
|
|
<div className="px-2" id="testView"> |
|
|
|
<div className="infoBox"> |
|
|
|
<div className="infoBox"> |
|
|
|
<p className="text-lg"> Test your smart contract in Solidity.</p> |
|
|
|
<p className="text-lg"> Test your smart contract in Solidity.</p> |
|
|
|
<p> Select directory to load and generate test files.</p> |
|
|
|
<p> Select directory to load and generate test files.</p> |
|
|
|
<label>Test directory:</label> |
|
|
|
<label>Test directory:</label> |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<div className="d-flex p-2"> |
|
|
|
<div className="d-flex p-2"> |
|
|
|
<datalist id="utPathList">{ |
|
|
|
<datalist id="utPathList">{ |
|
|
|
pathOptions.map(function (path) { |
|
|
|
pathOptions.map(function (path) { |
|
|
|
return <option key={path}>{path}</option> |
|
|
|
return <option key={path}>{path}</option> |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
</datalist> |
|
|
|
</datalist> |
|
|
|
<input |
|
|
|
<input |
|
|
|
placeholder={defaultPath} |
|
|
|
placeholder={defaultPath} |
|
|
@ -644,8 +648,8 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
name="utPath" |
|
|
|
name="utPath" |
|
|
|
value={inputPathValue} |
|
|
|
value={inputPathValue} |
|
|
|
title="Press 'Enter' to change the path for test files." |
|
|
|
title="Press 'Enter' to change the path for test files." |
|
|
|
style= {{ backgroundImage: "var(--primary)"}} |
|
|
|
style={{ backgroundImage: "var(--primary)" }} |
|
|
|
onKeyUp= {handleTestDirInput} |
|
|
|
onKeyUp={handleTestDirInput} |
|
|
|
onChange={handleEnter} |
|
|
|
onChange={handleEnter} |
|
|
|
/> |
|
|
|
/> |
|
|
|
<button |
|
|
|
<button |
|
|
@ -657,65 +661,65 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { |
|
|
|
> |
|
|
|
> |
|
|
|
Create |
|
|
|
Create |
|
|
|
</button> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div>
|
|
|
|
</div> |
|
|
|
<div className="d-flex p-2"> |
|
|
|
<div> |
|
|
|
<button |
|
|
|
<div className="d-flex p-2"> |
|
|
|
className="btn border w-50" |
|
|
|
<button |
|
|
|
data-id="testTabGenerateTestFile" |
|
|
|
className="btn border w-50" |
|
|
|
title="Generate sample test file." |
|
|
|
data-id="testTabGenerateTestFile" |
|
|
|
disabled={disableGenerateButton} |
|
|
|
title="Generate sample test file." |
|
|
|
onClick={() => { |
|
|
|
disabled={disableGenerateButton} |
|
|
|
testTabLogic.generateTestFile() |
|
|
|
onClick={() => { |
|
|
|
updateForNewCurrent() |
|
|
|
testTabLogic.generateTestFile() |
|
|
|
}} |
|
|
|
updateForNewCurrent() |
|
|
|
> |
|
|
|
}} |
|
|
|
Generate |
|
|
|
> |
|
|
|
</button> |
|
|
|
Generate |
|
|
|
<a className="btn border text-decoration-none pr-0 d-flex w-50 ml-2" title="Check out documentation." target="__blank" href="https://remix-ide.readthedocs.io/en/latest/unittesting.html#test-directory"> |
|
|
|
</button> |
|
|
|
<label className="btn p-1 ml-2 m-0">How to use...</label> |
|
|
|
<a className="btn border text-decoration-none pr-0 d-flex w-50 ml-2" title="Check out documentation." target="__blank" href="https://remix-ide.readthedocs.io/en/latest/unittesting.html#test-directory"> |
|
|
|
</a> |
|
|
|
<label className="btn p-1 ml-2 m-0">How to use...</label> |
|
|
|
</div> |
|
|
|
</a> |
|
|
|
<div className="d-flex p-2"> |
|
|
|
</div> |
|
|
|
<button id="runTestsTabRunAction" title={runButtonTitle} data-id="testTabRunTestsTabRunAction" className="w-50 btn btn-primary" disabled={disableRunButton} onClick={runTests}> |
|
|
|
<div className="d-flex p-2"> |
|
|
|
<span className="fas fa-play ml-2"></span> |
|
|
|
<button id="runTestsTabRunAction" title={runButtonTitle} data-id="testTabRunTestsTabRunAction" className="w-50 btn btn-primary" disabled={disableRunButton} onClick={runTests}> |
|
|
|
<label className="labelOnBtn btn btn-primary p-1 ml-2 m-0">Run</label> |
|
|
|
<span className="fas fa-play ml-2"></span> |
|
|
|
</button> |
|
|
|
<label className="labelOnBtn btn btn-primary p-1 ml-2 m-0">Run</label> |
|
|
|
<button id="runTestsTabStopAction" data-id="testTabRunTestsTabStopAction" className="w-50 pl-2 ml-2 btn btn-secondary" disabled={disableStopButton} title="Stop running tests" onClick={stopTests}> |
|
|
|
</button> |
|
|
|
<span className="fas fa-stop ml-2"></span> |
|
|
|
<button id="runTestsTabStopAction" data-id="testTabRunTestsTabStopAction" className="w-50 pl-2 ml-2 btn btn-secondary" disabled={disableStopButton} title="Stop running tests" onClick={stopTests}> |
|
|
|
<label className="labelOnBtn btn btn-secondary p-1 ml-2 m-0" id="runTestsTabStopActionLabel">{stopButtonLabel}</label> |
|
|
|
<span className="fas fa-stop ml-2"></span> |
|
|
|
</button> |
|
|
|
<label className="labelOnBtn btn btn-secondary p-1 ml-2 m-0" id="runTestsTabStopActionLabel">{stopButtonLabel}</label> |
|
|
|
</div> |
|
|
|
</button> |
|
|
|
<div className="d-flex align-items-center mx-3 pb-2 mt-2 border-bottom"> |
|
|
|
</div> |
|
|
|
<input id="checkAllTests" |
|
|
|
<div className="d-flex align-items-center mx-3 pb-2 mt-2 border-bottom"> |
|
|
|
type="checkbox" |
|
|
|
<input id="checkAllTests" |
|
|
|
data-id="testTabCheckAllTests" |
|
|
|
type="checkbox" |
|
|
|
onClick={checkAll} |
|
|
|
data-id="testTabCheckAllTests" |
|
|
|
checked={checkSelectAll} |
|
|
|
onClick={checkAll} |
|
|
|
onChange={() => {}} // eslint-disable-line
|
|
|
|
checked={checkSelectAll} |
|
|
|
/> |
|
|
|
onChange={() => { }} // eslint-disable-line
|
|
|
|
<label className="text-nowrap pl-2 mb-0" htmlFor="checkAllTests"> Select all </label> |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<label className="text-nowrap pl-2 mb-0" htmlFor="checkAllTests"> Select all </label> |
|
|
|
<div className="testList py-2 mt-0 border-bottom">{testFiles?.length ? testFiles.map((testFileObj: any, index) => { |
|
|
|
</div> |
|
|
|
const elemId = `singleTest${testFileObj.fileName}` |
|
|
|
<div className="testList py-2 mt-0 border-bottom">{testFiles?.length ? testFiles.map((testFileObj: any, index) => { |
|
|
|
return ( |
|
|
|
const elemId = `singleTest${testFileObj.fileName}` |
|
|
|
<div className="d-flex align-items-center py-1" key={index}> |
|
|
|
return ( |
|
|
|
<input className="singleTest" id={elemId} onChange={(e) => toggleCheckbox(e.target.checked, index)} type="checkbox" checked={testFileObj.checked}/> |
|
|
|
<div className="d-flex align-items-center py-1" key={index}> |
|
|
|
<label className="singleTestLabel text-nowrap pl-2 mb-0" htmlFor={elemId}>{testFileObj.fileName}</label> |
|
|
|
<input className="singleTest" id={elemId} onChange={(e) => toggleCheckbox(e.target.checked, index)} type="checkbox" checked={testFileObj.checked} /> |
|
|
|
</div> |
|
|
|
<label className="singleTestLabel text-nowrap pl-2 mb-0" htmlFor={elemId}>{testFileObj.fileName}</label> |
|
|
|
) |
|
|
|
</div> |
|
|
|
})
|
|
|
|
) |
|
|
|
: "No test file available" } </div> |
|
|
|
}) |
|
|
|
<div className="align-items-start flex-column mt-2 mx-3 mb-0"> |
|
|
|
: "No test file available"} </div> |
|
|
|
<span className='text-info h6' hidden={progressBarHidden}>Progress: {readyTestsNumber} finished (of {runningTestsNumber})</span> |
|
|
|
<div className="align-items-start flex-column mt-2 mx-3 mb-0"> |
|
|
|
<label className="text-warning h6" data-id="testTabTestsExecutionStopped" hidden={testsExecutionStoppedHidden}>The test execution has been stopped</label> |
|
|
|
<span className='text-info h6' hidden={progressBarHidden}>Progress: {readyTestsNumber} finished (of {runningTestsNumber})</span> |
|
|
|
<label className="text-danger h6" data-id="testTabTestsExecutionStoppedError" hidden={testsExecutionStoppedErrorHidden}>The test execution has been stopped because of error(s) in your test file</label> |
|
|
|
<label className="text-warning h6" data-id="testTabTestsExecutionStopped" hidden={testsExecutionStoppedHidden}>The test execution has been stopped</label> |
|
|
|
</div> |
|
|
|
<label className="text-danger h6" data-id="testTabTestsExecutionStoppedError" hidden={testsExecutionStoppedErrorHidden}>The test execution has been stopped because of error(s) in your test file</label> |
|
|
|
<div>{testsOutput}</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div>{testsOutput}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|