@salesforce/apex-node
Advanced tools
Comparing version 0.1.21 to 0.1.22
@@ -5,3 +5,3 @@ export { CancellationToken, CancellationTokenSource, Progress } from './common'; | ||
export { JUnitReporter, TapReporter, HumanReporter } from './reporters'; | ||
export { ApexTestProgressValue, ApexTestResultData, ApexTestResultOutcome, AsyncTestArrayConfiguration, AsyncTestConfiguration, CodeCoverageResult, OutputDirConfig, ResultFormat, SyncTestConfiguration, TestItem, TestLevel, TestResult, TestService } from './tests'; | ||
export { ApexTestProgressValue, ApexTestRunResultStatus, ApexTestResultData, ApexTestResultOutcome, AsyncTestArrayConfiguration, AsyncTestConfiguration, CodeCoverageResult, OutputDirConfig, ResultFormat, SyncTestConfiguration, TestItem, TestLevel, TestResult, TestService } from './tests'; | ||
export { Row, Table } from './utils'; |
@@ -20,2 +20,3 @@ "use strict"; | ||
var tests_1 = require("./tests"); | ||
exports.ApexTestRunResultStatus = tests_1.ApexTestRunResultStatus; | ||
exports.ApexTestResultOutcome = tests_1.ApexTestResultOutcome; | ||
@@ -22,0 +23,0 @@ exports.ResultFormat = tests_1.ResultFormat; |
export { TestService } from './testService'; | ||
export { ApexTestProgressValue, AsyncTestConfiguration, AsyncTestArrayConfiguration, SyncTestConfiguration, OutputDirConfig, ApexTestResultData, ApexTestResultOutcome, CodeCoverageResult, ResultFormat, TestItem, TestResult, TestLevel } from './types'; | ||
export { ApexTestProgressValue, ApexTestRunResultStatus, AsyncTestConfiguration, AsyncTestArrayConfiguration, SyncTestConfiguration, OutputDirConfig, ApexTestResultData, ApexTestResultOutcome, CodeCoverageResult, ResultFormat, TestItem, TestResult, TestLevel } from './types'; |
@@ -12,2 +12,3 @@ "use strict"; | ||
var types_1 = require("./types"); | ||
exports.ApexTestRunResultStatus = types_1.ApexTestRunResultStatus; | ||
exports.ApexTestResultOutcome = types_1.ApexTestResultOutcome; | ||
@@ -14,0 +15,0 @@ exports.ResultFormat = types_1.ResultFormat; |
import { Connection } from '@salesforce/core'; | ||
import { SyncTestConfiguration, SyncTestResult, AsyncTestConfiguration, AsyncTestArrayConfiguration, ApexTestProgressValue, ApexTestResult, ApexTestQueueItem, TestResult, OutputDirConfig, TestLevel } from './types'; | ||
import { SyncTestConfiguration, AsyncTestConfiguration, AsyncTestArrayConfiguration, ApexTestProgressValue, TestResult, OutputDirConfig, TestLevel } from './types'; | ||
import { CancellationToken, Progress } from '../common'; | ||
export declare class TestService { | ||
readonly connection: Connection; | ||
private readonly codecoverage; | ||
private readonly connection; | ||
private readonly asyncService; | ||
private readonly syncService; | ||
constructor(connection: Connection); | ||
buildSyncPayload(testLevel: TestLevel, tests?: string, classnames?: string): Promise<SyncTestConfiguration>; | ||
buildAsyncPayload(testLevel: TestLevel, tests?: string, classNames?: string, suiteNames?: string): Promise<AsyncTestConfiguration | AsyncTestArrayConfiguration>; | ||
private buildTestPayload; | ||
private buildAsyncClassPayload; | ||
/** | ||
@@ -19,4 +16,2 @@ * Synchronous Test Runs | ||
runTestSynchronous(options: SyncTestConfiguration, codeCoverage?: boolean, token?: CancellationToken): Promise<TestResult>; | ||
formatSyncResults(apiTestResult: SyncTestResult, startTime: number, codeCoverage?: boolean): Promise<TestResult>; | ||
private buildSyncTestResults; | ||
/** | ||
@@ -37,12 +32,14 @@ * Asynchronous Test Runs | ||
reportAsyncResults(testRunId: string, codeCoverage?: boolean, token?: CancellationToken): Promise<TestResult>; | ||
formatAsyncResults(testQueueResult: ApexTestQueueItem, testRunId: string, commandStartTime: number, codeCoverage?: boolean, progress?: Progress<ApexTestProgressValue>): Promise<TestResult>; | ||
getAsyncTestResults(testQueueResult: ApexTestQueueItem): Promise<ApexTestResult[]>; | ||
private buildAsyncTestResults; | ||
writeResultFiles(result: TestResult, outputDirConfig: OutputDirConfig, codeCoverage?: boolean): Promise<string[]>; | ||
/** | ||
* Abort test run with test run id | ||
* @param testRunId | ||
* | ||
* @param result test result | ||
* @param outputDirConfig config for result files | ||
* @param codeCoverage should report code coverage | ||
* @returns list of result files created | ||
*/ | ||
abortTestRun(testRunId: string, progress?: Progress<ApexTestProgressValue>): Promise<void>; | ||
private getTestRunRequestAction; | ||
writeResultFiles(result: TestResult, outputDirConfig: OutputDirConfig, codeCoverage?: boolean): Promise<string[]>; | ||
buildSyncPayload(testLevel: TestLevel, tests?: string, classnames?: string): Promise<SyncTestConfiguration>; | ||
buildAsyncPayload(testLevel: TestLevel, tests?: string, classNames?: string, suiteNames?: string): Promise<AsyncTestConfiguration | AsyncTestArrayConfiguration>; | ||
private buildAsyncClassPayload; | ||
private buildTestPayload; | ||
} |
@@ -13,18 +13,122 @@ "use strict"; | ||
const types_1 = require("./types"); | ||
const util = require("util"); | ||
const path_1 = require("path"); | ||
const i18n_1 = require("../i18n"); | ||
const streaming_1 = require("../streaming"); | ||
const reporters_1 = require("../reporters"); | ||
const diagnosticUtil_1 = require("./diagnosticUtil"); | ||
const utils_1 = require("./utils"); | ||
const utils_2 = require("../utils"); | ||
const fileSystemHandler_1 = require("../utils/fileSystemHandler"); | ||
const codeCoverage_1 = require("./codeCoverage"); | ||
const constants_1 = require("./constants"); | ||
const asyncTests_1 = require("./asyncTests"); | ||
const syncTests_1 = require("./syncTests"); | ||
const diagnosticUtil_1 = require("./diagnosticUtil"); | ||
class TestService { | ||
constructor(connection) { | ||
this.connection = connection; | ||
this.codecoverage = new codeCoverage_1.CodeCoverage(this.connection); | ||
this.syncService = new syncTests_1.SyncTests(connection); | ||
this.asyncService = new asyncTests_1.AsyncTests(connection); | ||
} | ||
/** | ||
* Synchronous Test Runs | ||
* @param options Synchronous Test Runs configuration | ||
* @param codeCoverage should report code coverage | ||
* @param token cancellation token | ||
*/ | ||
runTestSynchronous(options, codeCoverage = false, token) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return yield this.syncService.runTests(options, codeCoverage, token); | ||
}); | ||
} | ||
/** | ||
* Asynchronous Test Runs | ||
* @param options test options | ||
* @param codeCoverage should report code coverage | ||
* @param progress progress reporter | ||
* @param token cancellation token | ||
*/ | ||
runTestAsynchronous(options, codeCoverage = false, progress, token) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return yield this.asyncService.runTests(options, codeCoverage, progress, token); | ||
}); | ||
} | ||
/** | ||
* Report Asynchronous Test Run Results | ||
* @param testRunId test run id | ||
* @param codeCoverage should report code coverages | ||
* @param token cancellation token | ||
*/ | ||
reportAsyncResults(testRunId, codeCoverage = false, token) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return yield this.asyncService.reportAsyncResults(testRunId, codeCoverage, token); | ||
}); | ||
} | ||
/** | ||
* | ||
* @param result test result | ||
* @param outputDirConfig config for result files | ||
* @param codeCoverage should report code coverage | ||
* @returns list of result files created | ||
*/ | ||
writeResultFiles(result, outputDirConfig, codeCoverage = false) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { dirPath, resultFormats, fileInfos } = outputDirConfig; | ||
const fileMap = []; | ||
fileMap.push({ | ||
path: path_1.join(dirPath, 'test-run-id.txt'), | ||
content: result.summary.testRunId | ||
}); | ||
if (resultFormats) { | ||
for (const format of resultFormats) { | ||
if (!(format in types_1.ResultFormat)) { | ||
throw new Error(i18n_1.nls.localize('resultFormatErr')); | ||
} | ||
switch (format) { | ||
case types_1.ResultFormat.json: | ||
fileMap.push({ | ||
path: path_1.join(dirPath, result.summary.testRunId | ||
? `test-result-${result.summary.testRunId}.json` | ||
: `test-result.json`), | ||
content: utils_1.stringify(result) | ||
}); | ||
break; | ||
case types_1.ResultFormat.tap: | ||
const tapResult = new reporters_1.TapReporter().format(result); | ||
fileMap.push({ | ||
path: path_1.join(dirPath, `test-result-${result.summary.testRunId}-tap.txt`), | ||
content: tapResult | ||
}); | ||
break; | ||
case types_1.ResultFormat.junit: | ||
const junitResult = new reporters_1.JUnitReporter().format(result); | ||
fileMap.push({ | ||
path: path_1.join(dirPath, result.summary.testRunId | ||
? `test-result-${result.summary.testRunId}-junit.xml` | ||
: `test-result-junit.xml`), | ||
content: junitResult | ||
}); | ||
break; | ||
} | ||
} | ||
} | ||
if (codeCoverage) { | ||
const coverageRecords = result.tests.map(record => { | ||
return record.perClassCoverage; | ||
}); | ||
fileMap.push({ | ||
path: path_1.join(dirPath, `test-result-${result.summary.testRunId}-codecoverage.json`), | ||
content: utils_1.stringify(coverageRecords) | ||
}); | ||
} | ||
(_a = fileInfos) === null || _a === void 0 ? void 0 : _a.forEach(fileInfo => { | ||
fileMap.push({ | ||
path: path_1.join(dirPath, fileInfo.filename), | ||
content: typeof fileInfo.content !== 'string' | ||
? utils_1.stringify(fileInfo.content) | ||
: fileInfo.content | ||
}); | ||
}); | ||
fileSystemHandler_1.createFiles(fileMap); | ||
return fileMap.map(file => { | ||
return file.path; | ||
}); | ||
}); | ||
} | ||
// utils to build test run payloads that may contain namespaces | ||
@@ -82,2 +186,18 @@ buildSyncPayload(testLevel, tests, classnames) { | ||
} | ||
buildAsyncClassPayload(classNames) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const classNameArray = classNames.split(','); | ||
const classItems = classNameArray.map(item => { | ||
const classParts = item.split('.'); | ||
if (classParts.length > 1) { | ||
return { | ||
className: `${classParts[0]}.${classParts[1]}` | ||
}; | ||
} | ||
const prop = utils_1.isValidApexClassID(item) ? 'classId' : 'className'; | ||
return { [prop]: item }; | ||
}); | ||
return { tests: classItems, testLevel: "RunSpecifiedTests" /* RunSpecifiedTests */ }; | ||
}); | ||
} | ||
buildTestPayload(testNames) { | ||
@@ -137,454 +257,4 @@ return __awaiter(this, void 0, void 0, function* () { | ||
} | ||
buildAsyncClassPayload(classNames) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const classNameArray = classNames.split(','); | ||
const classItems = classNameArray.map(item => { | ||
const classParts = item.split('.'); | ||
if (classParts.length > 1) { | ||
return { | ||
className: `${classParts[0]}.${classParts[1]}` | ||
}; | ||
} | ||
const prop = utils_1.isValidApexClassID(item) ? 'classId' : 'className'; | ||
return { [prop]: item }; | ||
}); | ||
return { tests: classItems, testLevel: "RunSpecifiedTests" /* RunSpecifiedTests */ }; | ||
}); | ||
} | ||
/** | ||
* Synchronous Test Runs | ||
* @param options Synchronous Test Runs configuration | ||
* @param codeCoverage should report code coverage | ||
* @param token cancellation token | ||
*/ | ||
runTestSynchronous(options, codeCoverage = false, token) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
const url = `${this.connection.tooling._baseUrl()}/runTestsSynchronous`; | ||
const request = { | ||
method: 'POST', | ||
url, | ||
body: JSON.stringify(options), | ||
headers: { 'content-type': 'application/json' } | ||
}; | ||
const testRun = (yield this.connection.tooling.request(request)); | ||
if (token && token.isCancellationRequested) { | ||
return null; | ||
} | ||
return yield this.formatSyncResults(testRun, utils_2.getCurrentTime(), codeCoverage); | ||
} | ||
catch (e) { | ||
throw diagnosticUtil_1.formatTestErrors(e); | ||
} | ||
}); | ||
} | ||
formatSyncResults(apiTestResult, startTime, codeCoverage = false) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const coveredApexClassIdSet = new Set(); | ||
const { apexTestClassIdSet, testResults } = this.buildSyncTestResults(apiTestResult); | ||
const globalTestFailed = apiTestResult.failures.length; | ||
const globalTestPassed = apiTestResult.successes.length; | ||
const result = { | ||
summary: { | ||
outcome: globalTestFailed === 0 | ||
? "Passed" /* Passed */ | ||
: "Failed" /* Failed */, | ||
testsRan: apiTestResult.numTestsRun, | ||
passing: globalTestPassed, | ||
failing: globalTestFailed, | ||
skipped: 0, | ||
passRate: utils_1.calculatePercentage(globalTestPassed, apiTestResult.numTestsRun), | ||
failRate: utils_1.calculatePercentage(globalTestFailed, apiTestResult.numTestsRun), | ||
skipRate: utils_1.calculatePercentage(0, apiTestResult.numTestsRun), | ||
testStartTime: utils_2.formatStartTime(startTime), | ||
testExecutionTimeInMs: (_a = apiTestResult.totalTime, (_a !== null && _a !== void 0 ? _a : 0)), | ||
testTotalTimeInMs: (_b = apiTestResult.totalTime, (_b !== null && _b !== void 0 ? _b : 0)), | ||
commandTimeInMs: utils_2.getCurrentTime() - startTime, | ||
hostname: this.connection.instanceUrl, | ||
orgId: this.connection.getAuthInfoFields().orgId, | ||
username: this.connection.getUsername(), | ||
testRunId: '', | ||
userId: this.connection.getConnectionOptions().userId | ||
}, | ||
tests: testResults | ||
}; | ||
if (codeCoverage) { | ||
const perClassCovMap = yield this.codecoverage.getPerClassCodeCoverage(apexTestClassIdSet); | ||
result.tests.forEach(item => { | ||
const keyCodeCov = `${item.apexClass.id}-${item.methodName}`; | ||
const perClassCov = perClassCovMap.get(keyCodeCov); | ||
perClassCov.forEach(classCov => coveredApexClassIdSet.add(classCov.apexClassOrTriggerId)); | ||
item.perClassCoverage = perClassCov; | ||
}); | ||
const { codeCoverageResults, totalLines, coveredLines } = yield this.codecoverage.getAggregateCodeCoverage(coveredApexClassIdSet); | ||
result.codecoverage = codeCoverageResults; | ||
result.summary.totalLines = totalLines; | ||
result.summary.coveredLines = coveredLines; | ||
result.summary.testRunCoverage = utils_1.calculatePercentage(coveredLines, totalLines); | ||
result.summary.orgWideCoverage = yield this.codecoverage.getOrgWideCoverage(); | ||
} | ||
return result; | ||
}); | ||
} | ||
buildSyncTestResults(apiTestResult) { | ||
const testResults = []; | ||
const apexTestClassIdSet = new Set(); | ||
apiTestResult.successes.forEach(item => { | ||
var _a; | ||
const nms = item.namespace ? `${item.namespace}__` : ''; | ||
apexTestClassIdSet.add(item.id); | ||
testResults.push({ | ||
id: '', | ||
queueItemId: '', | ||
stackTrace: '', | ||
message: '', | ||
asyncApexJobId: '', | ||
methodName: item.methodName, | ||
outcome: "Pass" /* Pass */, | ||
apexLogId: apiTestResult.apexLogId, | ||
apexClass: { | ||
id: item.id, | ||
name: item.name, | ||
namespacePrefix: item.namespace, | ||
fullName: `${nms}${item.name}` | ||
}, | ||
runTime: (_a = item.time, (_a !== null && _a !== void 0 ? _a : 0)), | ||
testTimestamp: '', | ||
fullName: `${nms}${item.name}.${item.methodName}` | ||
}); | ||
}); | ||
apiTestResult.failures.forEach(item => { | ||
var _a; | ||
const nms = item.namespace ? `${item.namespace}__` : ''; | ||
apexTestClassIdSet.add(item.id); | ||
const diagnostic = item.message || item.stackTrace ? diagnosticUtil_1.getSyncDiagnostic(item) : null; | ||
testResults.push(Object.assign({ id: '', queueItemId: '', stackTrace: item.stackTrace, message: item.message, asyncApexJobId: '', methodName: item.methodName, outcome: "Fail" /* Fail */, apexLogId: apiTestResult.apexLogId, apexClass: { | ||
id: item.id, | ||
name: item.name, | ||
namespacePrefix: item.namespace, | ||
fullName: `${nms}${item.name}` | ||
}, runTime: (_a = item.time, (_a !== null && _a !== void 0 ? _a : 0)), testTimestamp: '', fullName: `${nms}${item.name}.${item.methodName}` }, (diagnostic ? { diagnostic } : {}))); | ||
}); | ||
return { apexTestClassIdSet, testResults }; | ||
} | ||
/** | ||
* Asynchronous Test Runs | ||
* @param options test options | ||
* @param codeCoverage should report code coverage | ||
* @param progress progress reporter | ||
* @param token cancellation token | ||
*/ | ||
runTestAsynchronous(options, codeCoverage = false, progress, token) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
const sClient = new streaming_1.StreamingClient(this.connection, progress); | ||
yield sClient.init(); | ||
yield sClient.handshake(); | ||
token && | ||
token.onCancellationRequested(() => __awaiter(this, void 0, void 0, function* () { | ||
const testRunId = yield sClient.subscribedTestRunIdPromise; | ||
yield this.abortTestRun(testRunId, progress); | ||
sClient.disconnect(); | ||
})); | ||
const asyncRunResult = yield sClient.subscribe(this.getTestRunRequestAction(options)); | ||
if (token && token.isCancellationRequested) { | ||
return null; | ||
} | ||
return yield this.formatAsyncResults(asyncRunResult.queueItem, asyncRunResult.runId, utils_2.getCurrentTime(), codeCoverage, progress); | ||
} | ||
catch (e) { | ||
throw diagnosticUtil_1.formatTestErrors(e); | ||
} | ||
}); | ||
} | ||
/** | ||
* Report Asynchronous Test Run Results | ||
* @param testRunId test run id | ||
* @param codeCoverage should report code coverages | ||
* @param token cancellation token | ||
*/ | ||
reportAsyncResults(testRunId, codeCoverage = false, token) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const sClient = new streaming_1.StreamingClient(this.connection); | ||
const queueResult = yield sClient.handler(undefined, testRunId); | ||
token && | ||
token.onCancellationRequested(() => __awaiter(this, void 0, void 0, function* () { | ||
sClient.disconnect(); | ||
})); | ||
if (token && token.isCancellationRequested) { | ||
return null; | ||
} | ||
return yield this.formatAsyncResults(queueResult, testRunId, utils_2.getCurrentTime(), codeCoverage); | ||
}); | ||
} | ||
formatAsyncResults(testQueueResult, testRunId, commandStartTime, codeCoverage = false, progress) { | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!utils_1.isValidTestRunID(testRunId)) { | ||
throw new Error(i18n_1.nls.localize('invalidTestRunIdErr', testRunId)); | ||
} | ||
let testRunSummaryQuery = 'SELECT AsyncApexJobId, Status, ClassesCompleted, ClassesEnqueued, '; | ||
testRunSummaryQuery += | ||
'MethodsEnqueued, StartTime, EndTime, TestTime, UserId '; | ||
testRunSummaryQuery += `FROM ApexTestRunResult WHERE AsyncApexJobId = '${testRunId}'`; | ||
(_a = progress) === null || _a === void 0 ? void 0 : _a.report({ | ||
type: 'FormatTestResultProgress', | ||
value: 'retrievingTestRunSummary', | ||
message: i18n_1.nls.localize('retrievingTestRunSummary') | ||
}); | ||
const testRunSummaryResults = (yield this.connection.tooling.query(testRunSummaryQuery)); | ||
if (testRunSummaryResults.records.length === 0) { | ||
throw new Error(i18n_1.nls.localize('noTestResultSummary', testRunId)); | ||
} | ||
const summaryRecord = testRunSummaryResults.records[0]; | ||
const coveredApexClassIdSet = new Set(); | ||
const apexTestResults = yield this.getAsyncTestResults(testQueueResult); | ||
const { apexTestClassIdSet, testResults, globalTests } = yield this.buildAsyncTestResults(apexTestResults); | ||
let outcome = summaryRecord.Status; | ||
if (globalTests.failed > 0) { | ||
outcome = "Failed" /* Failed */; | ||
} | ||
else if (globalTests.passed === 0) { | ||
outcome = "Skipped" /* Skipped */; | ||
} | ||
else if (summaryRecord.Status === "Completed" /* Completed */) { | ||
outcome = "Passed" /* Passed */; | ||
} | ||
// TODO: deprecate testTotalTime | ||
const result = { | ||
summary: { | ||
outcome, | ||
testsRan: testResults.length, | ||
passing: globalTests.passed, | ||
failing: globalTests.failed, | ||
skipped: globalTests.skipped, | ||
passRate: utils_1.calculatePercentage(globalTests.passed, testResults.length), | ||
failRate: utils_1.calculatePercentage(globalTests.failed, testResults.length), | ||
skipRate: utils_1.calculatePercentage(globalTests.skipped, testResults.length), | ||
testStartTime: utils_2.formatStartTime(summaryRecord.StartTime), | ||
testExecutionTimeInMs: (_b = summaryRecord.TestTime, (_b !== null && _b !== void 0 ? _b : 0)), | ||
testTotalTimeInMs: (_c = summaryRecord.TestTime, (_c !== null && _c !== void 0 ? _c : 0)), | ||
commandTimeInMs: utils_2.getCurrentTime() - commandStartTime, | ||
hostname: this.connection.instanceUrl, | ||
orgId: this.connection.getAuthInfoFields().orgId, | ||
username: this.connection.getUsername(), | ||
testRunId, | ||
userId: summaryRecord.UserId | ||
}, | ||
tests: testResults | ||
}; | ||
if (codeCoverage) { | ||
const perClassCovMap = yield this.codecoverage.getPerClassCodeCoverage(apexTestClassIdSet); | ||
result.tests.forEach(item => { | ||
const keyCodeCov = `${item.apexClass.id}-${item.methodName}`; | ||
const perClassCov = perClassCovMap.get(keyCodeCov); | ||
// Skipped test is not in coverage map, check to see if perClassCov exists first | ||
if (perClassCov) { | ||
perClassCov.forEach(classCov => coveredApexClassIdSet.add(classCov.apexClassOrTriggerId)); | ||
item.perClassCoverage = perClassCov; | ||
} | ||
}); | ||
(_d = progress) === null || _d === void 0 ? void 0 : _d.report({ | ||
type: 'FormatTestResultProgress', | ||
value: 'queryingForAggregateCodeCoverage', | ||
message: i18n_1.nls.localize('queryingForAggregateCodeCoverage') | ||
}); | ||
const { codeCoverageResults, totalLines, coveredLines } = yield this.codecoverage.getAggregateCodeCoverage(coveredApexClassIdSet); | ||
result.codecoverage = codeCoverageResults; | ||
result.summary.totalLines = totalLines; | ||
result.summary.coveredLines = coveredLines; | ||
result.summary.testRunCoverage = utils_1.calculatePercentage(coveredLines, totalLines); | ||
result.summary.orgWideCoverage = yield this.codecoverage.getOrgWideCoverage(); | ||
} | ||
return result; | ||
}); | ||
} | ||
getAsyncTestResults(testQueueResult) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let apexTestResultQuery = 'SELECT Id, QueueItemId, StackTrace, Message, '; | ||
apexTestResultQuery += | ||
'RunTime, TestTimestamp, AsyncApexJobId, MethodName, Outcome, ApexLogId, '; | ||
apexTestResultQuery += | ||
'ApexClass.Id, ApexClass.Name, ApexClass.NamespacePrefix '; | ||
apexTestResultQuery += 'FROM ApexTestResult WHERE QueueItemId IN (%s)'; | ||
const apexResultIds = testQueueResult.records.map(record => record.Id); | ||
let formattedIds = ''; | ||
const queries = []; | ||
// iterate thru ids, create query with id, & compare query length to char limit | ||
for (const id of apexResultIds) { | ||
const newIds = utils_1.addIdToQuery(formattedIds, id); | ||
const query = util.format(apexTestResultQuery, `'${newIds}'`); | ||
if (query.length > constants_1.QUERY_CHAR_LIMIT) { | ||
queries.push(util.format(apexTestResultQuery, `'${formattedIds}'`)); | ||
formattedIds = ''; | ||
} | ||
formattedIds = utils_1.addIdToQuery(formattedIds, id); | ||
} | ||
if (formattedIds.length > 0) { | ||
queries.push(util.format(apexTestResultQuery, `'${formattedIds}'`)); | ||
} | ||
const queryPromises = queries.map(query => { | ||
return this.connection.tooling.query(query); | ||
}); | ||
const apexTestResults = yield Promise.all(queryPromises); | ||
return apexTestResults; | ||
}); | ||
} | ||
buildAsyncTestResults(apexTestResults) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const apexTestClassIdSet = new Set(); | ||
let passed = 0; | ||
let failed = 0; | ||
let skipped = 0; | ||
// Iterate over test results, format and add them as results.tests | ||
const testResults = []; | ||
for (const result of apexTestResults) { | ||
result.records.forEach(item => { | ||
var _a; | ||
switch (item.Outcome) { | ||
case "Pass" /* Pass */: | ||
passed++; | ||
break; | ||
case "Fail" /* Fail */: | ||
case "CompileFail" /* CompileFail */: | ||
failed++; | ||
break; | ||
case "Skip" /* Skip */: | ||
skipped++; | ||
break; | ||
} | ||
apexTestClassIdSet.add(item.ApexClass.Id); | ||
// Can only query the FullName field if a single record is returned, so manually build the field | ||
item.ApexClass.FullName = item.ApexClass.NamespacePrefix | ||
? `${item.ApexClass.NamespacePrefix}__${item.ApexClass.Name}` | ||
: item.ApexClass.Name; | ||
const diagnostic = item.Message || item.StackTrace ? diagnosticUtil_1.getAsyncDiagnostic(item) : null; | ||
testResults.push(Object.assign({ id: item.Id, queueItemId: item.QueueItemId, stackTrace: item.StackTrace, message: item.Message, asyncApexJobId: item.AsyncApexJobId, methodName: item.MethodName, outcome: item.Outcome, apexLogId: item.ApexLogId, apexClass: { | ||
id: item.ApexClass.Id, | ||
name: item.ApexClass.Name, | ||
namespacePrefix: item.ApexClass.NamespacePrefix, | ||
fullName: item.ApexClass.FullName | ||
}, runTime: (_a = item.RunTime, (_a !== null && _a !== void 0 ? _a : 0)), testTimestamp: item.TestTimestamp, fullName: `${item.ApexClass.FullName}.${item.MethodName}` }, (diagnostic ? { diagnostic } : {}))); | ||
}); | ||
} | ||
return { | ||
apexTestClassIdSet, | ||
testResults, | ||
globalTests: { passed, failed, skipped } | ||
}; | ||
}); | ||
} | ||
writeResultFiles(result, outputDirConfig, codeCoverage = false) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { dirPath, resultFormats, fileInfos } = outputDirConfig; | ||
const fileMap = []; | ||
fileMap.push({ | ||
path: path_1.join(dirPath, 'test-run-id.txt'), | ||
content: result.summary.testRunId | ||
}); | ||
if (resultFormats) { | ||
for (const format of resultFormats) { | ||
if (!(format in types_1.ResultFormat)) { | ||
throw new Error(i18n_1.nls.localize('resultFormatErr')); | ||
} | ||
switch (format) { | ||
case types_1.ResultFormat.json: | ||
fileMap.push({ | ||
path: path_1.join(dirPath, result.summary.testRunId | ||
? `test-result-${result.summary.testRunId}.json` | ||
: `test-result.json`), | ||
content: utils_1.stringify(result) | ||
}); | ||
break; | ||
case types_1.ResultFormat.tap: | ||
const tapResult = new reporters_1.TapReporter().format(result); | ||
fileMap.push({ | ||
path: path_1.join(dirPath, `test-result-${result.summary.testRunId}-tap.txt`), | ||
content: tapResult | ||
}); | ||
break; | ||
case types_1.ResultFormat.junit: | ||
const junitResult = new reporters_1.JUnitReporter().format(result); | ||
fileMap.push({ | ||
path: path_1.join(dirPath, result.summary.testRunId | ||
? `test-result-${result.summary.testRunId}-junit.xml` | ||
: `test-result-junit.xml`), | ||
content: junitResult | ||
}); | ||
break; | ||
} | ||
} | ||
} | ||
if (codeCoverage) { | ||
const coverageRecords = result.tests.map(record => { | ||
return record.perClassCoverage; | ||
}); | ||
fileMap.push({ | ||
path: path_1.join(dirPath, `test-result-${result.summary.testRunId}-codecoverage.json`), | ||
content: utils_1.stringify(coverageRecords) | ||
}); | ||
} | ||
(_a = fileInfos) === null || _a === void 0 ? void 0 : _a.forEach(fileInfo => { | ||
fileMap.push({ | ||
path: path_1.join(dirPath, fileInfo.filename), | ||
content: typeof fileInfo.content !== 'string' | ||
? utils_1.stringify(fileInfo.content) | ||
: fileInfo.content | ||
}); | ||
}); | ||
fileSystemHandler_1.createFiles(fileMap); | ||
return fileMap.map(file => { | ||
return file.path; | ||
}); | ||
}); | ||
} | ||
/** | ||
* Abort test run with test run id | ||
* @param testRunId | ||
*/ | ||
abortTestRun(testRunId, progress) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
(_a = progress) === null || _a === void 0 ? void 0 : _a.report({ | ||
type: 'AbortTestRunProgress', | ||
value: 'abortingTestRun', | ||
message: i18n_1.nls.localize('abortingTestRun', testRunId), | ||
testRunId | ||
}); | ||
const testQueueItems = yield this.connection.tooling.query(`SELECT Id, Status FROM ApexTestQueueItem WHERE ParentJobId = '${testRunId}'`); | ||
for (const record of testQueueItems.records) { | ||
record.Status = "Aborted" /* Aborted */; | ||
} | ||
yield this.connection.tooling.update(testQueueItems.records); | ||
(_b = progress) === null || _b === void 0 ? void 0 : _b.report({ | ||
type: 'AbortTestRunProgress', | ||
value: 'abortingTestRunRequested', | ||
message: i18n_1.nls.localize('abortingTestRunRequested', testRunId), | ||
testRunId | ||
}); | ||
}); | ||
} | ||
getTestRunRequestAction(options) { | ||
const requestTestRun = () => __awaiter(this, void 0, void 0, function* () { | ||
const url = `${this.connection.tooling._baseUrl()}/runTestsAsynchronous`; | ||
const request = { | ||
method: 'POST', | ||
url, | ||
body: JSON.stringify(options), | ||
headers: { 'content-type': 'application/json' } | ||
}; | ||
try { | ||
const testRunId = (yield this.connection.tooling.request(request)); | ||
return Promise.resolve(testRunId); | ||
} | ||
catch (e) { | ||
return Promise.reject(e); | ||
} | ||
}); | ||
return requestTestRun; | ||
} | ||
} | ||
exports.TestService = TestService; | ||
//# sourceMappingURL=testService.js.map |
{ | ||
"name": "@salesforce/apex-node", | ||
"description": "Salesforce js library for Apex", | ||
"version": "0.1.21", | ||
"version": "0.1.22", | ||
"author": "Salesforce", | ||
@@ -6,0 +6,0 @@ "bugs": "https://github.com/forcedotcom/salesforcedx-apex/issues", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
207005
110
3397
1