@zjex/git-workflow 0.4.5 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +135 -364
- package/README.md +1 -1
- package/dist/index.js +129 -30
- package/docs/.vitepress/config.ts +2 -0
- package/docs/guide/command-quotes-handling.md +279 -0
- package/docs/guide/debug-mode.md +384 -0
- package/package.json +1 -1
- package/scripts/generate-changelog-manual.js +15 -64
- package/src/commands/tag.ts +42 -10
- package/src/commands/update.ts +25 -9
- package/src/index.ts +11 -3
- package/src/utils.ts +93 -10
- package/tests/command-with-quotes.test.ts +378 -0
- package/tests/debug-mode.test.ts +503 -0
- package/tests/update.test.ts +85 -69
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import type { Ora } from "ora";
|
|
3
|
+
|
|
4
|
+
describe("Debug 模式测试", () => {
|
|
5
|
+
let consoleLogSpy: any;
|
|
6
|
+
let utils: any;
|
|
7
|
+
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
vi.clearAllMocks();
|
|
10
|
+
consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
11
|
+
// 每次测试前重新导入模块
|
|
12
|
+
vi.resetModules();
|
|
13
|
+
utils = await import("../src/utils.js");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
vi.restoreAllMocks();
|
|
18
|
+
consoleLogSpy.mockRestore();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("setDebugMode 函数", () => {
|
|
22
|
+
it("应该正确设置 debug 模式", () => {
|
|
23
|
+
const { setDebugMode } = utils;
|
|
24
|
+
|
|
25
|
+
// 应该能正常调用,不抛出错误
|
|
26
|
+
expect(() => setDebugMode(true)).not.toThrow();
|
|
27
|
+
expect(() => setDebugMode(false)).not.toThrow();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("应该支持多次切换 debug 模式", () => {
|
|
31
|
+
const { setDebugMode } = utils;
|
|
32
|
+
|
|
33
|
+
for (let i = 0; i < 5; i++) {
|
|
34
|
+
expect(() => setDebugMode(true)).not.toThrow();
|
|
35
|
+
expect(() => setDebugMode(false)).not.toThrow();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("应该正确处理布尔值参数", () => {
|
|
40
|
+
const { setDebugMode } = utils;
|
|
41
|
+
|
|
42
|
+
expect(() => setDebugMode(true)).not.toThrow();
|
|
43
|
+
expect(() => setDebugMode(false)).not.toThrow();
|
|
44
|
+
|
|
45
|
+
// 测试重复设置相同值
|
|
46
|
+
expect(() => {
|
|
47
|
+
setDebugMode(true);
|
|
48
|
+
setDebugMode(true);
|
|
49
|
+
}).not.toThrow();
|
|
50
|
+
|
|
51
|
+
expect(() => {
|
|
52
|
+
setDebugMode(false);
|
|
53
|
+
setDebugMode(false);
|
|
54
|
+
}).not.toThrow();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("execAsync 函数 - 基本功能", () => {
|
|
59
|
+
it("应该返回成功结果", async () => {
|
|
60
|
+
const { execAsync, setDebugMode } = utils;
|
|
61
|
+
setDebugMode(false);
|
|
62
|
+
|
|
63
|
+
// 使用真实的命令测试
|
|
64
|
+
const result = await execAsync("echo test");
|
|
65
|
+
|
|
66
|
+
expect(result).toHaveProperty("success");
|
|
67
|
+
expect(typeof result.success).toBe("boolean");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("应该返回错误信息", async () => {
|
|
71
|
+
const { execAsync, setDebugMode } = utils;
|
|
72
|
+
setDebugMode(false);
|
|
73
|
+
|
|
74
|
+
// 使用一个会失败的命令
|
|
75
|
+
const result = await execAsync("exit 1");
|
|
76
|
+
|
|
77
|
+
expect(result).toHaveProperty("success");
|
|
78
|
+
expect(result).toHaveProperty("error");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("应该使用 shell 模式执行命令", async () => {
|
|
82
|
+
const { execAsync, setDebugMode } = utils;
|
|
83
|
+
setDebugMode(false);
|
|
84
|
+
|
|
85
|
+
// 测试 shell 特性(管道)
|
|
86
|
+
const result = await execAsync("echo hello | cat");
|
|
87
|
+
|
|
88
|
+
expect(result.success).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe("execAsync 函数 - Debug 模式", () => {
|
|
93
|
+
it("应该在 debug 模式下输出命令信息", async () => {
|
|
94
|
+
const { execAsync, setDebugMode } = utils;
|
|
95
|
+
setDebugMode(true);
|
|
96
|
+
|
|
97
|
+
await execAsync("echo test");
|
|
98
|
+
|
|
99
|
+
// 验证显示了 debug 信息
|
|
100
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
101
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
102
|
+
const debugCalls = calls.filter(
|
|
103
|
+
(call: string) => typeof call === "string" && call.includes("[DEBUG]"),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(debugCalls.length).toBeGreaterThan(0);
|
|
107
|
+
|
|
108
|
+
setDebugMode(false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("应该在 debug 模式下显示退出码", async () => {
|
|
112
|
+
const { execAsync, setDebugMode } = utils;
|
|
113
|
+
setDebugMode(true);
|
|
114
|
+
|
|
115
|
+
await execAsync("echo test");
|
|
116
|
+
|
|
117
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
118
|
+
const hasExitCode = calls.some(
|
|
119
|
+
(call: string) =>
|
|
120
|
+
typeof call === "string" && call.includes("[DEBUG] 退出码:"),
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
expect(hasExitCode).toBe(true);
|
|
124
|
+
|
|
125
|
+
setDebugMode(false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("应该在非 debug 模式下不输出额外信息", async () => {
|
|
129
|
+
const { execAsync, setDebugMode } = utils;
|
|
130
|
+
setDebugMode(false);
|
|
131
|
+
|
|
132
|
+
consoleLogSpy.mockClear();
|
|
133
|
+
await execAsync("echo test");
|
|
134
|
+
|
|
135
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
136
|
+
const debugCalls = calls.filter(
|
|
137
|
+
(call: string) => typeof call === "string" && call.includes("[DEBUG]"),
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
expect(debugCalls.length).toBe(0);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("execWithSpinner 函数 - 基本功能", () => {
|
|
145
|
+
it("应该在成功时调用 spinner.succeed", async () => {
|
|
146
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
147
|
+
setDebugMode(false);
|
|
148
|
+
|
|
149
|
+
const mockSpinner = {
|
|
150
|
+
succeed: vi.fn(),
|
|
151
|
+
fail: vi.fn(),
|
|
152
|
+
} as unknown as Ora;
|
|
153
|
+
|
|
154
|
+
const result = await execWithSpinner(
|
|
155
|
+
"echo test",
|
|
156
|
+
mockSpinner,
|
|
157
|
+
"成功消息",
|
|
158
|
+
"失败消息",
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
expect(result).toBe(true);
|
|
162
|
+
expect(mockSpinner.succeed).toHaveBeenCalledWith("成功消息");
|
|
163
|
+
expect(mockSpinner.fail).not.toHaveBeenCalled();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("应该在失败时调用 spinner.fail", async () => {
|
|
167
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
168
|
+
setDebugMode(false);
|
|
169
|
+
|
|
170
|
+
const mockSpinner = {
|
|
171
|
+
succeed: vi.fn(),
|
|
172
|
+
fail: vi.fn(),
|
|
173
|
+
} as unknown as Ora;
|
|
174
|
+
|
|
175
|
+
const result = await execWithSpinner(
|
|
176
|
+
"exit 1",
|
|
177
|
+
mockSpinner,
|
|
178
|
+
"成功消息",
|
|
179
|
+
"失败消息",
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
expect(result).toBe(false);
|
|
183
|
+
expect(mockSpinner.fail).toHaveBeenCalledWith("失败消息");
|
|
184
|
+
expect(mockSpinner.succeed).not.toHaveBeenCalled();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("应该在失败时显示错误信息", async () => {
|
|
188
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
189
|
+
setDebugMode(false);
|
|
190
|
+
|
|
191
|
+
const mockSpinner = {
|
|
192
|
+
succeed: vi.fn(),
|
|
193
|
+
fail: vi.fn(),
|
|
194
|
+
} as unknown as Ora;
|
|
195
|
+
|
|
196
|
+
consoleLogSpy.mockClear();
|
|
197
|
+
await execWithSpinner(
|
|
198
|
+
"node -e 'console.error(\"test error\"); process.exit(1)'",
|
|
199
|
+
mockSpinner,
|
|
200
|
+
"成功",
|
|
201
|
+
"失败",
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
// 应该显示错误信息
|
|
205
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("应该支持没有消息的情况", async () => {
|
|
209
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
210
|
+
setDebugMode(false);
|
|
211
|
+
|
|
212
|
+
const mockSpinner = {
|
|
213
|
+
succeed: vi.fn(),
|
|
214
|
+
fail: vi.fn(),
|
|
215
|
+
} as unknown as Ora;
|
|
216
|
+
|
|
217
|
+
await execWithSpinner("echo test", mockSpinner);
|
|
218
|
+
|
|
219
|
+
expect(mockSpinner.succeed).toHaveBeenCalledWith();
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe("execWithSpinner 函数 - Debug 模式", () => {
|
|
224
|
+
it("应该在 debug 模式下显示故障排查信息", async () => {
|
|
225
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
226
|
+
setDebugMode(true);
|
|
227
|
+
|
|
228
|
+
const mockSpinner = {
|
|
229
|
+
succeed: vi.fn(),
|
|
230
|
+
fail: vi.fn(),
|
|
231
|
+
} as unknown as Ora;
|
|
232
|
+
|
|
233
|
+
consoleLogSpy.mockClear();
|
|
234
|
+
await execWithSpinner("exit 1", mockSpinner, "成功", "失败");
|
|
235
|
+
|
|
236
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
237
|
+
const hasTroubleshooting = calls.some(
|
|
238
|
+
(call: string) =>
|
|
239
|
+
typeof call === "string" && call.includes("[DEBUG] 故障排查信息:"),
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
expect(hasTroubleshooting).toBe(true);
|
|
243
|
+
|
|
244
|
+
setDebugMode(false);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("应该在 debug 模式下显示工作目录", async () => {
|
|
248
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
249
|
+
setDebugMode(true);
|
|
250
|
+
|
|
251
|
+
const mockSpinner = {
|
|
252
|
+
succeed: vi.fn(),
|
|
253
|
+
fail: vi.fn(),
|
|
254
|
+
} as unknown as Ora;
|
|
255
|
+
|
|
256
|
+
consoleLogSpy.mockClear();
|
|
257
|
+
await execWithSpinner("exit 1", mockSpinner, "成功", "失败");
|
|
258
|
+
|
|
259
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
260
|
+
const hasWorkDir = calls.some(
|
|
261
|
+
(call: string) =>
|
|
262
|
+
typeof call === "string" && call.includes("工作目录:"),
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
expect(hasWorkDir).toBe(true);
|
|
266
|
+
|
|
267
|
+
setDebugMode(false);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("应该在 debug 模式下显示 Shell 信息", async () => {
|
|
271
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
272
|
+
setDebugMode(true);
|
|
273
|
+
|
|
274
|
+
const mockSpinner = {
|
|
275
|
+
succeed: vi.fn(),
|
|
276
|
+
fail: vi.fn(),
|
|
277
|
+
} as unknown as Ora;
|
|
278
|
+
|
|
279
|
+
consoleLogSpy.mockClear();
|
|
280
|
+
await execWithSpinner("exit 1", mockSpinner, "成功", "失败");
|
|
281
|
+
|
|
282
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
283
|
+
const hasShell = calls.some(
|
|
284
|
+
(call: string) => typeof call === "string" && call.includes("Shell:"),
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
expect(hasShell).toBe(true);
|
|
288
|
+
|
|
289
|
+
setDebugMode(false);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("应该在成功时不显示故障排查信息", async () => {
|
|
293
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
294
|
+
setDebugMode(true);
|
|
295
|
+
|
|
296
|
+
const mockSpinner = {
|
|
297
|
+
succeed: vi.fn(),
|
|
298
|
+
fail: vi.fn(),
|
|
299
|
+
} as unknown as Ora;
|
|
300
|
+
|
|
301
|
+
consoleLogSpy.mockClear();
|
|
302
|
+
await execWithSpinner("echo test", mockSpinner, "成功", "失败");
|
|
303
|
+
|
|
304
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
305
|
+
const hasTroubleshooting = calls.some(
|
|
306
|
+
(call: string) =>
|
|
307
|
+
typeof call === "string" && call.includes("[DEBUG] 故障排查信息:"),
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
expect(hasTroubleshooting).toBe(false);
|
|
311
|
+
|
|
312
|
+
setDebugMode(false);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it("应该在非 debug 模式下不显示故障排查信息", async () => {
|
|
316
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
317
|
+
setDebugMode(false);
|
|
318
|
+
|
|
319
|
+
const mockSpinner = {
|
|
320
|
+
succeed: vi.fn(),
|
|
321
|
+
fail: vi.fn(),
|
|
322
|
+
} as unknown as Ora;
|
|
323
|
+
|
|
324
|
+
consoleLogSpy.mockClear();
|
|
325
|
+
await execWithSpinner("exit 1", mockSpinner, "成功", "失败");
|
|
326
|
+
|
|
327
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
328
|
+
const hasTroubleshooting = calls.some(
|
|
329
|
+
(call: string) =>
|
|
330
|
+
typeof call === "string" && call.includes("[DEBUG] 故障排查信息:"),
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
expect(hasTroubleshooting).toBe(false);
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
describe("边界情况和特殊场景", () => {
|
|
338
|
+
it("应该正确处理包含引号的命令", async () => {
|
|
339
|
+
const { execAsync, setDebugMode } = utils;
|
|
340
|
+
setDebugMode(true);
|
|
341
|
+
|
|
342
|
+
consoleLogSpy.mockClear();
|
|
343
|
+
await execAsync('echo "hello world"');
|
|
344
|
+
|
|
345
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
346
|
+
const hasCommand = calls.some(
|
|
347
|
+
(call: string) =>
|
|
348
|
+
typeof call === "string" && call.includes('echo "hello world"'),
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
expect(hasCommand).toBe(true);
|
|
352
|
+
|
|
353
|
+
setDebugMode(false);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it("应该正确处理包含特殊字符的命令", async () => {
|
|
357
|
+
const { execAsync, setDebugMode } = utils;
|
|
358
|
+
setDebugMode(true);
|
|
359
|
+
|
|
360
|
+
const specialCommand = 'echo "test: 测试 🎉"';
|
|
361
|
+
|
|
362
|
+
consoleLogSpy.mockClear();
|
|
363
|
+
await execAsync(specialCommand);
|
|
364
|
+
|
|
365
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
366
|
+
const hasCommand = calls.some(
|
|
367
|
+
(call: string) =>
|
|
368
|
+
typeof call === "string" && call.includes(specialCommand),
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
expect(hasCommand).toBe(true);
|
|
372
|
+
|
|
373
|
+
setDebugMode(false);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("应该正确处理空命令", async () => {
|
|
377
|
+
const { execAsync, setDebugMode } = utils;
|
|
378
|
+
setDebugMode(true);
|
|
379
|
+
|
|
380
|
+
consoleLogSpy.mockClear();
|
|
381
|
+
|
|
382
|
+
// 空命令会抛出错误,这是预期的行为
|
|
383
|
+
try {
|
|
384
|
+
await execAsync("");
|
|
385
|
+
} catch (error) {
|
|
386
|
+
expect(error).toBeDefined();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
setDebugMode(false);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("应该正确处理长命令", async () => {
|
|
393
|
+
const { execAsync, setDebugMode } = utils;
|
|
394
|
+
setDebugMode(true);
|
|
395
|
+
|
|
396
|
+
const longCommand = "echo " + "x".repeat(1000);
|
|
397
|
+
|
|
398
|
+
consoleLogSpy.mockClear();
|
|
399
|
+
await execAsync(longCommand);
|
|
400
|
+
|
|
401
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
402
|
+
const hasDebug = calls.some(
|
|
403
|
+
(call: string) => typeof call === "string" && call.includes("[DEBUG]"),
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
expect(hasDebug).toBe(true);
|
|
407
|
+
|
|
408
|
+
setDebugMode(false);
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
describe("性能和资源管理", () => {
|
|
413
|
+
it("应该不会因为 debug 模式导致内存泄漏", () => {
|
|
414
|
+
const { setDebugMode } = utils;
|
|
415
|
+
|
|
416
|
+
// 多次切换 debug 模式
|
|
417
|
+
for (let i = 0; i < 100; i++) {
|
|
418
|
+
setDebugMode(true);
|
|
419
|
+
setDebugMode(false);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// 如果没有内存泄漏,这个测试应该能正常完成
|
|
423
|
+
expect(true).toBe(true);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it("应该能处理并发的命令执行", async () => {
|
|
427
|
+
const { execAsync, setDebugMode } = utils;
|
|
428
|
+
setDebugMode(true);
|
|
429
|
+
|
|
430
|
+
// 并发执行多个命令
|
|
431
|
+
const promises = [
|
|
432
|
+
execAsync("echo test1"),
|
|
433
|
+
execAsync("echo test2"),
|
|
434
|
+
execAsync("echo test3"),
|
|
435
|
+
];
|
|
436
|
+
|
|
437
|
+
const results = await Promise.all(promises);
|
|
438
|
+
|
|
439
|
+
expect(results).toHaveLength(3);
|
|
440
|
+
results.forEach((result) => {
|
|
441
|
+
expect(result).toHaveProperty("success");
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
setDebugMode(false);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it("应该正确处理快速连续的命令", async () => {
|
|
448
|
+
const { execAsync, setDebugMode } = utils;
|
|
449
|
+
setDebugMode(true);
|
|
450
|
+
|
|
451
|
+
// 快速连续执行命令
|
|
452
|
+
for (let i = 0; i < 5; i++) {
|
|
453
|
+
const result = await execAsync(`echo test${i}`);
|
|
454
|
+
expect(result.success).toBe(true);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
setDebugMode(false);
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
describe("集成测试 - 实际命令场景", () => {
|
|
462
|
+
it("应该正确处理 Git 命令", async () => {
|
|
463
|
+
const { execAsync, setDebugMode } = utils;
|
|
464
|
+
setDebugMode(true);
|
|
465
|
+
|
|
466
|
+
consoleLogSpy.mockClear();
|
|
467
|
+
await execAsync("git --version");
|
|
468
|
+
|
|
469
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
470
|
+
const hasGitCommand = calls.some(
|
|
471
|
+
(call: string) =>
|
|
472
|
+
typeof call === "string" && call.includes("git --version"),
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
expect(hasGitCommand).toBe(true);
|
|
476
|
+
|
|
477
|
+
setDebugMode(false);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
it("应该正确处理带参数的命令", async () => {
|
|
481
|
+
const { execWithSpinner, setDebugMode } = utils;
|
|
482
|
+
setDebugMode(true);
|
|
483
|
+
|
|
484
|
+
const mockSpinner = {
|
|
485
|
+
succeed: vi.fn(),
|
|
486
|
+
fail: vi.fn(),
|
|
487
|
+
} as unknown as Ora;
|
|
488
|
+
|
|
489
|
+
consoleLogSpy.mockClear();
|
|
490
|
+
await execWithSpinner('echo "test message"', mockSpinner, "成功", "失败");
|
|
491
|
+
|
|
492
|
+
const calls = consoleLogSpy.mock.calls.map((call: any) => call[0]);
|
|
493
|
+
const hasCommand = calls.some(
|
|
494
|
+
(call: string) =>
|
|
495
|
+
typeof call === "string" && call.includes('echo "test message"'),
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
expect(hasCommand).toBe(true);
|
|
499
|
+
|
|
500
|
+
setDebugMode(false);
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
});
|