Skip to content

Commit ca2076c

Browse files
fix: add initial NUTs, u-tests
1 parent 74a3cdd commit ca2076c

File tree

8 files changed

+240
-69
lines changed

8 files changed

+240
-69
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"dependencies": {
88
"@oclif/config": "^1",
99
"@salesforce/command": "^3.1.0",
10-
"@salesforce/core": "^2.18.3",
10+
"@salesforce/core": "^2.19.1",
1111
"@salesforce/source-deploy-retrieve": "^1.1.17",
1212
"chalk": "^4.1.0",
1313
"tslib": "^2"
@@ -16,10 +16,10 @@
1616
"@oclif/dev-cli": "^1",
1717
"@oclif/plugin-command-snapshot": "^2.0.0",
1818
"@salesforce/dev-config": "^2.1.0",
19-
"@salesforce/cli-plugins-testkit": "^0.0.4",
19+
"@salesforce/cli-plugins-testkit": "^0.0.8",
2020
"@salesforce/dev-scripts": "^0.7.0",
2121
"@salesforce/plugin-command-reference": "^1.3.0",
22-
"@salesforce/prettier-config": "^0.0.1",
22+
"@salesforce/prettier-config": "^0.0.2",
2323
"@salesforce/ts-sinon": "1.3.0",
2424
"@typescript-eslint/eslint-plugin": "^4.2.0",
2525
"@typescript-eslint/parser": "^4.2.0",

src/commands/force/source/deploy.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { flags, FlagsConfig } from '@salesforce/command';
1010
import { Lifecycle, Messages } from '@salesforce/core';
1111
import { SourceDeployResult } from '@salesforce/source-deploy-retrieve';
1212
import { Duration } from '@salesforce/kit';
13-
import { asString } from '@salesforce/ts-types';
13+
import { asString, asArray } from '@salesforce/ts-types';
1414
import * as chalk from 'chalk';
1515
import { SourceCommand } from '../../../sourceCommand';
1616

@@ -97,9 +97,9 @@ export class deploy extends SourceCommand {
9797
const hookEmitter = Lifecycle.getInstance();
9898

9999
const cs = await this.createComponentSet({
100-
sourcepath: this.flags.sourcepath as string[],
100+
sourcepath: asArray<string>(this.flags.sourcepath),
101101
manifest: asString(this.flags.manifest),
102-
metadata: this.flags.metadata as string[],
102+
metadata: asArray<string>(this.flags.metadata),
103103
});
104104

105105
await hookEmitter.emit('predeploy', { packageXmlPath: cs.getPackageXml() });

src/commands/force/source/retrieve.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { flags, FlagsConfig } from '@salesforce/command';
1010
import { Lifecycle, Messages, SfdxError, SfdxProjectJson } from '@salesforce/core';
1111
import { SourceRetrieveResult } from '@salesforce/source-deploy-retrieve';
1212
import { Duration } from '@salesforce/kit';
13-
import { asString } from '@salesforce/ts-types';
13+
import { asArray, asString } from '@salesforce/ts-types';
1414
import { blue, yellow } from 'chalk';
1515
import { SourceCommand } from '../../../sourceCommand';
1616

@@ -60,10 +60,10 @@ export class retrieve extends SourceCommand {
6060

6161
const cs = await this.createComponentSet({
6262
// safe to cast from the flags as an array of strings
63-
packagenames: this.flags.packagenames as string[],
64-
sourcepath: this.flags.sourcepath as string[],
63+
packagenames: asArray<string>(this.flags.packagenames),
64+
sourcepath: asArray<string>(this.flags.sourcepath),
6565
manifest: asString(this.flags.manifest),
66-
metadata: this.flags.metadata as string[],
66+
metadata: asArray<string>(this.flags.metadata),
6767
});
6868

6969
// emit pre retrieve event

src/sourceCommand.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,9 @@ export abstract class SourceCommand extends SfdxCommand {
3434
if (options.sourcepath) {
3535
options.sourcepath.forEach((filepath) => {
3636
if (fs.fileExistsSync(filepath)) {
37-
this.logger.debug(`Creating ComponentSet from sourcepath ${path.resolve(filepath)}`);
3837
setAggregator.push(...ComponentSet.fromSource(path.resolve(filepath)));
3938
} else {
40-
throw SfdxError.create('@salesforce/plugin-source', 'sourceCommand', 'SourcePathInvalid', [filepath]);
39+
throw new SfdxError(`The sourcepath "${filepath}" is not a valid source file path.`);
4140
}
4241
});
4342
}
@@ -48,8 +47,6 @@ export abstract class SourceCommand extends SfdxCommand {
4847
}
4948

5049
if (options.manifest) {
51-
this.logger.debug(`Creating ComponentSet from manifest ${path.resolve(options.manifest)}`);
52-
5350
setAggregator.push(
5451
...(await ComponentSet.fromManifestFile(options.manifest, {
5552
// to create a link to the actual source component we need to have it resolve through all packages
@@ -68,8 +65,6 @@ export abstract class SourceCommand extends SfdxCommand {
6865
// either -m ApexClass or -m ApexClass:MyApexClass
6966
fullName: splitEntry.length === 1 ? '*' : splitEntry[1],
7067
};
71-
this.logger.debug(`Creating ComponentSet from metadata member ${metadata.type}:${metadata.fullName}`);
72-
7368
const cs = new ComponentSet([metadata]);
7469
// we need to search the entire project for the matching metadata component
7570
// no better way than to have it search than process.cwd()

test/commands/source/deploy.nut.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2020, 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 { TestSession, execCmd } from '@salesforce/cli-plugins-testkit';
8+
9+
let session: TestSession;
10+
11+
describe('source:deploy NUTs', () => {
12+
before(() => {
13+
session = TestSession.create({
14+
project: {
15+
gitClone: 'https://github.com/amphro/simple-mpd-project.git',
16+
},
17+
// create org and push source to get something to deploy
18+
setupCommands: [
19+
'sfdx force:org:create -d 1 -s -f config/project-scratch-def.json',
20+
'sfdx force:source:push',
21+
'sfdx force:source:convert --packagename force-app --outputdir FORCE-APP',
22+
'sfdx force:source:convert --packagename my-app --outputdir MY-APP',
23+
],
24+
});
25+
});
26+
27+
it('deploys via sourcepath', () => {
28+
execCmd('force:source:deploy --sourcepath "force-app" --json', { ensureExitCode: 0 });
29+
// TODO: once json is fixed add json validation
30+
// const output =
31+
// expect(output.jsonOutput)
32+
// .to.have.property('result')
33+
// .with.keys(['username', 'accessToken', 'id', 'orgId', 'profileName', 'loginUrl', 'instanceUrl']);
34+
// const result = (output.jsonOutput as Record<string, unknown>).result as Record<string, string>;
35+
// expect(result.orgId).to.have.length(18);
36+
// expect(result.id).to.have.length(18);
37+
// expect(result.accessToken.startsWith(result.orgId.substr(0, 15))).to.be.true;
38+
});
39+
40+
it('deploys via sourcepath with multiple', () => {
41+
execCmd('force:source:deploy --sourcepath "force-app, my-app" --json', { ensureExitCode: 0 });
42+
});
43+
44+
// it('deploys via package name with spaces', () => {
45+
// execCmd('force:source:deploy --packagenames "my app" --json', { ensureExitCode: 0 });
46+
// });
47+
//
48+
// it('deploys via package names', () => {
49+
// execCmd('force:source:deploy --packagenames "my app, force-app" --json', { ensureExitCode: 0 });
50+
// });
51+
52+
it('deploys via metadata', () => {
53+
execCmd('force:source:deploy --metadata ApexClass --json', { ensureExitCode: 0 });
54+
});
55+
56+
it('deploys via metadata', () => {
57+
execCmd('force:source:deploy --metadata ApexClass:MyTest --json', { ensureExitCode: 0 });
58+
});
59+
60+
it('deploys via metadata mixed param types', () => {
61+
execCmd('force:source:deploy --metadata ApexClass:MyTest,CustomField --json', { ensureExitCode: 0 });
62+
});
63+
64+
it('deploys via manifest', () => {
65+
execCmd('force:source:deploy --manifest "FORCE-APP/package.xml" --json', { ensureExitCode: 0 });
66+
});
67+
68+
it('deploys via multiple manifests', () => {
69+
execCmd('force:source:deploy --manifest "FORCE-APP/package.xml,MY-APP/package.xml" --json', {
70+
ensureExitCode: 0,
71+
});
72+
});
73+
74+
it('deploys via undefined manifest, should fail', () => {
75+
execCmd('force:source:deploy --manifest "doesnotexist.xml --json', { ensureExitCode: 1 });
76+
});
77+
78+
after(async () => {
79+
await session.clean();
80+
});
81+
});

test/commands/source/retrieve.nut.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,24 @@
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 { execCmd } from '@salesforce/cli-plugins-testkit';
8-
// import { TestSession, execCmd } from '@salesforce/cli-plugins-testkit';
7+
import { TestSession, execCmd } from '@salesforce/cli-plugins-testkit';
98

10-
// let session: TestSession;
9+
let session: TestSession;
1110

1211
describe('source:retrieve NUTs', () => {
1312
before(() => {
14-
// session = TestSession.create({
15-
// project: {
16-
// gitClone: 'https://github.com/trailheadapps/ebikes-lwc.git',
17-
// },
18-
// // create org and push source to get something to retrieve
19-
// setupCommands: [
20-
// 'sfdx force:org:create -d 1 -s -f config/project-scratch-def.json',
21-
// 'sfdx force:source:push',
22-
// 'sfdx force:source:convert --packagename force-app --outputdir FORCE-APP',
23-
// 'sfdx force:source:convert --packagename my-app --outputdir MY-APP',
24-
// ],
25-
// });
13+
session = TestSession.create({
14+
project: {
15+
gitClone: 'https://github.com/amphro/simple-mpd-project.git',
16+
},
17+
// create org and push source to get something to retrieve
18+
setupCommands: [
19+
'sfdx force:org:create -d 1 -s -f config/project-scratch-def.json',
20+
'sfdx force:source:push',
21+
'sfdx force:source:convert --packagename force-app --outputdir FORCE-APP',
22+
'sfdx force:source:convert --packagename my-app --outputdir MY-APP',
23+
],
24+
});
2625
});
2726

2827
it('retrieves via sourcepath', () => {
@@ -42,13 +41,13 @@ describe('source:retrieve NUTs', () => {
4241
execCmd('force:source:retrieve --sourcepath "force-app, my-app" --json', { ensureExitCode: 0 });
4342
});
4443

45-
it('retrieves via package name with spaces', () => {
46-
execCmd('force:source:retrieve --packagenames "my app" --json', { ensureExitCode: 0 });
47-
});
48-
49-
it('retrieves via package names', () => {
50-
execCmd('force:source:retrieve --packagenames "my app, force-app" --json', { ensureExitCode: 0 });
51-
});
44+
// it('retrieves via package name with spaces', () => {
45+
// execCmd('force:source:retrieve --packagenames "my app" --json', { ensureExitCode: 0 });
46+
// });
47+
//
48+
// it('retrieves via package names', () => {
49+
// execCmd('force:source:retrieve --packagenames "my app, force-app" --json', { ensureExitCode: 0 });
50+
// });
5251

5352
it('retrieves via metadata', () => {
5453
execCmd('force:source:retrieve --metadata ApexClass --json', { ensureExitCode: 0 });
@@ -77,6 +76,6 @@ describe('source:retrieve NUTs', () => {
7776
});
7877

7978
after(async () => {
80-
// await session.clean();
79+
await session.clean();
8180
});
8281
});

test/commands/source/sourceCommand.test.ts

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,100 @@
55
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
77

8-
describe('sourceCommand tests', () => {});
8+
import { ComponentSet } from '@salesforce/source-deploy-retrieve';
9+
import { asArray, asString } from '@salesforce/ts-types';
10+
import { stubMethod } from '@salesforce/ts-sinon';
11+
import { expect, $$ } from '@salesforce/command/lib/test';
12+
import { fs } from '@salesforce/core';
13+
import { SinonStub } from 'sinon';
14+
import { FlagOptions, SourceCommand } from '../../../src/sourceCommand';
15+
16+
class sourceCommandTest extends SourceCommand {
17+
public async run() {}
18+
public async callCreateCopmonentSet(options: FlagOptions): Promise<ComponentSet> {
19+
return await this.createComponentSet(options);
20+
}
21+
}
22+
23+
describe('sourceCommand tests', () => {
24+
describe('createComponentSet tests', () => {
25+
const command = new sourceCommandTest([''], null);
26+
let fromSource: SinonStub;
27+
let fromManifest: SinonStub;
28+
29+
beforeEach(() => {
30+
stubMethod($$.SANDBOX, fs, 'fileExistsSync').returns(true);
31+
fromSource = stubMethod($$.SANDBOX, ComponentSet, 'fromSource').returns([
32+
{ name: 'MyTest', type: { id: 'apexclass', name: 'ApexClass' }, xml: '', parent: undefined, content: '' },
33+
]);
34+
fromManifest = stubMethod($$.SANDBOX, ComponentSet, 'fromManifestFile').resolves([
35+
{ name: 'MyTest', type: { id: 'apexclass', name: 'ApexClass' }, xml: '', parent: undefined, content: '' },
36+
]);
37+
});
38+
39+
it('will create appropriate ComponentSet from path', async () => {
40+
try {
41+
await command.callCreateCopmonentSet({
42+
sourcepath: asArray<string>(['force-app']),
43+
manifest: asString(''),
44+
metadata: asArray<string>([]),
45+
});
46+
} catch (e) {
47+
// we can't stub everything needed to create a ComponentSet, so expect the constructor to throw
48+
// but we'll spy on everything and make sure it looks correct
49+
// we need lots of NUTs
50+
}
51+
expect(fromSource.callCount).to.equal(1);
52+
});
53+
54+
it('will create appropriate ComponentSet from multiple paths', async () => {
55+
try {
56+
await command.callCreateCopmonentSet({
57+
sourcepath: asArray<string>(['force-app', 'my-app']),
58+
manifest: asString(''),
59+
metadata: asArray<string>([]),
60+
});
61+
} catch (e) {
62+
// we can't stub everything needed to create a ComponentSet, so expect the constructor to throw
63+
// but we'll spy on everything and make sure it looks correct
64+
// we need lots of NUTs
65+
}
66+
expect(fromSource.callCount).to.equal(2);
67+
});
68+
69+
it('will create appropriate ComponentSet from packagenames', async () => {
70+
// TODO: Flush out once we can retrieve via packagenames
71+
});
72+
73+
it('will create appropriate ComponentSet from multiple packagenames', async () => {
74+
// TODO: Flush out once we can retrieve via packagenames
75+
});
76+
77+
it('will create appropriate ComponentSet from metadata (ApexClass)', async () => {
78+
// not sure how to stub ComponentSet constructor
79+
});
80+
81+
it('will create appropriate ComponentSet from metadata (ApexClass:MyClass)', async () => {
82+
// not sure how to stub ComponentSet constructor
83+
});
84+
85+
it('will create appropriate ComponentSet from metadata (ApexClass:MyClass,CustomObject,CustomField:MyField', async () => {
86+
// not sure how to stub ComponentSet constructor
87+
});
88+
89+
it('will create appropriate ComponentSet from manifest', async () => {
90+
try {
91+
await command.callCreateCopmonentSet({
92+
sourcepath: asArray<string>([]),
93+
manifest: asString('manifest.xml'),
94+
metadata: asArray<string>(['']),
95+
});
96+
} catch (e) {
97+
// we can't stub everything needed to create a ComponentSet, so expect the constructor to throw
98+
// but we'll spy on everything and make sure it looks correct
99+
// we need lots of NUTs
100+
}
101+
expect(fromManifest.callCount).to.equal(1);
102+
});
103+
});
104+
});

0 commit comments

Comments
 (0)