@ -17,8 +17,6 @@ var { UnitTestRunner, assertLibCode } = require('@remix-project/remix-tests')
const _paq = window . _paq = window . _paq || [ ]
// const TestTabLogic = require('./testTab/testTab')
const profile = {
name : 'solidityUnitTesting' ,
displayName : 'Solidity unit testing' ,
@ -43,15 +41,8 @@ module.exports = class TestTab extends ViewPlugin {
this . renderer = new Renderer ( this )
this . testRunner = new UnitTestRunner ( )
this . testTabLogic = new TestTabLogic ( this . fileManager , helper )
this . hasBeenStopped = false
this . runningTestsNumber = 0
this . readyTestsNumber = 0
this . areTestsRunning = false
this . defaultPath = 'tests'
this . offsetToLineColumnConverter = offsetToLineColumnConverter
this . allFilesInvolved = [ '.deps/remix-tests/remix_tests.sol' , '.deps/remix-tests/remix_accounts.sol' ]
this . isDebugging = false
this . currentErrors = [ ]
this . element = document . createElement ( 'div' )
appManager . event . on ( 'activate' , ( name ) => {
@ -150,300 +141,6 @@ module.exports = class TestTab extends ViewPlugin {
this . fileManager . events . on ( 'currentFileChanged' , ( file , provider ) => this . updateForNewCurrent ( file ) )
}
async updateForNewCurrent ( 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
if ( this . currentErrors ) {
if ( Array . isArray ( this . currentErrors ) && this . currentErrors . length > 0 ) {
const errFiles = this . currentErrors . map ( err => { if ( err . sourceLocation && err . sourceLocation . file ) return err . sourceLocation . file } )
if ( errFiles . includes ( file ) ) return
} else if ( this . currentErrors . sourceLocation && this . currentErrors . sourceLocation . file && this . 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 ( this . isDebugging && this . allFilesInvolved . includes ( file ) ) return
this . data . allTests = [ ]
this . updateTestFileList ( )
this . clearResults ( )
this . updateGenerateFileAction ( )
if ( ! this . areTestsRunning ) this . updateRunAction ( file )
try {
await this . testTabLogic . getTests ( ( error , tests ) => {
if ( error ) return tooltip ( error )
this . data . allTests = tests
this . data . selectedTests = [ ... this . data . allTests ]
this . updateTestFileList ( tests )
if ( ! this . testsOutput ) return // eslint-disable-line
} )
} catch ( e ) {
console . log ( e )
}
}
createSingleTest ( testFile ) {
return yo `
< div class = "d-flex align-items-center py-1" >
< input class = "singleTest" id = "singleTest${testFile}" onchange = $ { ( e ) => this . toggleCheckbox ( e . target . checked , testFile ) } type = "checkbox" checked = "true" >
< label class = "singleTestLabel text-nowrap pl-2 mb-0" for = "singleTest${testFile}" > $ { testFile } < / l a b e l >
< / d i v >
`
}
listTests ( ) {
if ( ! this . data . allTests || ! this . data . allTests . length ) return [ ]
return this . data . allTests . map (
testFile => this . createSingleTest ( testFile )
)
}
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 )
}
printHHLogs ( logsArr , testName ) {
let finalLogs = ` <b> ${ testName } :</b> \n `
for ( const log of logsArr ) {
let formattedLog
// Hardhat implements the same formatting options that can be found in Node.js' console.log,
// which in turn uses util.format: https://nodejs.org/dist/latest-v12.x/docs/api/util.html#util_util_format_format_args
// For example: console.log("Name: %s, Age: %d", remix, 6) will log 'Name: remix, Age: 6'
// We check first arg to determine if 'util.format' is needed
if ( typeof log [ 0 ] === 'string' && ( log [ 0 ] . includes ( '%s' ) || log [ 0 ] . includes ( '%d' ) ) ) {
formattedLog = format ( log [ 0 ] , ... log . slice ( 1 ) )
} else {
formattedLog = log . join ( ' ' )
}
finalLogs = finalLogs + ' ' + formattedLog + '\n'
}
_paq . push ( [ 'trackEvent' , 'solidityUnitTesting' , 'hardhat' , 'console.log' ] )
this . call ( 'terminal' , 'log' , { type : 'info' , value : finalLogs } )
}
testCallback ( result , runningTests ) {
this . testsOutput . hidden = false
let debugBtn = yo ` `
if ( ( result . type === 'testPass' || result . type === 'testFailure' ) && result . debugTxHash ) {
const { web3 , debugTxHash } = result
debugBtn = yo ` <div id= ${ result . value . replaceAll ( ' ' , '_' ) } class="btn border btn btn-sm ml-1" title="Start debugging" onclick= ${ ( ) => this . startDebug ( debugTxHash , web3 ) } >
< i class = "fas fa-bug" > < / i >
< / d i v > `
debugBtn . style . cursor = 'pointer'
}
if ( result . type === 'contract' ) {
this . testSuite = result . value
if ( this . testSuites ) {
this . testSuites . push ( this . testSuite )
} else {
this . testSuites = [ this . testSuite ]
}
this . rawFileName = result . filename
this . runningTestFileName = this . cleanFileName ( this . rawFileName , this . testSuite )
this . outputHeader = yo `
< div id = "${this.runningTestFileName}" data - id = "testTabSolidityUnitTestsOutputheader" class = "pt-1" >
< span class = "font-weight-bold" > $ { this . testSuite } ( $ { this . rawFileName } ) < / s p a n >
< / d i v >
`
this . testsOutput . appendChild ( this . outputHeader )
} else if ( result . type === 'testPass' ) {
if ( result . hhLogs && result . hhLogs . length ) this . printHHLogs ( result . hhLogs , result . value )
this . testsOutput . appendChild ( yo `
< div
id = "${this.runningTestFileName}"
data - id = "testTabSolidityUnitTestsOutputheader"
class = "${css.testPass} ${css.testLog} bg-light mb-2 px-2 text-success border-0"
onclick = $ { ( ) => this . discardHighlight ( ) }
>
< div class = "d-flex my-1 align-items-start justify-content-between" >
< span style = "margin-block: auto" > ✓ $ { result . value } < / s p a n >
$ { debugBtn }
< / d i v >
< / d i v >
` )
} else if ( result . type === 'testFailure' ) {
if ( result . hhLogs && result . hhLogs . length ) this . printHHLogs ( result . hhLogs , result . value )
if ( ! result . assertMethod ) {
this . testsOutput . appendChild ( yo `
< div
class = "bg-light mb-2 px-2 ${css.testLog} d-flex flex-column text-danger border-0"
id = "UTContext${result.context}"
onclick = $ { ( ) => this . highlightLocation ( result . location , runningTests , result . filename ) }
>
< div class = "d-flex my-1 align-items-start justify-content-between" >
< span > ✘ $ { result . value } < / s p a n >
$ { debugBtn }
< / d i v >
< span class = "text-dark" > Error Message : < / s p a n >
< span class = "pb-2 text-break" > "${result.errMsg}" < / s p a n >
< / d i v >
` )
} else {
const preposition = result . assertMethod === 'equal' || result . assertMethod === 'notEqual' ? 'to' : ''
const method = result . assertMethod === 'ok' ? '' : result . assertMethod
const expected = result . assertMethod === 'ok' ? '\'true\'' : result . expected
this . testsOutput . appendChild ( yo `
< div
class = "bg-light mb-2 px-2 ${css.testLog} d-flex flex-column text-danger border-0"
id = "UTContext${result.context}"
onclick = $ { ( ) => this . highlightLocation ( result . location , runningTests , result . filename ) }
>
< div class = "d-flex my-1 align-items-start justify-content-between" >
< span > ✘ $ { result . value } < / s p a n >
$ { debugBtn }
< / d i v >
< span class = "text-dark" > Error Message : < / s p a n >
< span class = "pb-2 text-break" > "${result.errMsg}" < / s p a n >
< span class = "text-dark" > Assertion : < / s p a n >
< div class = "d-flex flex-wrap" >
< span > Expected value should be < / s p a n >
< div class = "mx-1 font-weight-bold" > $ { method } < / d i v >
< div > $ { preposition } $ { expected } < / d i v >
< / d i v >
< span class = "text-dark" > Received value : < / s p a n >
< span > $ { result . returned } < / s p a n >
< span class = "text-dark text-sm pb-2" > Skipping the remaining tests of the function . < / s p a n >
< / d i v >
` )
}
} else if ( result . type === 'logOnly' ) {
if ( result . hhLogs && result . hhLogs . length ) this . printHHLogs ( result . hhLogs , result . value )
}
}
resultsCallback ( _err , result , cb ) {
// total stats for the test
// result.passingNum
// result.failureNum
// result.timePassed
cb ( )
}
cleanFileName ( fileName , testSuite ) {
return fileName ? fileName . replace ( /\//g , '_' ) . replace ( /\./g , '_' ) + testSuite : fileName
}
setHeader ( status ) {
if ( status ) {
const label = yo `
< div
class = "alert-success d-inline-block mb-1 mr-1 p-1 passed_${this.runningTestFileName}"
title = "All contract tests passed"
>
PASS
< / d i v >
`
this . outputHeader && yo . update ( this . outputHeader , yo `
< div id = "${this.runningTestFileName}" data - id = "testTabSolidityUnitTestsOutputheader" class = "pt-1" >
$ { label } < span class = "font-weight-bold" > $ { this . testSuite } ( $ { this . rawFileName } ) < / s p a n >
< / d i v >
` )
} else {
const label = yo `
< div
class = "alert-danger d-inline-block mb-1 mr-1 p-1 failed_${this.runningTestFileName}"
title = "At least one contract test failed"
>
FAIL
< / d i v >
`
this . outputHeader && yo . update ( this . outputHeader , yo `
< div id = "${this.runningTestFileName}" data - id = "testTabSolidityUnitTestsOutputheader" class = "pt-1" >
$ { label } < span class = "font-weight-bold" > $ { this . testSuite } ( $ { this . rawFileName } ) < / s p a n >
< / d i v >
` )
}
}
updateFinalResult ( _errors , result , filename ) {
++ this . readyTestsNumber
this . testsOutput . hidden = false
if ( ! result && ( _errors && ( _errors . errors || ( Array . isArray ( _errors ) && ( _errors [ 0 ] . message || _errors [ 0 ] . formattedMessage ) ) ) ) ) {
this . testCallback ( { type : 'contract' , filename } )
this . currentErrors = _errors . errors
this . setHeader ( false )
}
if ( _errors && _errors . errors ) {
_errors . errors . forEach ( ( err ) => this . renderer . error ( err . formattedMessage || err . message , this . testsOutput , { type : err . severity , errorType : err . type } ) )
} else if ( _errors && Array . isArray ( _errors ) && ( _errors [ 0 ] . message || _errors [ 0 ] . formattedMessage ) ) {
_errors . forEach ( ( err ) => this . renderer . error ( err . formattedMessage || err . message , this . testsOutput , { type : err . severity , errorType : err . type } ) )
} else if ( _errors && ! _errors . errors && ! Array . isArray ( _errors ) ) {
// To track error like this: https://github.com/ethereum/remix/pull/1438
this . renderer . error ( _errors . formattedMessage || _errors . message , this . testsOutput , { type : 'error' } )
}
yo . update ( this . resultStatistics , this . createResultLabel ( ) )
if ( result ) {
const totalTime = parseFloat ( result . totalTime ) . toFixed ( 2 )
if ( result . totalPassing > 0 && result . totalFailing > 0 ) {
this . testsOutput . appendChild ( yo `
< div class = "d-flex alert-secondary mb-3 p-3 flex-column" >
< span class = "font-weight-bold" > Result for $ { filename } < / s p a n >
< span class = "text-success" > Passing : $ { result . totalPassing } < / s p a n >
< span class = "text-danger" > Failing : $ { result . totalFailing } < / s p a n >
< span > Total time : $ { totalTime } s < / s p a n >
< / d i v >
` )
} else if ( result . totalPassing > 0 && result . totalFailing <= 0 ) {
this . testsOutput . appendChild ( yo `
< div class = "d-flex alert-secondary mb-3 p-3 flex-column" >
< span class = "font-weight-bold" > Result for $ { filename } < / s p a n >
< span class = "text-success" > Passing : $ { result . totalPassing } < / s p a n >
< span > Total time : $ { totalTime } s < / s p a n >
< / d i v >
` )
} else if ( result . totalPassing <= 0 && result . totalFailing > 0 ) {
this . testsOutput . appendChild ( yo `
< div class = "d-flex alert-secondary mb-3 p-3 flex-column" >
< span class = "font-weight-bold" > Result for $ { filename } < / s p a n >
< span class = "text-danger" > Failing : $ { result . totalFailing } < / s p a n >
< span > Total time : $ { totalTime } s < / s p a n >
< / d i v >
` )
}
// fix for displaying right label for multiple tests (testsuites) in a single file
this . testSuites . forEach ( testSuite => {
this . testSuite = testSuite
this . runningTestFileName = this . cleanFileName ( filename , this . testSuite )
this . outputHeader = document . querySelector ( ` # ${ this . runningTestFileName } ` )
this . setHeader ( true )
} )
result . errors . forEach ( ( error , index ) => {
this . testSuite = error . context
this . runningTestFileName = this . cleanFileName ( filename , error . context )
this . outputHeader = document . querySelector ( ` # ${ this . runningTestFileName } ` )
const isFailingLabel = document . querySelector ( ` .failed_ ${ this . runningTestFileName } ` )
if ( ! isFailingLabel ) this . setHeader ( false )
} )
this . testsOutput . appendChild ( yo `
< div >
< p class = "text-info mb-2 border-top m-0" > < / p >
< / d i v >
` )
}
if ( this . hasBeenStopped && ( this . readyTestsNumber !== this . runningTestsNumber ) ) {
// if all tests has been through before stopping no need to print this.
this . testsExecutionStopped . hidden = false
}
if ( _errors ) this . testsExecutionStoppedError . hidden = false
if ( _errors || this . hasBeenStopped || this . readyTestsNumber === this . runningTestsNumber ) {
// All tests are ready or the operation has been canceled or there was a compilation error in one of the test files.
const stopBtn = document . getElementById ( 'runTestsTabStopAction' )
stopBtn . setAttribute ( 'disabled' , 'disabled' )
const stopBtnLabel = document . getElementById ( 'runTestsTabStopActionLabel' )
stopBtnLabel . innerText = 'Stop'
if ( this . data . selectedTests . length !== 0 ) {
const runBtn = document . getElementById ( 'runTestsTabRunAction' )
runBtn . removeAttribute ( 'disabled' )
}
this . areTestsRunning = false
}
}
async testFromPath ( path ) {
const fileContent = await this . fileManager . readFile ( path )
return this . testFromSource ( fileContent , path )
@ -485,167 +182,6 @@ module.exports = class TestTab extends ViewPlugin {
} )
}
runTest ( testFilePath , callback ) {
this . isDebugging = false
if ( this . hasBeenStopped ) {
this . updateFinalResult ( )
return
}
this . resultStatistics . hidden = false
this . fileManager . readFile ( testFilePath ) . then ( ( content ) => {
const runningTests = { }
runningTests [ testFilePath ] = { content }
const { currentVersion , evmVersion , optimize , runs , isUrl } = this . compileTab . getCurrentCompilerConfig ( )
const currentCompilerUrl = isUrl ? currentVersion : urlFromVersion ( currentVersion )
const compilerConfig = {
currentCompilerUrl ,
evmVersion ,
optimize ,
usingWorker : canUseWorker ( currentVersion ) ,
runs
}
const deployCb = async ( file , contractAddress ) => {
const compilerData = await this . call ( 'compilerArtefacts' , 'getCompilerAbstract' , file )
await this . call ( 'compilerArtefacts' , 'addResolvedContract' , contractAddress , compilerData )
}
this . testRunner . runTestSources (
runningTests ,
compilerConfig ,
( result ) => this . testCallback ( result , runningTests ) ,
( _err , result , cb ) => this . resultsCallback ( _err , result , cb ) ,
deployCb ,
( error , result ) => {
this . updateFinalResult ( error , result , testFilePath )
callback ( error )
} , ( url , cb ) => {
return this . contentImport . resolveAndSave ( url ) . then ( ( result ) => cb ( null , result ) ) . catch ( ( error ) => cb ( error . message ) )
} , { testFilePath }
)
} ) . catch ( ( error ) => {
if ( error ) return // eslint-disable-line
} )
}
clearResults ( ) {
yo . update ( this . resultStatistics , yo ` <span></span> ` )
this . call ( 'editor' , 'clearAnnotations' )
this . testsOutput . innerHTML = ''
this . testsOutput . hidden = true
this . testsExecutionStopped . hidden = true
this . testsExecutionStoppedError . hidden = true
}
runTests ( ) {
this . areTestsRunning = true
this . hasBeenStopped = false
this . readyTestsNumber = 0
this . runningTestsNumber = this . data . selectedTests . length
const stopBtn = document . getElementById ( 'runTestsTabStopAction' )
stopBtn . removeAttribute ( 'disabled' )
const runBtn = document . getElementById ( 'runTestsTabRunAction' )
runBtn . setAttribute ( 'disabled' , 'disabled' )
this . clearResults ( )
yo . update ( this . resultStatistics , this . createResultLabel ( ) )
const tests = this . data . selectedTests
if ( ! tests ) return
this . resultStatistics . hidden = tests . length === 0
_paq . push ( [ 'trackEvent' , 'solidityUnitTesting' , 'runTests' ] )
async . eachOfSeries ( tests , ( value , key , callback ) => {
if ( this . hasBeenStopped ) return
this . runTest ( value , callback )
} )
}
stopTests ( ) {
this . hasBeenStopped = true
const stopBtnLabel = document . getElementById ( 'runTestsTabStopActionLabel' )
stopBtnLabel . innerText = 'Stopping'
const stopBtn = document . getElementById ( 'runTestsTabStopAction' )
stopBtn . setAttribute ( 'disabled' , 'disabled' )
const runBtn = document . getElementById ( 'runTestsTabRunAction' )
runBtn . setAttribute ( 'disabled' , 'disabled' )
}
updateRunAction ( currentFile ) {
const el = yo `
< button id = "runTestsTabRunAction" title = "Run tests" data - id = "testTabRunTestsTabRunAction" class = "w-50 btn btn-primary" onclick = "${() => this.runTests()}" >
< span class = "fas fa-play ml-2" > < / s p a n >
< label class = "${css.labelOnBtn} btn btn-primary p-1 ml-2 m-0" > Run < / l a b e l >
< / b u t t o n >
`
const isSolidityActive = this . appManager . isActive ( 'solidity' )
if ( ! isSolidityActive || ! this . listTests ( ) . length ) {
el . setAttribute ( 'disabled' , 'disabled' )
if ( ! currentFile || ( currentFile && currentFile . split ( '.' ) . pop ( ) . toLowerCase ( ) !== 'sol' ) ) {
el . setAttribute ( 'title' , 'No solidity file selected' )
} else {
el . setAttribute ( 'title' , 'The "Solidity Plugin" should be activated' )
}
}
if ( ! this . runActionElement ) {
this . runActionElement = el
} else {
yo . update ( this . runActionElement , el )
}
return this . runActionElement
}
updateStopAction ( ) {
return yo `
< button id = "runTestsTabStopAction" data - id = "testTabRunTestsTabStopAction" class = "w-50 pl-2 ml-2 btn btn-secondary" disabled = "disabled" title = "Stop running tests" onclick = $ { ( ) => this . stopTests ( ) } " >
< span class = "fas fa-stop ml-2" > < / s p a n >
< label class = "${css.labelOnBtn} btn btn-secondary p-1 ml-2 m-0" id = "runTestsTabStopActionLabel" > Stop < / l a b e l >
< / b u t t o n >
`
}
updateTestFileList ( tests ) {
const testsMessage = ( tests && tests . length ? this . listTests ( ) : 'No test file available' )
const el = yo ` <div class=" ${ css . testList } py-2 mt-0 border-bottom"> ${ testsMessage } </div> `
if ( ! this . testFilesListElement ) {
this . testFilesListElement = el
} else {
yo . update ( this . testFilesListElement , el )
}
this . updateRunAction ( )
return this . testFilesListElement
}
selectAll ( ) {
return yo `
< div class = "d-flex align-items-center mx-3 pb-2 mt-2 border-bottom" >
< input id = "checkAllTests"
type = "checkbox"
data - id = "testTabCheckAllTests"
onclick = "${(event) => { this.checkAll(event) }}"
checked = "true"
>
< label class = "text-nowrap pl-2 mb-0" for = "checkAllTests" > Select all < / l a b e l >
< / d i v >
`
}
infoButton ( ) {
return yo `
< a class = "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" >
< label class = "btn p-1 ml-2 m-0" > How to use ... < / l a b e l >
< / a >
`
}
createResultLabel ( ) {
if ( ! this . data . selectedTests ) return yo ` <span></span> `
const ready = this . readyTestsNumber ? ` ${ this . readyTestsNumber } ` : '0'
return yo ` <span class='text-info h6'>Progress: ${ ready } finished (of ${ this . runningTestsNumber } )</span> `
}
pathAdded ( text ) {
for ( const option of this . uiPathList . querySelectorAll ( 'option' ) ) {
if ( option . innerHTML === text ) return true
}
return false
}
render ( ) {
this . onActivationInternal ( )
this . renderComponent ( )
@ -657,83 +193,4 @@ module.exports = class TestTab extends ViewPlugin {
< SolidityUnitTesting testTab = { this } helper = { helper } / >
, this . element )
}
render2 ( ) {
this . onActivationInternal ( )
this . testsOutput = yo ` <div class="mx-3 mb-2 pb-4 border-top border-primary" hidden='true' id="solidityUnittestsOutput" data-id="testTabSolidityUnitTestsOutput"></a> `
this . testsExecutionStopped = yo ` <label class="text-warning h6" data-id="testTabTestsExecutionStopped">The test execution has been stopped</label> `
this . testsExecutionStoppedError = yo ` <label class="text-danger h6" data-id="testTabTestsExecutionStoppedError">The test execution has been stopped because of error(s) in your test file</label> `
this . uiPathList = yo ` <datalist id="utPathList"></datalist> `
this . inputPath = yo ` <input
placeholder = $ { this . defaultPath }
list = "utPathList"
class = "${css.inputFolder} custom-select"
id = "utPath"
data - id = "uiPathInput"
name = "utPath"
title = "Press 'Enter' to change the path for test files."
style = "background-image: var(--primary);"
onkeyup = $ { ( e ) => this . handleTestDirInput ( e ) }
onchange = $ { async ( e ) => this . handleEnter ( e ) }
/ > `
this . createTestFolder = yo `
< button
class = "btn border ml-2"
data - id = "testTabGenerateTestFolder"
title = "Create a test folder"
disabled = true
onclick = $ { ( e ) => this . handleCreateFolder ( ) }
>
Create
< / b u t t o n >
`
const availablePaths = yo `
< div >
< div class = "d-flex p-2" >
$ { this . inputPath }
$ { this . createTestFolder }
$ { this . uiPathList }
< / d i v >
< / d i v >
`
this . updateDirList ( '/' )
this . testsExecutionStopped . hidden = true
this . testsExecutionStoppedError . hidden = true
this . resultStatistics = this . createResultLabel ( )
this . resultStatistics . hidden = true
const el = yo `
< div class = "${css.testTabView} px-2" id = "testView" >
< div class = "${css.infoBox}" >
< p class = "text-lg" > Test your smart contract in Solidity . < / p >
< p > Select directory to load and generate test files . < / p >
< label > Test directory : < / l a b e l >
$ { availablePaths }
< / d i v >
< div class = "${css.tests}" >
< div class = "d-flex p-2" >
$ { this . updateGenerateFileAction ( ) }
$ { this . infoButton ( ) }
< / d i v >
< div class = "d-flex p-2" >
$ { this . updateRunAction ( ) }
$ { this . updateStopAction ( ) }
< / d i v >
$ { this . selectAll ( ) }
$ { this . updateTestFileList ( ) }
< div class = "align-items-start flex-column mt-2 mx-3 mb-0" >
$ { this . resultStatistics }
$ { this . testsExecutionStopped }
$ { this . testsExecutionStoppedError }
< / d i v >
$ { this . testsOutput }
< / d i v >
< / d i v >
`
this . _view . el = el
this . testTabLogic . setCurrentPath ( this . defaultPath )
this . updateForNewCurrent ( this . fileManager . currentFile ( ) )
return el
}
}