Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extensions/vscode/src/extension/services/CliService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class CliService {

private probeCommand(bin: string, args: string[]): Promise<{ ok: boolean; version?: string }> {
return new Promise((resolve) => {
const proc = spawn(resolveBin(bin), args, { env: getShellEnv() });
const proc = spawn(resolveBin(bin), args, { env: getShellEnv(), shell: process.platform === 'win32' });
let stdout = '';
let errored = false;
proc.stdout?.on('data', (d) => { stdout += d.toString(); });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// src/extension/services/__tests__/CliService.test.ts
process.env.OCR_SKIP_SHELL_RESOLVE = '1';
import { CliService } from '../CliService';
import { spawn } from 'child_process';

jest.mock('child_process');

describe('CliService.isAvailable', () => {
it('node 一定存在 → true', async () => {
Expand All @@ -13,6 +16,57 @@ describe('CliService.isAvailable', () => {
});
});

describe('CliService probe shell option', () => {
const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');

afterEach(() => {
jest.resetAllMocks();
if (originalPlatform) {
Object.defineProperty(process, 'platform', originalPlatform);
}
});

it('Windows 上 probeCommand 应传入 shell: true', async () => {
Object.defineProperty(process, 'platform', { value: 'win32' });
const mockProc = {
stdout: { on: jest.fn() },
on: jest.fn((event: string, cb: Function) => {
if (event === 'close') cb(0);
}),
};
(spawn as jest.Mock).mockReturnValue(mockProc);

const svc = new CliService('node');
await (svc as any).probeCommand('npm', ['--version']);

expect(spawn).toHaveBeenCalledWith(
'npm',
['--version'],
expect.objectContaining({ shell: true }),
);
});

it('非 Windows 上 probeCommand 不应传入 shell', async () => {
Object.defineProperty(process, 'platform', { value: 'linux' });
const mockProc = {
stdout: { on: jest.fn() },
on: jest.fn((event: string, cb: Function) => {
if (event === 'close') cb(0);
}),
};
(spawn as jest.Mock).mockReturnValue(mockProc);

const svc = new CliService('node');
await (svc as any).probeCommand('npm', ['--version']);

expect(spawn).toHaveBeenCalledWith(
'npm',
['--version'],
expect.not.objectContaining({ shell: true }),
);
});
});

describe('CliService.runRaw', () => {
it('收集 stdout 并在结束时 resolve', async () => {
// 用 node 打印一段 JSON 模拟 ocr
Expand Down