Skip to content

Commit

Permalink
test: ut for coverage output functions
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed Sep 17, 2023
1 parent 0199d3b commit d0a3bef
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 48 deletions.
29 changes: 13 additions & 16 deletions src/formatters/deployResultFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { DeployResultJson, isSdrFailure, isSdrSuccess, TestLevel, Verbosity, For
import {
generateCoveredLines,
getCoverageFormattersOptions,
getCoverageNumbers,
mapTestResults,
transformCoverageToApexCoverage,
} from '../utils/coverage';
Expand Down Expand Up @@ -63,20 +64,17 @@ export class DeployResultFormatter extends TestResultsFormatter implements Forma
(!this.result.response?.numberTestsTotal && !this.flags['test-level']) ||
this.flags['test-level'] === 'NoTestRun'
) {
let testsWarn = '';

if (this.coverageOptions.reportFormats?.length) {
testsWarn += `\`--coverage-formatters\` was specified but no tests ran.${EOL}`;
}
if (this.junit) {
testsWarn += `\`--junit\` was specified but no tests ran.${EOL}`;
}
const testsWarn = (
this.coverageOptions.reportFormats?.length ? ['`--coverage-formatters` was specified but no tests ran.'] : []
)
.concat(this.junit ? ['`--junit` was specified but no tests ran.'] : [])
.concat([
'You can ensure tests run by specifying `--test-level` and setting it to `RunSpecifiedTests`, `RunLocalTests` or `RunAllTestsInOrg`.',
]);

// only emit warning if --coverage-formatters or --junit flags were passed
if (testsWarn.length > 0) {
testsWarn +=
'You can ensure tests run by specifying `--test-level` and setting it to `RunSpecifiedTests`, `RunLocalTests` or `RunAllTestsInOrg`.';
await Lifecycle.getInstance().emitWarning(testsWarn);
if (testsWarn.length > 1) {
await Lifecycle.getInstance().emitWarning(testsWarn.join(EOL));
}
}

Expand Down Expand Up @@ -185,10 +183,9 @@ export class DeployResultFormatter extends TestResultsFormatter implements Forma
...mapTestResults(ensureArray(runTestResult.failures)),
],
codecoverage: ensureArray(runTestResult?.codeCoverage).map((cov): CodeCoverageResult => {
const numLinesUncovered = parseInt(cov.numLocationsNotCovered, 10);
const [uncoveredLines, coveredLines] = generateCoveredLines(cov);
const numLocationsNum = parseInt(cov.numLocations, 10);
const numLocationsNotCovered: number = parseInt(cov.numLocationsNotCovered, 10);
const [numLocationsNum, numLinesUncovered] = getCoverageNumbers(cov);

return {
// TODO: fix this type in SDR?
type: cov.type as 'ApexClass' | 'ApexTrigger',
Expand All @@ -200,7 +197,7 @@ export class DeployResultFormatter extends TestResultsFormatter implements Forma
uncoveredLines,
percentage:
numLocationsNum > 0
? (((numLocationsNum - numLocationsNotCovered) / numLocationsNum) * 100).toFixed() + '%'
? (((numLocationsNum - numLinesUncovered) / numLocationsNum) * 100).toFixed() + '%'
: '',
};
}),
Expand Down
59 changes: 31 additions & 28 deletions src/formatters/testResultsFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
CodeCoverageWarnings,
DeployResult,
Failures,
MetadataApiDeployStatus,
RunTestResult,
Successes,
} from '@salesforce/source-deploy-retrieve';
import { ensureArray } from '@salesforce/kit';
Expand Down Expand Up @@ -40,10 +42,10 @@ export class TestResultsFormatter {
return;
}

this.displayVerboseTestFailures();
displayVerboseTestFailures(this.result.response);

if (this.verbosity === 'verbose') {
this.displayVerboseTestSuccesses();
displayVerboseTestSuccesses(this.result.response.details.runTestResult?.successes);
displayVerboseTestCoverage(this.result.response.details.runTestResult?.codeCoverage);
}

Expand All @@ -65,37 +67,38 @@ export class TestResultsFormatter {
if (this.flags.verbose) return 'verbose';
return 'normal';
}
}

private displayVerboseTestSuccesses(): void {
const successes = ensureArray(this.result.response.details.runTestResult?.successes).sort(testResultSort);
if (successes.length > 0) {
ux.log();
ux.log(success(`Test Success [${successes.length}]`));
for (const test of successes) {
const testName = underline(`${test.name}.${test.methodName}`);
ux.log(`${check} ${testName}`);
}
const displayVerboseTestSuccesses = (resultSuccesses: RunTestResult['successes']): void => {
const successes = ensureArray(resultSuccesses).sort(testResultSort);
if (successes.length > 0) {
ux.log();
ux.log(success(`Test Success [${successes.length}]`));
for (const test of successes) {
const testName = underline(`${test.name}.${test.methodName}`);
ux.log(`${check} ${testName}`);
}
}
};

private displayVerboseTestFailures(): void {
if (!this.result.response.numberTestErrors) return;
const failures = ensureArray(this.result.response.details.runTestResult?.failures).sort(testResultSort);
const failureCount = this.result.response.details.runTestResult?.numFailures;
ux.log();
ux.log(error(`Test Failures [${failureCount}]`));
for (const test of failures) {
const testName = underline(`${test.name}.${test.methodName}`);
ux.log(`• ${testName}`);
ux.log(` ${dim('message')}: ${test.message}`);
if (test.stackTrace) {
const stackTrace = test.stackTrace.replace(/\n/g, `${os.EOL} `);
ux.log(` ${dim('stacktrace')}: ${os.EOL} ${stackTrace}`);
}
ux.log();
/** display the Test failures if there are any testErrors in the mdapi deploy response */
const displayVerboseTestFailures = (response: MetadataApiDeployStatus): void => {
if (!response.numberTestErrors) return;
const failures = ensureArray(response.details.runTestResult?.failures).sort(testResultSort);
const failureCount = response.details.runTestResult?.numFailures;
ux.log();
ux.log(error(`Test Failures [${failureCount}]`));
for (const test of failures) {
const testName = underline(`${test.name}.${test.methodName}`);
ux.log(`• ${testName}`);
ux.log(` ${dim('message')}: ${test.message}`);
if (test.stackTrace) {
const stackTrace = test.stackTrace.replace(/\n/g, `${os.EOL} `);
ux.log(` ${dim('stacktrace')}: ${os.EOL} ${stackTrace}`);
}
ux.log();
}
}
};

/**
* Display the table if there is at least one coverage item in the result
Expand All @@ -109,7 +112,7 @@ const displayVerboseTestCoverage = (coverage?: CodeCoverage | CodeCoverage[]): v
ux.table(codeCoverage.sort(coverageSort).map(coverageOutput), {
name: { header: 'Name' },
coveragePercent: { header: '% Covered' },
lineNotCovered: { header: 'Uncovered Lines' },
linesNotCovered: { header: 'Uncovered Lines' },
});
}
};
Expand Down
6 changes: 3 additions & 3 deletions src/utils/coverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ export const transformCoverageToApexCoverage = (mdCoverage: CodeCoverage[]): Ape

export const coverageOutput = (
cov: CodeCoverage
): Pick<CodeCoverage, 'name'> & { coveragePercent: string; lineNotCovered: string } => ({
): Pick<CodeCoverage, 'name'> & { coveragePercent: string; linesNotCovered: string } => ({
name: cov.name,
coveragePercent: formatPercent(getCoveragePct(cov)),
lineNotCovered: cov.locationsNotCovered
linesNotCovered: cov.locationsNotCovered
? ensureArray(cov.locationsNotCovered)
.map((location) => location.line)
.join(',')
Expand All @@ -109,7 +109,7 @@ const color = (percent: number): Chalk =>

const formatPercent = (percent: number): string => color(percent)(`${percent}%`);

const getCoveragePct = (cov: CodeCoverage): number => {
export const getCoveragePct = (cov: CodeCoverage): number => {
const [lineCount, uncoveredLineCount] = getCoverageNumbers(cov);
const coverageDecimal = parseFloat(((lineCount - uncoveredLineCount) / lineCount).toFixed(2));

Expand Down
Loading

0 comments on commit d0a3bef

Please sign in to comment.