Skip to content

Commit 16661d8

Browse files
committed
feat: use deprecatedArray for consistency in sf commands and compatibility
1 parent db42532 commit 16661d8

File tree

4 files changed

+67
-58
lines changed

4 files changed

+67
-58
lines changed

messages/runtest.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ NOTE: The testRunCoverage value (JSON and JUnit result formats) is a percentage
2020

2121
- Run the specified Apex test classes in your default org and display results in human-readable form:
2222

23-
<%= config.bin %> <%= command.id %> --class-names "MyClassTest,MyOtherClassTest" --result-format human
23+
<%= config.bin %> <%= command.id %> --class-names MyClassTest --class-names MyOtherClassTest --result-format human
2424

2525
- Run the specified Apex test suites in your default org and include code coverage results and additional details:
2626

27-
<%= config.bin %> <%= command.id %> --suite-names "MySuite,MyOtherSuite" --code-coverage --detailed-coverage
27+
<%= config.bin %> <%= command.id %> --suite-names MySuite --suite-names MyOtherSuite --code-coverage --detailed-coverage
2828

2929
- Run the specified Apex tests in your default org and display results in human-readable output:
3030

31-
<%= config.bin %> <%= command.id %> --tests "MyClassTest.testCoolFeature,MyClassTest.testAwesomeFeature,AnotherClassTest,namespace.TheirClassTest.testThis" --result-format human
31+
<%= config.bin %> <%= command.id %> --tests MyClassTest.testCoolFeature --tests MyClassTest.testAwesomeFeature --tests AnotherClassTest --tests namespace.TheirClassTest.testThis --result-format human
3232

3333
- Run all tests in the org with the specified username with the specified test level; save the output to the specified directory:
3434

@@ -40,27 +40,33 @@ Format of the test results.
4040

4141
# flags.class-names.summary
4242

43-
Comma-separated list of Apex test class names to run; default is all classes.
43+
Apex test class names to run; default is all classes.
4444

4545
# flags.class-names.description
4646

4747
If you select --class-names, you can't specify --suite-names or --tests.
48+
For multiple classes, repeat the flag for each.
49+
--class-names Class1 --class-names Class2
4850

4951
# flags.suite-names.summary
5052

51-
Comma-separated list of Apex test suite names to run; default is all suites.
53+
Apex test suite names to run; default is all suites.
5254

5355
# flags.suite-names.description
5456

5557
If you select --suite-names, you can't specify --class-names or --tests.
58+
For multiple suites, repeat the flag for each.
59+
--suite-names Suite1 --suite-names Suite2
5660

5761
# flags.tests.summary
5862

59-
Comma-separated list of Apex test class names or IDs and, if applicable, test methods to run; default is all tests.
63+
Apex test class names or IDs and, if applicable, test methods to run; default is all tests.
6064

6165
# flags.tests.description
6266

6367
If you specify --tests, you can't specify --class-names or --suite-names
68+
For multiple tests, repeat the flag for each.
69+
--tests Test1 --tests Test2
6470

6571
# flags.code-coverage.summary
6672

@@ -98,10 +104,6 @@ Display detailed code coverage per test.
98104

99105
Run "%s apex get test -i %s -o %s" to retrieve test results
100106

101-
# classSuiteTestErr
102-
103-
Specify either classnames, suitenames, or tests
104-
105107
# syncClassErr
106108

107109
Synchronous test runs can include test methods from only one Apex class. Omit the --synchronous flag or include tests from only one class

src/commands/apex/run.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export default class Run extends SfCommand<ExecuteResult> {
4545
aliases: ['apexcodefile'],
4646
char: 'f',
4747
summary: messages.getMessage('flags.file'),
48+
exists: true,
4849
}),
4950
};
5051

src/commands/apex/run/test.ts

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
import { CancellationTokenSource, TestLevel, TestResult, TestRunIdResult, TestService } from '@salesforce/apex-node';
88
import {
9+
arrayWithDeprecation,
910
Flags,
1011
loglevel,
1112
orgApiVersionFlagWithDeprecations,
@@ -24,6 +25,7 @@ const messages = Messages.loadMessages('@salesforce/plugin-apex', 'runtest');
2425

2526
export const TestLevelValues = ['RunLocalTests', 'RunAllTestsInOrg', 'RunSpecifiedTests'];
2627
export type RunCommandResult = RunResult | TestRunIdResult;
28+
const exclusiveTestSpecifiers = ['class-names', 'suite-names', 'tests'];
2729
export default class Test extends SfCommand<RunCommandResult> {
2830
public static readonly summary = messages.getMessage('summary');
2931
public static readonly description = messages.getMessage('description');
@@ -55,12 +57,13 @@ export default class Test extends SfCommand<RunCommandResult> {
5557
description: messages.getMessage('flags.test-level.description'),
5658
options: TestLevelValues,
5759
}),
58-
'class-names': Flags.string({
60+
'class-names': arrayWithDeprecation({
5961
deprecateAliases: true,
6062
aliases: ['classnames'],
6163
char: 'n',
6264
summary: messages.getMessage('flags.class-names.summary'),
6365
description: messages.getMessage('flags.class-names.description'),
66+
exclusive: exclusiveTestSpecifiers.filter((specifier) => specifier !== 'class-names'),
6467
}),
6568
'result-format': Flags.string({
6669
deprecateAliases: true,
@@ -70,17 +73,19 @@ export default class Test extends SfCommand<RunCommandResult> {
7073
options: resultFormat,
7174
default: 'human',
7275
}),
73-
'suite-names': Flags.string({
76+
'suite-names': arrayWithDeprecation({
7477
deprecateAliases: true,
7578
aliases: ['suitenames'],
7679
char: 's',
7780
summary: messages.getMessage('flags.suite-names.summary'),
7881
description: messages.getMessage('flags.suite-names.description'),
82+
exclusive: exclusiveTestSpecifiers.filter((specifier) => specifier !== 'suite-names'),
7983
}),
80-
tests: Flags.string({
84+
tests: arrayWithDeprecation({
8185
char: 't',
8286
summary: messages.getMessage('flags.tests.summary'),
8387
description: messages.getMessage('flags.tests.description'),
88+
exclusive: exclusiveTestSpecifiers.filter((specifier) => specifier !== 'tests'),
8489
}),
8590
// we want to pass `undefined` to the API
8691
// eslint-disable-next-line sf-plugin/flag-min-max-default
@@ -108,9 +113,7 @@ export default class Test extends SfCommand<RunCommandResult> {
108113
public async run(): Promise<RunCommandResult> {
109114
const { flags } = await this.parse(Test);
110115

111-
const testLevel = await this.validateFlags(
112-
flags['code-coverage'],
113-
flags['result-format'],
116+
const testLevel = await validateFlags(
114117
flags['class-names'],
115118
flags['suite-names'],
116119
flags.tests,
@@ -159,48 +162,17 @@ export default class Test extends SfCommand<RunCommandResult> {
159162
}
160163
}
161164

162-
// eslint-disable-next-line class-methods-use-this
163-
public async validateFlags(
164-
codeCoverage?: boolean,
165-
resultFormatFlag?: string,
166-
classNames?: string,
167-
suiteNames?: string,
168-
tests?: string,
169-
synchronous?: boolean,
170-
testLevel?: TestLevel
171-
): Promise<TestLevel> {
172-
if ((classNames && (suiteNames || tests)) || (suiteNames && tests)) {
173-
return Promise.reject(new Error(messages.getMessage('classSuiteTestErr')));
174-
}
175-
176-
if (synchronous && (suiteNames || (classNames && classNames.split(',').length > 1))) {
177-
return Promise.reject(new Error(messages.getMessage('syncClassErr')));
178-
}
179-
180-
if ((tests || classNames || suiteNames) && testLevel && testLevel !== 'RunSpecifiedTests') {
181-
return Promise.reject(new Error(messages.getMessage('testLevelErr')));
182-
}
183-
184-
if (testLevel) {
185-
return testLevel;
186-
}
187-
if (classNames || suiteNames || tests) {
188-
return TestLevel.RunSpecifiedTests;
189-
}
190-
return TestLevel.RunLocalTests;
191-
}
192-
193165
private async runTest(
194166
testService: TestService,
195167
flags: {
196-
tests?: string;
197-
'class-names'?: string;
168+
tests?: string[];
169+
'class-names'?: string[];
198170
'code-coverage'?: boolean;
199171
},
200172
testLevel: TestLevel
201173
): Promise<TestResult> {
202174
const payload = {
203-
...(await testService.buildSyncPayload(testLevel, flags.tests, flags['class-names'])),
175+
...(await testService.buildSyncPayload(testLevel, flags.tests?.join(','), flags['class-names']?.join(','))),
204176
skipCodeCoverage: !flags['code-coverage'],
205177
};
206178
return testService.runTestSynchronous(
@@ -213,9 +185,9 @@ export default class Test extends SfCommand<RunCommandResult> {
213185
private async runTestAsynchronous(
214186
testService: TestService,
215187
flags: {
216-
tests?: string;
217-
'class-names'?: string;
218-
'suite-names'?: string;
188+
tests?: string[];
189+
'class-names'?: string[];
190+
'suite-names'?: string[];
219191
'code-coverage'?: boolean;
220192
synchronous?: boolean;
221193
'result-format'?: string;
@@ -225,7 +197,12 @@ export default class Test extends SfCommand<RunCommandResult> {
225197
testLevel: TestLevel
226198
): Promise<TestRunIdResult> {
227199
const payload = {
228-
...(await testService.buildAsyncPayload(testLevel, flags.tests, flags['class-names'], flags['suite-names'])),
200+
...(await testService.buildAsyncPayload(
201+
testLevel,
202+
flags.tests?.join(','),
203+
flags['class-names']?.join(','),
204+
flags['suite-names']?.join(',')
205+
)),
229206
skipCodeCoverage: !flags['code-coverage'],
230207
};
231208

@@ -239,3 +216,28 @@ export default class Test extends SfCommand<RunCommandResult> {
239216
) as Promise<TestRunIdResult>;
240217
}
241218
}
219+
220+
// eslint-disable-next-line class-methods-use-this
221+
const validateFlags = async (
222+
classNames?: string[],
223+
suiteNames?: string[],
224+
tests?: string[],
225+
synchronous?: boolean,
226+
testLevel?: TestLevel
227+
): Promise<TestLevel> => {
228+
if (synchronous && (suiteNames || (classNames?.length && classNames.length > 1))) {
229+
return Promise.reject(new Error(messages.getMessage('syncClassErr')));
230+
}
231+
232+
if ((tests || classNames || suiteNames) && testLevel && testLevel !== 'RunSpecifiedTests') {
233+
return Promise.reject(new Error(messages.getMessage('testLevelErr')));
234+
}
235+
236+
if (testLevel) {
237+
return testLevel;
238+
}
239+
if (classNames || suiteNames || tests) {
240+
return TestLevel.RunSpecifiedTests;
241+
}
242+
return TestLevel.RunLocalTests;
243+
};

test/commands/apex/run/test.test.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { Messages, Org } from '@salesforce/core';
1010
import { createSandbox, SinonSandbox } from 'sinon';
1111
import { Ux } from '@salesforce/sf-plugins-core';
1212
import { Config } from '@oclif/core';
13-
import { expect } from 'chai';
13+
import { assert, expect } from 'chai';
1414
import { TestService } from '@salesforce/apex-node';
1515
import Test from '../../../../src/commands/apex/run/test';
1616
import {
@@ -401,22 +401,26 @@ describe('apex:test:run', () => {
401401
});
402402

403403
it('rejects classname/suitnames/test variations', async () => {
404+
// uses oclif exclusive now
404405
try {
405406
await new Test(['--class-names', 'myApex', '--suite-names', 'testsuite'], config).run();
406407
} catch (e) {
407-
expect((e as Error).message).to.equal(messages.getMessage('classSuiteTestErr'));
408+
assert(e instanceof Error);
409+
expect(e.message).to.include('cannot also be provided when using');
408410
}
409411

410412
try {
411413
await new Test(['--class-names', 'myApex', '--tests', 'testsuite'], config).run();
412414
} catch (e) {
413-
expect((e as Error).message).to.equal(messages.getMessage('classSuiteTestErr'));
415+
assert(e instanceof Error);
416+
expect(e.message).to.include('cannot also be provided when using');
414417
}
415418

416419
try {
417420
await new Test(['--suite-names', 'myApex', '--tests', 'testsuite'], config).run();
418421
} catch (e) {
419-
expect((e as Error).message).to.equal(messages.getMessage('classSuiteTestErr'));
422+
assert(e instanceof Error);
423+
expect(e.message).to.include('cannot also be provided when using');
420424
}
421425
});
422426
});

0 commit comments

Comments
 (0)