diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000000..06cc47d9a2 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "root": true, + "ignorePatterns": ["**/*"], + "plugins": ["@nrwl/nx"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": { + "@nrwl/nx/enforce-module-boundaries": [ + "error", + { + "enforceBuildableLibDependency": true, + "allow": [], + "depConstraints": [ + { + "sourceTag": "*", + "onlyDependOnLibsWithTags": ["*"] + } + ] + } + ] + } + }, + { + "files": ["*.ts", "*.tsx"], + "extends": ["plugin:@nrwl/nx/typescript"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "extends": ["plugin:@nrwl/nx/javascript"], + "rules": {} + } + ] +} diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts index f6ccce0509..1ca31687c9 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts @@ -64,9 +64,11 @@ module.exports = { .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"]', 'Passed: 2', 120000) + .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'Failed: 1', 120000) + .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'FAILMyTest (tests/simple_storage_test.sol)', 120000) + // '.failed_tests_simple_storage_test_solMyTest' is the class for 'FAIL' label + .verify.elementPresent('.failed_tests_simple_storage_test_solMyTest') }, 'Should run advance unit test using natspec and experimental ABIEncoderV2 `ks2b_test.sol` #group2': function (browser: NightwatchBrowser) { @@ -94,10 +96,9 @@ module.exports = { .waitForElementPresent('*[data-id="testTabRunTestsTabRunAction"]') .clickElementAtPosition('.singleTestLabel', 0) .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') + .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'tests/4_Ballot_test.sol', 200000) + .notContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'tests/ks2b_test.sol') .notContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'tests/simple_storage_test.sol') .waitForElementContainsText('*[data-id="testTabTestsExecutionStopped"]', 'The test execution has been stopped', 60000) }, @@ -151,6 +152,7 @@ module.exports = { .waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]') .addFile('myTests/simple_storage_test.sol', sources[0]['tests/simple_storage_test.sol']) .clickLaunchIcon('solidityUnitTesting') + .clearValue('*[data-id="uiPathInput"]') .setValue('*[data-id="uiPathInput"]', 'myTests') .click('*[data-id="testTabGenerateTestFolder"]') .clickElementAtPosition('.singleTest', 0, { forceSelectIfUnselected: true }) diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index c82a2bcc1d..6fd97b446a 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -1,18 +1,17 @@ +/* global */ +import React from 'react' // eslint-disable-line +import ReactDOM from 'react-dom' +import { SolidityUnitTesting } from '@remix-ui/solidity-unit-testing' // eslint-disable-line +import { TestTabLogic } from '@remix-ui/solidity-unit-testing' // eslint-disable-line + import { ViewPlugin } from '@remixproject/engine-web' -import { removeMultipleSlashes, removeTrailingSlashes } from '../../lib/helper' +import helper from '../../lib/helper' import { canUseWorker, urlFromVersion } from '@remix-project/remix-solidity' -import { format } from 'util' -var yo = require('yo-yo') -var async = require('async') -var tooltip = require('../ui/tooltip') + +// var tooltip = require('../ui/tooltip') var Renderer = require('../ui/renderer') -var css = require('./styles/test-tab-styles') 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', @@ -29,33 +28,18 @@ 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() - this.hasBeenStopped = false - this.runningTestsNumber = 0 - this.readyTestsNumber = 0 - this.areTestsRunning = false - this.defaultPath = 'tests' + this.testTabLogic = new TestTabLogic(this.fileManager, helper) this.offsetToLineColumnConverter = offsetToLineColumnConverter this.allFilesInvolved = ['.deps/remix-tests/remix_tests.sol', '.deps/remix-tests/remix_accounts.sol'] - this.isDebugging = false - this.currentErrors = [] - - appManager.event.on('activate', (name) => { - if (name === 'solidity') this.updateRunAction() - }) - appManager.event.on('deactivate', (name) => { - if (name === 'solidity') this.updateRunAction() - }) + this.element = document.createElement('div') } onActivationInternal () { - this.testTabLogic = new TestTabLogic(this.fileManager) this.listenToEvents() this.call('filePanel', 'registerContextMenuItem', { id: 'solidityUnitTesting', @@ -70,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]) } } @@ -93,7 +77,6 @@ module.exports = class TestTab extends ViewPlugin { } await this.testRunner.init() await this.createTestLibs() - this.updateRunAction() } onDeactivation () { @@ -104,26 +87,6 @@ module.exports = class TestTab extends ViewPlugin { } listenToEvents () { - this.on('filePanel', 'newTestFileCreated', async 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) - this.data.allTests.push(file) - this.data.selectedTests.push(file) - } - }) - - this.on('filePanel', 'setWorkspace', async () => { - this.setCurrentPath(this.defaultPath) - }) - this.on('filePanel', 'workspaceCreated', async () => { this.createTestLibs() }) @@ -136,361 +99,6 @@ module.exports = class TestTab extends ViewPlugin { this.emit('compilationFinished', source.target, source, 'soljson', data) } }) - - this.fileManager.events.on('noFileSelected', () => { - }) - - 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` -
- this.toggleCheckbox(e.target.checked, testFile)} type="checkbox" checked="true"> - -
- ` - } - - listTests () { - if (!this.data.allTests || !this.data.allTests.length) return [] - return this.data.allTests.map( - testFile => this.createSingleTest(testFile) - ) - } - - toggleCheckbox (eChecked, test) { - if (!this.data.selectedTests) { - this.data.selectedTests = this._view.el.querySelectorAll('.singleTest:checked') - } - let selectedTests = this.data.selectedTests - selectedTests = eChecked ? [...selectedTests, test] : selectedTests.filter(el => el !== test) - this.data.selectedTests = selectedTests - const checkAll = this._view.el.querySelector('[id="checkAllTests"]') - const runBtn = document.getElementById('runTestsTabRunAction') - - if (eChecked) { - checkAll.checked = true - const stopBtnInnerText = document.getElementById('runTestsTabStopAction').innerText - if ((this.readyTestsNumber === this.runningTestsNumber || this.hasBeenStopped) && stopBtnInnerText.trim() === 'Stop') { - runBtn.removeAttribute('disabled') - runBtn.setAttribute('title', 'Run tests') - } - } else if (!selectedTests.length) { - checkAll.checked = false - runBtn.setAttribute('disabled', 'disabled') - runBtn.setAttribute('title', 'No test file selected') - } - } - - checkAll (event) { - const checkBoxes = this._view.el.querySelectorAll('.singleTest') - const checkboxesLabels = this._view.el.querySelectorAll('.singleTestLabel') - // checks/unchecks all - for (let i = 0; i < checkBoxes.length; i++) { - checkBoxes[i].checked = event.target.checked - this.toggleCheckbox(event.target.checked, checkboxesLabels[i].innerText) - } - } - - async discardHighlight () { - await this.call('editor', 'discardHighlight') - } - - async highlightLocation (location, runningTests, fileName) { - if (location) { - var split = location.split(':') - var file = split[2] - location = { - start: parseInt(split[0]), - length: parseInt(split[1]) - } - location = this.offsetToLineColumnConverter.offsetToLineColumnWithContent( - location, - parseInt(file), - runningTests[fileName].content - ) - await this.call('editor', 'discardHighlight') - await this.call('editor', 'highlight', location, fileName, '', { focus: true }) - } - } - - 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 = `${testName}:\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`
this.startDebug(debugTxHash, web3)}> - -
` - 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` -
- ${this.testSuite} (${this.rawFileName}) -
- ` - 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` -
this.discardHighlight()} - > -
- ✓ ${result.value} - ${debugBtn} -
-
- `) - } else if (result.type === 'testFailure') { - if (result.hhLogs && result.hhLogs.length) this.printHHLogs(result.hhLogs, result.value) - if (!result.assertMethod) { - this.testsOutput.appendChild(yo` -
this.highlightLocation(result.location, runningTests, result.filename)} - > -
- ✘ ${result.value} - ${debugBtn} -
- Error Message: - "${result.errMsg}" -
- `) - } 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` -
this.highlightLocation(result.location, runningTests, result.filename)} - > -
- ✘ ${result.value} - ${debugBtn} -
- Error Message: - "${result.errMsg}" - Assertion: -
- Expected value should be -
${method}
-
${preposition} ${expected}
-
- Received value: - ${result.returned} - Skipping the remaining tests of the function. -
- `) - } - } 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` -
- PASS -
- ` - - this.outputHeader && yo.update(this.outputHeader, yo` -
- ${label} ${this.testSuite} (${this.rawFileName}) -
- `) - } else { - const label = yo` -
- FAIL -
- ` - - this.outputHeader && yo.update(this.outputHeader, yo` -
- ${label} ${this.testSuite} (${this.rawFileName}) -
- `) - } - } - - 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` -
- Result for ${filename} - Passing: ${result.totalPassing} - Failing: ${result.totalFailing} - Total time: ${totalTime}s -
- `) - } else if (result.totalPassing > 0 && result.totalFailing <= 0) { - this.testsOutput.appendChild(yo` -
- Result for ${filename} - Passing: ${result.totalPassing} - Total time: ${totalTime}s -
- `) - } else if (result.totalPassing <= 0 && result.totalFailing > 0) { - this.testsOutput.appendChild(yo` -
- Result for ${filename} - Failing: ${result.totalFailing} - Total time: ${totalTime}s -
- `) - } - // 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` -
-

-
- `) - } - 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) { @@ -498,17 +106,6 @@ module.exports = class TestTab extends ViewPlugin { return this.testFromSource(fileContent, path) } - /** - * Changes the current path of Unit Testing Plugin - * @param path - the path from where UT plugin takes _test.sol files to run - */ - async setCurrentPath (path) { - this.testTabLogic.setCurrentPath(path) - this.inputPath.value = path - this.updateDirList(path) - await this.updateForNewCurrent() - } - /* Test is not associated with the UI */ @@ -534,337 +131,15 @@ 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 - }) - } - - handleCreateFolder () { - this.inputPath.value = this.trimTestDirInput(this.inputPath.value) - let path = removeMultipleSlashes(this.inputPath.value) - if (path !== '/') path = removeTrailingSlashes(path) - if (this.inputPath.value === '') this.inputPath.value = this.defaultPath - this.inputPath.value = path - this.testTabLogic.generateTestFolder(this.inputPath.value) - this.createTestFolder.disabled = true - this.updateGenerateFileAction().disabled = false - this.testTabLogic.setCurrentPath(this.inputPath.value) - this.updateRunAction() - this.updateForNewCurrent() - this.uiPathList.appendChild(yo``) - } - - clearResults () { - yo.update(this.resultStatistics, yo``) - 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') - } - - updateGenerateFileAction () { - const el = yo` - - ` - if (!this.generateFileActionElement) { - this.generateFileActionElement = el - } else { - yo.update(this.generateFileActionElement, el) - } - return this.generateFileActionElement - } - - updateRunAction (currentFile) { - const el = yo` - - ` - 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` - - ` - } - - updateTestFileList (tests) { - const testsMessage = (tests && tests.length ? this.listTests() : 'No test file available') - const el = yo`
${testsMessage}
` - if (!this.testFilesListElement) { - this.testFilesListElement = el - } else { - yo.update(this.testFilesListElement, el) - } - this.updateRunAction() - return this.testFilesListElement - } - - selectAll () { - return yo` -
- - -
- ` - } - - infoButton () { - return yo` - - - - ` - } - - createResultLabel () { - if (!this.data.selectedTests) return yo`` - const ready = this.readyTestsNumber ? `${this.readyTestsNumber}` : '0' - return yo`Progress: ${ready} finished (of ${this.runningTestsNumber})` - } - - updateDirList (path) { - for (const o of this.uiPathList.querySelectorAll('option')) o.remove() - this.testTabLogic.dirList(path).then((options) => { - options.forEach((path) => this.uiPathList.appendChild(yo``)) - }) - } - - trimTestDirInput (input) { - if (input.includes('/')) return input.split('/').map(e => e.trim()).join('/') - else return input.trim() - } - - pathAdded (text) { - for (const option of this.uiPathList.querySelectorAll('option')) { - if (option.innerHTML === text) return true - } - return false - } - - async handleTestDirInput (e) { - let testDirInput = this.trimTestDirInput(this.inputPath.value) - testDirInput = removeMultipleSlashes(testDirInput) - if (testDirInput !== '/') testDirInput = removeTrailingSlashes(testDirInput) - if (e.key === 'Enter') { - this.inputPath.value = testDirInput - if (await this.testTabLogic.pathExists(testDirInput)) { - this.testTabLogic.setCurrentPath(testDirInput) - this.updateForNewCurrent() - return - } - } - - if (testDirInput) { - if (testDirInput.endsWith('/') && testDirInput !== '/') { - testDirInput = removeTrailingSlashes(testDirInput) - if (this.testTabLogic.currentPath === testDirInput.substr(0, testDirInput.length - 1)) { - this.createTestFolder.disabled = true - this.updateGenerateFileAction().disabled = true - } - this.updateDirList(testDirInput) - } else { - // If there is no matching folder in the workspace with entered text, enable Create button - if (await this.testTabLogic.pathExists(testDirInput)) { - this.createTestFolder.disabled = true - this.updateGenerateFileAction().disabled = false - } else { - // Enable Create button - this.createTestFolder.disabled = false - // Disable Generate button because dir does not exist - this.updateGenerateFileAction().disabled = true - } - } - } else { - this.updateDirList('/') - } - } - - async handleEnter (e) { - this.inputPath.value = removeMultipleSlashes(this.trimTestDirInput(this.inputPath.value)) - if (this.createTestFolder.disabled) { - if (await this.testTabLogic.pathExists(this.inputPath.value)) { - this.testTabLogic.setCurrentPath(this.inputPath.value) - this.updateForNewCurrent() - } - } - } - render () { this.onActivationInternal() - this.testsOutput = yo`