import { escapeStrForRegex } from 'jest-regex-util' ; import * as path from 'path' ; import * as uuid from 'uuid' ; import * as vscode from 'vscode' ; import { nls } from '../../messages' ; import { telemetryService } from '../../telemetry' ; import { TestExecutionInfo , TestInfoKind } from '../types' ; import { getCliArgsFromJestArgs , getLwcTestRunnerExecutable , getTestWorkspaceFolder , workspaceService } from '../workspace' ; import { SfdxTask , taskService } from './taskService' ; import { testResultsWatcher } from './testResultsWatcher' ; export const enum TestRunType { RUN = 'run' , DEBUG = 'debug' , WATCH = 'watch' } param cwd param testFsPath export function normalizeRunTestsByPath ( cwd , testFsPath ) { if ( /^win32/ . test ( process . platform ) ) { return path . relative ( cwd , testFsPath ) ; } return testFsPath ; } type JestExecutionInfo = { jestArgs : string [ ] ; jestOutputFilePath : string ; } ; /**
 * Test Runner class for running/debugging/watching Jest tests.
 */ export class TestRunner { private testExecutionInfo : TestExecutionInfo ; private testRunType : TestRunType ; private testRunId : string ; private logName ? : string ; param testExecutionInfo param testRunType param logName constructor ( testExecutionInfo , testRunType , logName ? ) { this . testRunId = uuid . v4 ( ) ; this . testExecutionInfo = testExecutionInfo ; this . testRunType = testRunType ; this . logName = logName ; } param workspaceFolder public getJestExecutionInfo ( workspaceFolder ) { const { testRunId , testRunType , testExecutionInfo } = this ; const testName = 'testName' in testExecutionInfo ? testExecutionInfo . testName : undefined ; const { kind , testUri } = testExecutionInfo ; const { fsPath : testFsPath } = testUri ; const tempFolder = testResultsWatcher . getTempFolder ( workspaceFolder , testExecutionInfo ) ; const testResultFileName = `test-result-${ testRunId }.json` ; const outputFilePath = path . join ( tempFolder , testResultFileName ) ; let runTestsByPathArgs ; if ( kind === TestInfoKind . TEST_FILE || kind === TestInfoKind . TEST_CASE ) { const workspaceFolderFsPath = workspaceFolder . uri . fsPath ; runTestsByPathArgs = [ '--runTestsByPath' , normalizeRunTestsByPath ( workspaceFolderFsPath , testFsPath ) ] ; } else { runTestsByPathArgs = [ ] ; } const testNamePatternArgs = testName ? [ '--testNamePattern' , `"${ escapeStrForRegex ( testName ) }"` ] : [ ] ; let runModeArgs ; if ( testRunType === TestRunType . WATCH ) { runModeArgs = [ '--watch' ] ; } else { runModeArgs = [ ] ; } const args = [ ... runModeArgs , '--json' , '--outputFile' , outputFilePath , '--testLocationInResults' , ... runTestsByPathArgs , ... testNamePatternArgs ] ; return { jestArgs : args , jestOutputFilePath : outputFilePath } ; } /**
     * Generate shell execution info necessary for task execution
     */ public getShellExecutionInfo ( ) { const workspaceFolder = getTestWorkspaceFolder ( this . testExecutionInfo . testUri ) ; if ( workspaceFolder ) { const jestExecutionInfo = this . getJestExecutionInfo ( workspaceFolder ) ; if ( jestExecutionInfo ) { const { jestArgs , jestOutputFilePath } = jestExecutionInfo ; const cwd = workspaceFolder . uri . fsPath ; const lwcTestRunnerExecutable = getLwcTestRunnerExecutable ( cwd ) ; const cliArgs = getCliArgsFromJestArgs ( jestArgs , this . testRunType ) ; if ( lwcTestRunnerExecutable ) { return { workspaceFolder , command : lwcTestRunnerExecutable , args : cliArgs , testResultFsPath : jestOutputFilePath } ; } } } } param testResultFsPath public startWatchingTestResults ( testResultFsPath ) { testResultsWatcher . watchTestResults ( testResultFsPath ) ; } private getTaskName ( ) { switch ( this . testRunType ) { case TestRunType . RUN : return nls . localize ( 'run_test_task_name' ) ; case TestRunType . WATCH : return nls . localize ( 'watch_test_task_name' ) ; default : return nls . localize ( 'default_task_name' ) ; } } /**
     * Create and start a task for test execution.
     * Returns the task wrapper on task creation if successful.
     */ public async executeAsSfdxTask ( ) { const shellExecutionInfo = this . getShellExecutionInfo ( ) ; if ( shellExecutionInfo ) { const { command , args , workspaceFolder , testResultFsPath } = shellExecutionInfo ; this . startWatchingTestResults ( testResultFsPath ) ; const taskName = this . getTaskName ( ) ; const sfdxTask = taskService . createTask ( this . testRunId , taskName , workspaceFolder , command , args ) ; if ( this . logName ) { const startTime = process . hrtime ( ) ; sfdxTask . onDidEnd ( ( ) => { telemetryService . sendCommandEvent ( this . logName , startTime , { workspaceType : workspaceService . getCurrentWorkspaceTypeForTelemetry ( ) } ) ; } ) ; } return sfdxTask . execute ( ) ; } } }