Skip to content

Commit 0af5887

Browse files
authored
Merge pull request #38 from salesforcecli/mdonnalley/junit
feat: support junit test formatter
2 parents 3999aca + 1914956 commit 0af5887

File tree

9 files changed

+204
-30
lines changed

9 files changed

+204
-30
lines changed

command-snapshot.json

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,34 @@
4747
"alias": [],
4848
"command": "agent:test:results",
4949
"flagAliases": [],
50-
"flagChars": ["i", "o"],
51-
"flags": ["api-version", "flags-dir", "job-id", "json", "result-format", "target-org"],
50+
"flagChars": ["f", "i", "o"],
51+
"flags": ["api-version", "flags-dir", "job-id", "json", "output-dir", "result-format", "target-org"],
5252
"plugin": "@salesforce/plugin-agent"
5353
},
5454
{
5555
"alias": [],
5656
"command": "agent:test:resume",
5757
"flagAliases": [],
58-
"flagChars": ["i", "o", "r", "w"],
59-
"flags": ["api-version", "flags-dir", "job-id", "json", "result-format", "target-org", "use-most-recent", "wait"],
58+
"flagChars": ["f", "i", "o", "r", "w"],
59+
"flags": [
60+
"api-version",
61+
"flags-dir",
62+
"job-id",
63+
"json",
64+
"output-dir",
65+
"result-format",
66+
"target-org",
67+
"use-most-recent",
68+
"wait"
69+
],
6070
"plugin": "@salesforce/plugin-agent"
6171
},
6272
{
6373
"alias": [],
6474
"command": "agent:test:run",
6575
"flagAliases": [],
66-
"flagChars": ["n", "o", "w"],
67-
"flags": ["api-version", "flags-dir", "json", "name", "result-format", "target-org", "wait"],
76+
"flagChars": ["f", "n", "o", "w"],
77+
"flags": ["api-version", "flags-dir", "json", "name", "output-dir", "result-format", "target-org", "wait"],
6878
"plugin": "@salesforce/plugin-agent"
6979
}
7080
]

messages/shared.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
# flags.result-format.summary
22

33
Format of the test run results.
4+
5+
# flags.output-dir.summary
6+
7+
Directory to write the test results to.
8+
9+
# flags.output-dir.description
10+
11+
If test run is complete, write the results to the specified directory. If the tests are still running, the test results will not be written.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"@inquirer/select": "^4.0.1",
1111
"@oclif/core": "^4",
1212
"@oclif/multi-stage-output": "^0.7.12",
13-
"@salesforce/agents": "^0.3.0",
13+
"@salesforce/agents": "^0.4.0",
1414
"@salesforce/core": "^8.8.0",
1515
"@salesforce/kit": "^3.2.1",
1616
"@salesforce/sf-plugins-core": "^12.1.0",

src/commands/agent/test/results.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77

88
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
99
import { Messages } from '@salesforce/core';
10-
import { AgentTester, AgentTestDetailsResponse, humanFormat } from '@salesforce/agents';
11-
import { resultFormatFlag } from '../../../flags.js';
10+
import { AgentTester, AgentTestDetailsResponse } from '@salesforce/agents';
11+
import { resultFormatFlag, testOutputDirFlag } from '../../../flags.js';
12+
import { handleTestResults } from '../../../handleTestResults.js';
1213

1314
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
1415
const messages = Messages.loadMessages('@salesforce/plugin-agent', 'agent.test.results');
@@ -30,16 +31,21 @@ export default class AgentTestResults extends SfCommand<AgentTestResultsResult>
3031
required: true,
3132
}),
3233
'result-format': resultFormatFlag(),
34+
'output-dir': testOutputDirFlag(),
3335
};
3436

3537
public async run(): Promise<AgentTestResultsResult> {
3638
const { flags } = await this.parse(AgentTestResults);
3739

3840
const agentTester = new AgentTester(flags['target-org'].getConnection(flags['api-version']));
3941
const response = await agentTester.details(flags['job-id']);
40-
if (flags['result-format'] === 'human') {
41-
this.log(await humanFormat(flags['job-id'], response));
42-
}
42+
await handleTestResults({
43+
id: flags['job-id'],
44+
format: flags['result-format'],
45+
results: response,
46+
jsonEnabled: this.jsonEnabled(),
47+
outputDir: flags['output-dir'],
48+
});
4349
return response;
4450
}
4551
}

src/commands/agent/test/resume.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77

88
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
99
import { Messages } from '@salesforce/core';
10-
import { AgentTester, humanFormat } from '@salesforce/agents';
10+
import { AgentTester } from '@salesforce/agents';
1111
import { AgentTestCache } from '../../../agentTestCache.js';
1212
import { TestStages } from '../../../testStages.js';
13-
import { resultFormatFlag } from '../../../flags.js';
13+
import { resultFormatFlag, testOutputDirFlag } from '../../../flags.js';
14+
import { handleTestResults } from '../../../handleTestResults.js';
1415

1516
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
1617
const messages = Messages.loadMessages('@salesforce/plugin-agent', 'agent.test.resume');
@@ -48,6 +49,7 @@ export default class AgentTestResume extends SfCommand<AgentTestResumeResult> {
4849
description: messages.getMessage('flags.wait.description'),
4950
}),
5051
'result-format': resultFormatFlag(),
52+
'output-dir': testOutputDirFlag(),
5153
};
5254

5355
public async run(): Promise<AgentTestResumeResult> {
@@ -68,9 +70,13 @@ export default class AgentTestResume extends SfCommand<AgentTestResumeResult> {
6870

6971
mso.stop();
7072

71-
if (response && flags['result-format'] === 'human') {
72-
this.log(await humanFormat(name ?? aiEvaluationId, response));
73-
}
73+
await handleTestResults({
74+
id: aiEvaluationId,
75+
format: flags['result-format'],
76+
results: response,
77+
jsonEnabled: this.jsonEnabled(),
78+
outputDir: flags['output-dir'],
79+
});
7480

7581
return {
7682
status: 'COMPLETED',

src/commands/agent/test/run.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77

88
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
99
import { Messages } from '@salesforce/core';
10-
import { AgentTester, humanFormat } from '@salesforce/agents';
10+
import { AgentTester } from '@salesforce/agents';
1111
import { colorize } from '@oclif/core/ux';
12-
import { resultFormatFlag } from '../../../flags.js';
12+
import { resultFormatFlag, testOutputDirFlag } from '../../../flags.js';
1313
import { AgentTestCache } from '../../../agentTestCache.js';
1414
import { TestStages } from '../../../testStages.js';
15+
import { handleTestResults } from '../../../handleTestResults.js';
1516

1617
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
1718
const messages = Messages.loadMessages('@salesforce/plugin-agent', 'agent.test.run');
@@ -47,6 +48,7 @@ export default class AgentTestRun extends SfCommand<AgentTestRunResult> {
4748
description: messages.getMessage('flags.wait.description'),
4849
}),
4950
'result-format': resultFormatFlag(),
51+
'output-dir': testOutputDirFlag(),
5052
};
5153

5254
public async run(): Promise<AgentTestRunResult> {
@@ -69,9 +71,14 @@ export default class AgentTestRun extends SfCommand<AgentTestRunResult> {
6971

7072
mso.stop();
7173

72-
if (detailsResponse && flags['result-format'] === 'human') {
73-
this.log(await humanFormat(flags.name, detailsResponse));
74-
}
74+
await handleTestResults({
75+
id: response.aiEvaluationId,
76+
format: flags['result-format'],
77+
results: detailsResponse,
78+
jsonEnabled: this.jsonEnabled(),
79+
outputDir: flags['output-dir'],
80+
});
81+
7582
return {
7683
status: 'COMPLETED',
7784
aiEvaluationId: response.aiEvaluationId,

src/flags.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@ export const resultFormatFlag = Flags.option({
1414
options: [
1515
'json',
1616
'human',
17+
'junit',
1718
// 'tap',
18-
// 'junit'
1919
] as const,
2020
default: 'human',
2121
summary: messages.getMessage('flags.result-format.summary'),
2222
});
23+
24+
export const testOutputDirFlag = Flags.custom<string>({
25+
char: 'f',
26+
description: messages.getMessage('flags.output-dir.description'),
27+
summary: messages.getMessage('flags.output-dir.summary'),
28+
});

src/handleTestResults.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (c) 2024, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import { join } from 'node:path';
8+
import { writeFile, mkdir } from 'node:fs/promises';
9+
import { AgentTestDetailsResponse, jsonFormat, humanFormat, junitFormat } from '@salesforce/agents';
10+
import { Ux } from '@salesforce/sf-plugins-core/Ux';
11+
12+
async function writeFileToDir(outputDir: string, fileName: string, content: string): Promise<void> {
13+
// if directory doesn't exist, create it
14+
await mkdir(outputDir, { recursive: true });
15+
16+
await writeFile(join(outputDir, fileName), content);
17+
}
18+
19+
export async function handleTestResults({
20+
id,
21+
format,
22+
results,
23+
jsonEnabled,
24+
outputDir,
25+
}: {
26+
id: string;
27+
format: 'human' | 'json' | 'junit';
28+
results: AgentTestDetailsResponse | undefined;
29+
jsonEnabled: boolean;
30+
outputDir?: string;
31+
}): Promise<void> {
32+
if (!results) {
33+
// do nothing since there are no results to handle
34+
return;
35+
}
36+
37+
const ux = new Ux({ jsonEnabled });
38+
39+
if (format === 'human') {
40+
const formatted = await humanFormat(results);
41+
ux.log(formatted);
42+
if (outputDir) {
43+
await writeFileToDir(outputDir, `test-result-${id}.txt`, formatted);
44+
}
45+
}
46+
47+
if (format === 'json') {
48+
const formatted = await jsonFormat(results);
49+
ux.log(formatted);
50+
if (outputDir) {
51+
await writeFileToDir(outputDir, `test-result-${id}.json`, formatted);
52+
}
53+
}
54+
55+
if (format === 'junit') {
56+
const formatted = await junitFormat(results);
57+
ux.log(formatted);
58+
if (outputDir) {
59+
await writeFileToDir(outputDir, `test-result-${id}.xml`, formatted);
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)