mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-01 21:20:44 +00:00
191 lines
5.3 KiB
TypeScript
191 lines
5.3 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import {
|
|
describe,
|
|
it,
|
|
expect,
|
|
vi,
|
|
beforeEach,
|
|
afterEach,
|
|
type MockInstance,
|
|
} from 'vitest';
|
|
import { handleInstall, installCommand } from './install.js';
|
|
import yargs from 'yargs';
|
|
|
|
const mockInstallExtension = vi.hoisted(() => vi.fn());
|
|
const mockRefreshCache = vi.hoisted(() => vi.fn());
|
|
const mockParseInstallSource = vi.hoisted(() => vi.fn());
|
|
const mockRequestConsentNonInteractive = vi.hoisted(() => vi.fn());
|
|
const mockRequestConsentOrFail = vi.hoisted(() => vi.fn());
|
|
const mockIsWorkspaceTrusted = vi.hoisted(() => vi.fn());
|
|
const mockLoadSettings = vi.hoisted(() => vi.fn());
|
|
|
|
vi.mock('@qwen-code/qwen-code-core', () => ({
|
|
ExtensionManager: vi.fn().mockImplementation(() => ({
|
|
installExtension: mockInstallExtension,
|
|
refreshCache: mockRefreshCache,
|
|
})),
|
|
parseInstallSource: mockParseInstallSource,
|
|
}));
|
|
|
|
vi.mock('./consent.js', () => ({
|
|
requestConsentNonInteractive: mockRequestConsentNonInteractive,
|
|
requestConsentOrFail: mockRequestConsentOrFail,
|
|
requestChoicePluginNonInteractive: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('../../config/trustedFolders.js', () => ({
|
|
isWorkspaceTrusted: mockIsWorkspaceTrusted,
|
|
}));
|
|
|
|
vi.mock('../../config/settings.js', () => ({
|
|
loadSettings: mockLoadSettings,
|
|
}));
|
|
|
|
vi.mock('../../utils/errors.js', () => ({
|
|
getErrorMessage: vi.fn((error: Error) => error.message),
|
|
}));
|
|
|
|
describe('extensions install command', () => {
|
|
it('should fail if no source is provided', () => {
|
|
const validationParser = yargs([])
|
|
.locale('en')
|
|
.command(installCommand)
|
|
.fail(false);
|
|
expect(() => validationParser.parse('install')).toThrow(
|
|
'Not enough non-option arguments: got 0, need at least 1',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('handleInstall', () => {
|
|
let consoleLogSpy: MockInstance;
|
|
let consoleErrorSpy: MockInstance;
|
|
let processSpy: MockInstance;
|
|
|
|
beforeEach(() => {
|
|
consoleLogSpy = vi.spyOn(console, 'log');
|
|
consoleErrorSpy = vi.spyOn(console, 'error');
|
|
processSpy = vi
|
|
.spyOn(process, 'exit')
|
|
.mockImplementation(() => undefined as never);
|
|
mockRefreshCache.mockResolvedValue(undefined);
|
|
mockLoadSettings.mockReturnValue({ merged: {} });
|
|
mockIsWorkspaceTrusted.mockReturnValue(true);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('should install an extension from a http source', async () => {
|
|
mockParseInstallSource.mockResolvedValue({
|
|
type: 'http',
|
|
url: 'http://google.com',
|
|
});
|
|
mockInstallExtension.mockResolvedValue({ name: 'http-extension' });
|
|
|
|
await handleInstall({
|
|
source: 'http://google.com',
|
|
});
|
|
|
|
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
'Extension "http-extension" installed successfully and enabled.',
|
|
);
|
|
});
|
|
|
|
it('should install an extension from a https source', async () => {
|
|
mockParseInstallSource.mockResolvedValue({
|
|
type: 'https',
|
|
url: 'https://google.com',
|
|
});
|
|
mockInstallExtension.mockResolvedValue({ name: 'https-extension' });
|
|
|
|
await handleInstall({
|
|
source: 'https://google.com',
|
|
});
|
|
|
|
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
'Extension "https-extension" installed successfully and enabled.',
|
|
);
|
|
});
|
|
|
|
it('should install an extension from a git source', async () => {
|
|
mockParseInstallSource.mockResolvedValue({
|
|
type: 'git',
|
|
url: 'git@some-url',
|
|
});
|
|
mockInstallExtension.mockResolvedValue({ name: 'git-extension' });
|
|
|
|
await handleInstall({
|
|
source: 'git@some-url',
|
|
});
|
|
|
|
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
'Extension "git-extension" installed successfully and enabled.',
|
|
);
|
|
});
|
|
|
|
it('throws an error from an unknown source', async () => {
|
|
mockParseInstallSource.mockRejectedValue(
|
|
new Error('Install source not found.'),
|
|
);
|
|
await handleInstall({
|
|
source: 'test://google.com',
|
|
});
|
|
|
|
expect(consoleErrorSpy).toHaveBeenCalledWith('Install source not found.');
|
|
expect(processSpy).toHaveBeenCalledWith(1);
|
|
});
|
|
|
|
it('should install an extension from a sso source', async () => {
|
|
mockParseInstallSource.mockResolvedValue({
|
|
type: 'sso',
|
|
url: 'sso://google.com',
|
|
});
|
|
mockInstallExtension.mockResolvedValue({ name: 'sso-extension' });
|
|
|
|
await handleInstall({
|
|
source: 'sso://google.com',
|
|
});
|
|
|
|
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
'Extension "sso-extension" installed successfully and enabled.',
|
|
);
|
|
});
|
|
|
|
it('should install an extension from a local path', async () => {
|
|
mockParseInstallSource.mockResolvedValue({
|
|
type: 'local',
|
|
path: '/some/path',
|
|
});
|
|
mockInstallExtension.mockResolvedValue({ name: 'local-extension' });
|
|
|
|
await handleInstall({
|
|
source: '/some/path',
|
|
});
|
|
|
|
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
'Extension "local-extension" installed successfully and enabled.',
|
|
);
|
|
});
|
|
|
|
it('should throw an error if install extension fails', async () => {
|
|
mockParseInstallSource.mockResolvedValue({
|
|
type: 'git',
|
|
url: 'git@some-url',
|
|
});
|
|
mockInstallExtension.mockRejectedValue(
|
|
new Error('Install extension failed'),
|
|
);
|
|
|
|
await handleInstall({ source: 'git@some-url' });
|
|
|
|
expect(consoleErrorSpy).toHaveBeenCalledWith('Install extension failed');
|
|
expect(processSpy).toHaveBeenCalledWith(1);
|
|
});
|
|
});
|