Skip to content

Commit 4f5c8ac

Browse files
test(codedapp-tool): add unit tests (#315)
- Add Vitest config with coverage support (@vitest/coverage-v8) - Add unit tests for tool, error-handler, resolve-credentials - Add unit tests for Commander command registration Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8af7d53 commit 4f5c8ac

7 files changed

Lines changed: 422 additions & 3 deletions

File tree

package-lock.json

Lines changed: 17 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/codedapp-tool/package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
"prepublishOnly": "npm run clean && npm run build:full",
1919
"dev": "bash scripts/dev.sh",
2020
"dev:link": "bash scripts/link-to-uipcli.sh",
21-
"clean": "rimraf dist"
21+
"clean": "rimraf dist",
22+
"test": "vitest run",
23+
"test:watch": "vitest",
24+
"test:coverage": "vitest run --coverage"
2225
},
2326
"dependencies": {
2427
"commander": "^14.0.3",
@@ -28,7 +31,9 @@
2831
"@uipath/uipath-ts-cli": "*",
2932
"@types/node": "^20.11.19",
3033
"rimraf": "^6.0.1",
31-
"typescript": "^5.3.3"
34+
"typescript": "^5.3.3",
35+
"@vitest/coverage-v8": "^3.2.4",
36+
"vitest": "^3.2.4"
3237
},
3338
"repository": {
3439
"type": "git",
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
import { Command } from 'commander';
3+
4+
vi.mock('@uipath/uipath-ts-cli/actions', () => ({
5+
executePush: vi.fn().mockResolvedValue(undefined),
6+
executePull: vi.fn().mockResolvedValue(undefined),
7+
executePack: vi.fn().mockResolvedValue(undefined),
8+
executePublish: vi.fn().mockResolvedValue(undefined),
9+
executeDeploy: vi.fn().mockResolvedValue(undefined),
10+
}));
11+
12+
vi.mock('@uipath/auth', () => ({
13+
getLoginStatusAsync: vi.fn().mockResolvedValue({ loginStatus: 'Not logged in' }),
14+
resolveEnvFilePathAsync: vi.fn(),
15+
saveEnvFileAsync: vi.fn(),
16+
}));
17+
18+
vi.mock('../../src/utils/folder-selection.js', () => ({
19+
ensureFolderKey: vi.fn().mockResolvedValue(undefined),
20+
}));
21+
22+
import { registerPushCommand } from '../../src/commands/push.js';
23+
import { registerPullCommand } from '../../src/commands/pull.js';
24+
import { registerPackCommand } from '../../src/commands/pack.js';
25+
import { registerPublishCommand } from '../../src/commands/publish.js';
26+
import { registerDeployCommand } from '../../src/commands/deploy.js';
27+
28+
describe('Command Registration', () => {
29+
describe('push command', () => {
30+
it('should register push command on program', () => {
31+
const program = new Command();
32+
registerPushCommand(program);
33+
34+
const pushCmd = program.commands.find((c) => c.name() === 'push');
35+
expect(pushCmd).toBeDefined();
36+
expect(pushCmd!.description()).toContain('Push');
37+
});
38+
39+
it('should have correct options', () => {
40+
const program = new Command();
41+
registerPushCommand(program);
42+
43+
const pushCmd = program.commands.find((c) => c.name() === 'push')!;
44+
const optionNames = pushCmd.options.map((o) => o.long);
45+
expect(optionNames).toContain('--buildDir');
46+
expect(optionNames).toContain('--ignoreResources');
47+
expect(optionNames).toContain('--baseUrl');
48+
expect(optionNames).toContain('--orgId');
49+
expect(optionNames).toContain('--tenantId');
50+
expect(optionNames).toContain('--accessToken');
51+
});
52+
});
53+
54+
describe('pull command', () => {
55+
it('should register pull command on program', () => {
56+
const program = new Command();
57+
registerPullCommand(program);
58+
59+
const pullCmd = program.commands.find((c) => c.name() === 'pull');
60+
expect(pullCmd).toBeDefined();
61+
expect(pullCmd!.description()).toContain('Pull');
62+
});
63+
64+
it('should have overwrite option', () => {
65+
const program = new Command();
66+
registerPullCommand(program);
67+
68+
const pullCmd = program.commands.find((c) => c.name() === 'pull')!;
69+
const optionNames = pullCmd.options.map((o) => o.long);
70+
expect(optionNames).toContain('--overwrite');
71+
expect(optionNames).toContain('--targetDir');
72+
});
73+
});
74+
75+
describe('pack command', () => {
76+
it('should register pack command on program', () => {
77+
const program = new Command();
78+
registerPackCommand(program);
79+
80+
const packCmd = program.commands.find((c) => c.name() === 'pack');
81+
expect(packCmd).toBeDefined();
82+
expect(packCmd!.description()).toContain('Package');
83+
});
84+
85+
it('should require dist argument', () => {
86+
const program = new Command();
87+
registerPackCommand(program);
88+
89+
const packCmd = program.commands.find((c) => c.name() === 'pack')!;
90+
const args = packCmd.registeredArguments;
91+
expect(args.length).toBeGreaterThan(0);
92+
expect(args[0].required).toBe(true);
93+
});
94+
95+
it('should have packaging options', () => {
96+
const program = new Command();
97+
registerPackCommand(program);
98+
99+
const packCmd = program.commands.find((c) => c.name() === 'pack')!;
100+
const optionNames = packCmd.options.map((o) => o.long);
101+
expect(optionNames).toContain('--name');
102+
expect(optionNames).toContain('--version');
103+
expect(optionNames).toContain('--output');
104+
expect(optionNames).toContain('--dry-run');
105+
});
106+
});
107+
108+
describe('publish command', () => {
109+
it('should register publish command on program', () => {
110+
const program = new Command();
111+
registerPublishCommand(program);
112+
113+
const publishCmd = program.commands.find((c) => c.name() === 'publish');
114+
expect(publishCmd).toBeDefined();
115+
expect(publishCmd!.description()).toContain('Publish');
116+
});
117+
118+
it('should have publish options', () => {
119+
const program = new Command();
120+
registerPublishCommand(program);
121+
122+
const publishCmd = program.commands.find((c) => c.name() === 'publish')!;
123+
const optionNames = publishCmd.options.map((o) => o.long);
124+
expect(optionNames).toContain('--name');
125+
expect(optionNames).toContain('--version');
126+
expect(optionNames).toContain('--type');
127+
expect(optionNames).toContain('--uipathDir');
128+
});
129+
});
130+
131+
describe('deploy command', () => {
132+
it('should register deploy command on program', () => {
133+
const program = new Command();
134+
registerDeployCommand(program);
135+
136+
const deployCmd = program.commands.find((c) => c.name() === 'deploy');
137+
expect(deployCmd).toBeDefined();
138+
expect(deployCmd!.description()).toContain('Deploy');
139+
});
140+
141+
it('should have deploy options', () => {
142+
const program = new Command();
143+
registerDeployCommand(program);
144+
145+
const deployCmd = program.commands.find((c) => c.name() === 'deploy')!;
146+
const optionNames = deployCmd.options.map((o) => o.long);
147+
expect(optionNames).toContain('--name');
148+
expect(optionNames).toContain('--folderKey');
149+
expect(optionNames).toContain('--orgName');
150+
});
151+
});
152+
});
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { describe, it, expect, vi, beforeEach } from 'vitest';
2+
import { Command } from 'commander';
3+
4+
vi.mock('../../src/utils/resolve-credentials.js', () => ({
5+
loadAuthCredentials: vi.fn().mockResolvedValue(undefined),
6+
}));
7+
8+
vi.mock('../../src/commands/push.js', () => ({
9+
registerPushCommand: vi.fn(),
10+
}));
11+
vi.mock('../../src/commands/pull.js', () => ({
12+
registerPullCommand: vi.fn(),
13+
}));
14+
vi.mock('../../src/commands/pack.js', () => ({
15+
registerPackCommand: vi.fn(),
16+
}));
17+
vi.mock('../../src/commands/publish.js', () => ({
18+
registerPublishCommand: vi.fn(),
19+
}));
20+
vi.mock('../../src/commands/deploy.js', () => ({
21+
registerDeployCommand: vi.fn(),
22+
}));
23+
24+
import { metadata, registerCommands } from '../../src/tool.js';
25+
import { registerPushCommand } from '../../src/commands/push.js';
26+
import { registerPullCommand } from '../../src/commands/pull.js';
27+
import { registerPackCommand } from '../../src/commands/pack.js';
28+
import { registerPublishCommand } from '../../src/commands/publish.js';
29+
import { registerDeployCommand } from '../../src/commands/deploy.js';
30+
31+
describe('codedapp-tool', () => {
32+
describe('metadata', () => {
33+
it('should export correct tool name', () => {
34+
expect(metadata.name).toBe('codedapp-tool');
35+
});
36+
37+
it('should have codedapp command prefix', () => {
38+
expect(metadata.commandPrefix).toBe('codedapp');
39+
});
40+
41+
it('should have a version', () => {
42+
expect(metadata.version).toBeDefined();
43+
expect(typeof metadata.version).toBe('string');
44+
});
45+
46+
it('should have a description', () => {
47+
expect(metadata.description).toBeDefined();
48+
});
49+
});
50+
51+
describe('registerCommands', () => {
52+
let program: Command;
53+
54+
beforeEach(() => {
55+
vi.clearAllMocks();
56+
program = new Command();
57+
});
58+
59+
it('should register all 5 commands', () => {
60+
registerCommands(program);
61+
62+
expect(registerPushCommand).toHaveBeenCalledWith(program);
63+
expect(registerPullCommand).toHaveBeenCalledWith(program);
64+
expect(registerPackCommand).toHaveBeenCalledWith(program);
65+
expect(registerPublishCommand).toHaveBeenCalledWith(program);
66+
expect(registerDeployCommand).toHaveBeenCalledWith(program);
67+
});
68+
69+
it('should add a preAction hook', () => {
70+
const hookSpy = vi.spyOn(program, 'hook');
71+
registerCommands(program);
72+
73+
expect(hookSpy).toHaveBeenCalledWith('preAction', expect.any(Function));
74+
});
75+
});
76+
});

0 commit comments

Comments
 (0)