Skip to content

Commit d95f0a3

Browse files
committed
feat: show test failures while polling for status
1 parent dcd59c2 commit d95f0a3

File tree

3 files changed

+46
-6
lines changed

3 files changed

+46
-6
lines changed

src/formatters/testResultsFormatter.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
Successes,
1919
} from '@salesforce/source-deploy-retrieve';
2020
import { ensureArray } from '@salesforce/kit';
21-
import { TestLevel, Verbosity } from '../utils/types.js';
21+
import { isTruthy, TestLevel, Verbosity } from '../utils/types.js';
2222
import { tableHeader, error, success, check } from '../utils/output.js';
2323
import { coverageOutput } from '../utils/coverage.js';
2424

@@ -45,7 +45,9 @@ export class TestResultsFormatter {
4545
return;
4646
}
4747

48-
displayVerboseTestFailures(this.result.response);
48+
if (!isTruthy(process.env.CI)) {
49+
displayVerboseTestFailures(this.result.response);
50+
}
4951

5052
if (this.verbosity === 'verbose') {
5153
displayVerboseTestSuccesses(this.result.response.details.runTestResult?.successes);

src/utils/deployStages.ts

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,22 @@
44
* Licensed under the BSD 3-Clause license.
55
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
7+
import os from 'node:os';
78
import { MultiStageOutput } from '@oclif/multi-stage-output';
89
import { Lifecycle, Messages } from '@salesforce/core';
9-
import { MetadataApiDeploy, MetadataApiDeployStatus, RequestStatus } from '@salesforce/source-deploy-retrieve';
10+
import {
11+
Failures,
12+
MetadataApiDeploy,
13+
MetadataApiDeployStatus,
14+
RequestStatus,
15+
Successes,
16+
} from '@salesforce/source-deploy-retrieve';
1017
import { SourceMemberPollingEvent } from '@salesforce/source-tracking';
1118
import terminalLink from 'terminal-link';
19+
import { ensureArray } from '@salesforce/kit';
20+
import ansis from 'ansis';
1221
import { getZipFileSize } from './output.js';
22+
import { isTruthy } from './types.js';
1323

1424
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
1525
const mdTransferMessages = Messages.loadMessages('@salesforce/plugin-deploy-retrieve', 'metadata.transfer');
@@ -129,7 +139,7 @@ export class DeployStages {
129139
type: 'dynamic-key-value',
130140
},
131141
{
132-
label: 'Completed',
142+
label: 'Successful',
133143
get: (data): string | undefined =>
134144
data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestsCompleted
135145
? formatProgress(data?.mdapiDeploy?.numberTestsCompleted, data?.mdapiDeploy?.numberTestsTotal)
@@ -138,10 +148,11 @@ export class DeployStages {
138148
type: 'dynamic-key-value',
139149
},
140150
{
141-
label: 'Failures',
151+
label: 'Failed',
142152
get: (data): string | undefined =>
143153
data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestErrors
144-
? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal)
154+
? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) +
155+
(isTruthy(process.env.CI) ? os.EOL + formatTestFailures(data) : '')
145156
: undefined,
146157
stage: 'Running Tests',
147158
type: 'dynamic-key-value',
@@ -241,3 +252,26 @@ export class DeployStages {
241252
this.mso.skipTo('Done', data);
242253
}
243254
}
255+
256+
function formatTestFailures(data: Data): string {
257+
if (data.mdapiDeploy.details.runTestResult?.failures === undefined) return '';
258+
const failures = ensureArray(data.mdapiDeploy.details.runTestResult?.failures).sort(testResultSort);
259+
260+
let output = '';
261+
262+
for (const test of failures) {
263+
const testName = ansis.underline(`${test.name}.${test.methodName}`);
264+
output += ` • ${testName}${os.EOL}`;
265+
output += ` message: ${test.message}${os.EOL}`;
266+
if (test.stackTrace) {
267+
const stackTrace = test.stackTrace.replace(/\n/g, `${os.EOL} `);
268+
output += ` stacktrace:${os.EOL} ${stackTrace}${os.EOL}${os.EOL}`;
269+
}
270+
}
271+
272+
// remove last EOL char
273+
return output.slice(0, -1);
274+
}
275+
276+
const testResultSort = <T extends Successes | Failures>(a: T, b: T): number =>
277+
a.methodName === b.methodName ? a.name.localeCompare(b.name) : a.methodName.localeCompare(b.methodName);

src/utils/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,7 @@ export const isFileResponseDeleted = (fileResponse: FileResponseSuccess): boolea
124124
fileResponse.state === ComponentStatus.Deleted;
125125

126126
export const isDefined = <T>(value?: T): value is T => value !== undefined;
127+
128+
export function isTruthy(value: string | undefined): boolean {
129+
return value !== '0' && value !== 'false';
130+
}

0 commit comments

Comments
 (0)