Skip to content

Commit a180d5c

Browse files
committed
test(nx-plugin): add tests for buildCommandString
1 parent 4e90518 commit a180d5c

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

packages/nx-plugin/src/internal/execute-process.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ export function calcDuration(start: number, stop?: number): number {
77
return Math.round((stop ?? performance.now()) - start);
88
}
99

10-
function buildCommandString(command: string, args: string[] = []): string {
10+
export function buildCommandString(
11+
command: string,
12+
args: string[] = [],
13+
): string {
1114
if (args.length === 0) {
1215
return command;
1316
}
@@ -169,9 +172,6 @@ export function executeProcess(cfg: ProcessConfig): Promise<ProcessResult> {
169172
const date = new Date().toISOString();
170173
const start = performance.now();
171174

172-
// Build the complete command string
173-
const commandString = buildCommandString(command, args ?? []);
174-
175175
ui().logger.log(
176176
gray(
177177
`Executing command:\n${formatCommandLog({
@@ -193,6 +193,8 @@ export function executeProcess(cfg: ProcessConfig): Promise<ProcessResult> {
193193
}
194194

195195
return new Promise((resolve, reject) => {
196+
const commandString = buildCommandString(command, args ?? []);
197+
196198
const childProcess = exec(commandString, {
197199
cwd,
198200
env: env ? { ...process.env, ...env } : process.env,

packages/nx-plugin/src/internal/execute-process.unit.test.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { beforeEach, describe, expect, it, vi } from 'vitest';
22
import { getAsyncProcessRunnerConfig } from '@code-pushup/test-utils';
3-
import { type ProcessObserver, executeProcess } from './execute-process.js';
3+
import {
4+
type ProcessObserver,
5+
buildCommandString,
6+
executeProcess,
7+
} from './execute-process.js';
48

59
describe('executeProcess', () => {
610
const spyObserver: ProcessObserver = {
@@ -90,3 +94,43 @@ describe('executeProcess', () => {
9094
expect(spyObserver.onComplete).toHaveBeenCalledOnce();
9195
});
9296
});
97+
98+
describe('buildCommandString', () => {
99+
it('should return command when no args provided', () => {
100+
expect(buildCommandString('node')).toBe('node');
101+
});
102+
103+
it('should return command when empty args array provided', () => {
104+
expect(buildCommandString('node', [])).toBe('node');
105+
});
106+
107+
it('should return command with simple args', () => {
108+
expect(buildCommandString('npm', ['install', 'package'])).toBe(
109+
'npm install package',
110+
);
111+
});
112+
113+
it('should escape args with spaces', () => {
114+
expect(buildCommandString('echo', ['hello world'])).toBe(
115+
'echo "hello world"',
116+
);
117+
});
118+
119+
it('should escape args with double quotes for shell safety and cross-platform compatibility', () => {
120+
expect(buildCommandString('echo', ['say "hello"'])).toBe(
121+
'echo "say \\"hello\\""',
122+
);
123+
});
124+
125+
it('should escape args with single quotes for shell safety and cross-platform compatibility', () => {
126+
expect(buildCommandString('echo', ["it's working"])).toBe(
127+
'echo "it\'s working"',
128+
);
129+
});
130+
131+
it('should handle mixed escaped and non-escaped args', () => {
132+
expect(
133+
buildCommandString('node', ['script.js', 'hello world', '--flag']),
134+
).toBe('node script.js "hello world" --flag');
135+
});
136+
});

0 commit comments

Comments
 (0)