Files
qwen-code/packages/core/src/ide/ide-installer.test.ts
2025-11-04 15:53:03 +08:00

179 lines
5.2 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { vi } from 'vitest';
vi.mock('node:child_process', async (importOriginal) => {
const actual =
(await importOriginal()) as typeof import('node:child_process');
return {
...actual,
execSync: vi.fn(),
spawnSync: vi.fn(() => ({ status: 0 })),
};
});
vi.mock('fs');
vi.mock('os');
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { getIdeInstaller } from './ide-installer.js';
import * as child_process from 'node:child_process';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { IDE_DEFINITIONS, type IdeInfo } from './detect-ide.js';
describe('ide-installer', () => {
const HOME_DIR = '/home/user';
beforeEach(() => {
vi.spyOn(os, 'homedir').mockReturnValue(HOME_DIR);
});
afterEach(() => {
vi.restoreAllMocks();
});
describe('getIdeInstaller', () => {
it.each([
{ ide: IDE_DEFINITIONS.vscode },
{ ide: IDE_DEFINITIONS.firebasestudio },
])('returns a VsCodeInstaller for "$ide.name"', ({ ide }) => {
const installer = getIdeInstaller(ide);
expect(installer).not.toBeNull();
expect(installer?.install).toEqual(expect.any(Function));
});
});
describe('VsCodeInstaller', () => {
function setup({
ide = IDE_DEFINITIONS.vscode,
existsResult = false,
execSync = () => '',
platform = 'linux' as NodeJS.Platform,
}: {
ide?: IdeInfo;
existsResult?: boolean;
execSync?: () => string;
platform?: NodeJS.Platform;
} = {}) {
vi.spyOn(child_process, 'execSync').mockImplementation(execSync);
vi.spyOn(fs, 'existsSync').mockReturnValue(existsResult);
const installer = getIdeInstaller(ide, platform)!;
return { installer };
}
describe('install', () => {
it.each([
{
platform: 'win32' as NodeJS.Platform,
expectedLookupPaths: [
path.join('C:\\Program Files', 'Microsoft VS Code/bin/code.cmd'),
path.join(
HOME_DIR,
'/AppData/Local/Programs/Microsoft VS Code/bin/code.cmd',
),
],
},
{
platform: 'darwin' as NodeJS.Platform,
expectedLookupPaths: [
'/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code',
path.join(HOME_DIR, 'Library/Application Support/Code/bin/code'),
],
},
{
platform: 'linux' as NodeJS.Platform,
expectedLookupPaths: ['/usr/share/code/bin/code'],
},
])(
'identifies the path to code cli on platform: $platform',
async ({ platform, expectedLookupPaths }) => {
const { installer } = setup({
platform,
execSync: () => {
throw new Error('Command not found'); // `code` is not in PATH
},
});
await installer.install();
for (const [idx, path] of expectedLookupPaths.entries()) {
expect(fs.existsSync).toHaveBeenNthCalledWith(idx + 1, path);
}
},
);
it('installs the extension using code cli', async () => {
const { installer } = setup({
platform: 'linux',
});
await installer.install();
// Note: The implementation uses process.platform, not the mocked platform
const isActuallyWindows = process.platform === 'win32';
const expectedCommand = isActuallyWindows ? '"code"' : 'code';
expect(child_process.spawnSync).toHaveBeenCalledWith(
expectedCommand,
[
'--install-extension',
'qwenlm.qwen-code-vscode-ide-companion',
'--force',
],
{ stdio: 'pipe', shell: isActuallyWindows },
);
});
it.each([
{
ide: IDE_DEFINITIONS.vscode,
expectedMessage:
'VS Code companion extension was installed successfully',
},
{
ide: IDE_DEFINITIONS.firebasestudio,
expectedMessage:
'Firebase Studio companion extension was installed successfully',
},
])(
'returns that the cli was installed successfully',
async ({ ide, expectedMessage }) => {
const { installer } = setup({ ide });
const result = await installer.install();
expect(result.success).toBe(true);
expect(result.message).toContain(expectedMessage);
},
);
it.each([
{
ide: IDE_DEFINITIONS.vscode,
expectedErr: 'VS Code CLI not found',
},
{
ide: IDE_DEFINITIONS.firebasestudio,
expectedErr: 'Firebase Studio CLI not found',
},
])(
'should return a failure message if $ide is not installed',
async ({ ide, expectedErr }) => {
const { installer } = setup({
ide,
execSync: () => {
throw new Error('Command not found');
},
existsResult: false,
});
const result = await installer.install();
expect(result.success).toBe(false);
expect(result.message).toContain(expectedErr);
},
);
});
});
});