mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-01 21:20:44 +00:00
fix test
This commit is contained in:
parent
f8e41fb7fa
commit
8b4626a2be
12 changed files with 1339 additions and 1493 deletions
106
packages/cli/src/commands/extensions.test.tsx
Normal file
106
packages/cli/src/commands/extensions.test.tsx
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { extensionsCommand } from './extensions.js';
|
||||
import { updateCommand } from './extensions/update.js';
|
||||
import { disableCommand } from './extensions/disable.js';
|
||||
import { enableCommand } from './extensions/enable.js';
|
||||
import { linkCommand } from './extensions/link.js';
|
||||
import { newCommand } from './extensions/new.js';
|
||||
import yargs from 'yargs';
|
||||
|
||||
describe('extensions command', () => {
|
||||
it('should have correct command name', () => {
|
||||
expect(extensionsCommand.command).toBe('extensions <command>');
|
||||
});
|
||||
|
||||
it('should have a description', () => {
|
||||
expect(extensionsCommand.describe).toBe('Manage Qwen Code extensions.');
|
||||
});
|
||||
|
||||
it('should require a subcommand', () => {
|
||||
const parser = yargs([])
|
||||
.command(extensionsCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
|
||||
expect(() => parser.parse('extensions')).toThrow();
|
||||
});
|
||||
|
||||
it('should register install subcommand', () => {
|
||||
const parser = yargs([])
|
||||
.command(extensionsCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
|
||||
// This should throw as 'install' requires a source argument
|
||||
expect(() => parser.parse('extensions install')).toThrow(
|
||||
'Not enough non-option arguments',
|
||||
);
|
||||
});
|
||||
|
||||
it('should register uninstall subcommand', () => {
|
||||
const parser = yargs([])
|
||||
.command(extensionsCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
|
||||
expect(() => parser.parse('extensions uninstall')).toThrow(
|
||||
'Not enough non-option arguments',
|
||||
);
|
||||
});
|
||||
|
||||
it('should register list subcommand', () => {
|
||||
const parser = yargs([])
|
||||
.command(extensionsCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
|
||||
// list doesn't require arguments, so it should not throw
|
||||
expect(() => parser.parse('extensions list')).not.toThrow();
|
||||
});
|
||||
|
||||
it('should register update subcommand', () => {
|
||||
const parser = yargs([]).command(updateCommand).fail(false).locale('en');
|
||||
|
||||
expect(() => parser.parse('update')).toThrow(
|
||||
'Either an extension name or --all must be provided',
|
||||
);
|
||||
});
|
||||
|
||||
it('should register disable subcommand', () => {
|
||||
const parser = yargs([]).command(disableCommand).fail(false).locale('en');
|
||||
|
||||
expect(() => parser.parse('disable')).toThrow(
|
||||
'Not enough non-option arguments',
|
||||
);
|
||||
});
|
||||
|
||||
it('should register enable subcommand', () => {
|
||||
const parser = yargs([]).command(enableCommand).fail(false).locale('en');
|
||||
|
||||
expect(() => parser.parse('enable')).toThrow(
|
||||
'Not enough non-option arguments',
|
||||
);
|
||||
});
|
||||
|
||||
it('should register link subcommand', () => {
|
||||
const parser = yargs([]).command(linkCommand).fail(false).locale('en');
|
||||
|
||||
expect(() => parser.parse('link')).toThrow(
|
||||
'Not enough non-option arguments',
|
||||
);
|
||||
});
|
||||
|
||||
it('should register new subcommand', async () => {
|
||||
const parser = yargs([]).command(newCommand).fail(false).locale('en');
|
||||
|
||||
await expect(parser.parseAsync('new')).rejects.toThrow(
|
||||
'Not enough non-option arguments',
|
||||
);
|
||||
});
|
||||
});
|
||||
273
packages/cli/src/commands/extensions/consent.test.ts
Normal file
273
packages/cli/src/commands/extensions/consent.test.ts
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { extensionConsentString, requestConsentOrFail } from './consent.js';
|
||||
import type { ExtensionConfig } from '@qwen-code/qwen-code-core';
|
||||
|
||||
vi.mock('../../i18n/index.js', () => ({
|
||||
t: vi.fn((str: string, params?: Record<string, string>) => {
|
||||
if (params) {
|
||||
return Object.entries(params).reduce(
|
||||
(acc, [key, value]) => acc.replace(`{{${key}}}`, value),
|
||||
str,
|
||||
);
|
||||
}
|
||||
return str;
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('extensionConsentString', () => {
|
||||
it('should include extension name', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
};
|
||||
|
||||
const result = extensionConsentString(config);
|
||||
|
||||
expect(result).toContain('Installing extension "test-extension".');
|
||||
});
|
||||
|
||||
it('should include warning message', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
};
|
||||
|
||||
const result = extensionConsentString(config);
|
||||
|
||||
expect(result).toContain('Extensions may introduce unexpected behavior');
|
||||
});
|
||||
|
||||
it('should include MCP servers when present', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
mcpServers: {
|
||||
'test-server': {
|
||||
command: 'node',
|
||||
args: ['server.js'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = extensionConsentString(config);
|
||||
|
||||
expect(result).toContain(
|
||||
'This extension will run the following MCP servers',
|
||||
);
|
||||
expect(result).toContain('test-server');
|
||||
expect(result).toContain('local');
|
||||
expect(result).toContain('node server.js');
|
||||
});
|
||||
|
||||
it('should include remote MCP servers', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
mcpServers: {
|
||||
'remote-server': {
|
||||
httpUrl: 'https://example.com/mcp',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = extensionConsentString(config);
|
||||
|
||||
expect(result).toContain('remote');
|
||||
expect(result).toContain('https://example.com/mcp');
|
||||
});
|
||||
|
||||
it('should include commands when present', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
};
|
||||
|
||||
const result = extensionConsentString(config, ['command1', 'command2']);
|
||||
|
||||
expect(result).toContain('This extension will add the following commands');
|
||||
expect(result).toContain('command1, command2');
|
||||
});
|
||||
|
||||
it('should include context file name when present (string)', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
contextFileName: 'CUSTOM.md',
|
||||
};
|
||||
|
||||
const result = extensionConsentString(config);
|
||||
|
||||
expect(result).toContain('CUSTOM.md');
|
||||
});
|
||||
|
||||
it('should include context file name when present (array)', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
contextFileName: ['FILE1.md', 'FILE2.md'],
|
||||
};
|
||||
|
||||
const result = extensionConsentString(config);
|
||||
|
||||
expect(result).toContain('FILE1.md, FILE2.md');
|
||||
});
|
||||
|
||||
it('should include excluded tools when present', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
excludeTools: ['tool1', 'tool2'],
|
||||
};
|
||||
|
||||
const result = extensionConsentString(config);
|
||||
|
||||
expect(result).toContain(
|
||||
'This extension will exclude the following core tools',
|
||||
);
|
||||
expect(result).toContain('tool1, tool2');
|
||||
});
|
||||
|
||||
it('should include skills when present', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
};
|
||||
|
||||
const result = extensionConsentString(
|
||||
config,
|
||||
[],
|
||||
[
|
||||
{
|
||||
name: 'skill1',
|
||||
description: 'Skill 1 description',
|
||||
level: 'extension',
|
||||
filePath: '/test/skill1',
|
||||
body: 'skill body',
|
||||
},
|
||||
{
|
||||
name: 'skill2',
|
||||
description: 'Skill 2 description',
|
||||
level: 'extension',
|
||||
filePath: '/test/skill2',
|
||||
body: 'skill body',
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
expect(result).toContain(
|
||||
'This extension will install the following skills',
|
||||
);
|
||||
expect(result).toContain('skill1');
|
||||
expect(result).toContain('Skill 1 description');
|
||||
});
|
||||
|
||||
it('should include subagents when present', () => {
|
||||
const config: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
};
|
||||
|
||||
const result = extensionConsentString(
|
||||
config,
|
||||
[],
|
||||
[],
|
||||
[
|
||||
{
|
||||
name: 'agent1',
|
||||
description: 'Agent 1 description',
|
||||
systemPrompt: 'You are agent1',
|
||||
level: 'extension',
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
expect(result).toContain(
|
||||
'This extension will install the following subagents',
|
||||
);
|
||||
expect(result).toContain('agent1');
|
||||
expect(result).toContain('Agent 1 description');
|
||||
});
|
||||
});
|
||||
|
||||
describe('requestConsentOrFail', () => {
|
||||
let mockRequestConsent: ReturnType<typeof vi.fn>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockRequestConsent = vi.fn();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should do nothing when options is undefined', async () => {
|
||||
await requestConsentOrFail(mockRequestConsent, undefined);
|
||||
|
||||
expect(mockRequestConsent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should request consent for new extension', async () => {
|
||||
mockRequestConsent.mockResolvedValueOnce(true);
|
||||
|
||||
await requestConsentOrFail(mockRequestConsent, {
|
||||
extensionConfig: { name: 'test-extension', version: '1.0.0' },
|
||||
});
|
||||
|
||||
expect(mockRequestConsent).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should throw error when user declines consent', async () => {
|
||||
mockRequestConsent.mockResolvedValueOnce(false);
|
||||
|
||||
await expect(
|
||||
requestConsentOrFail(mockRequestConsent, {
|
||||
extensionConfig: { name: 'test-extension', version: '1.0.0' },
|
||||
}),
|
||||
).rejects.toThrow('Installation cancelled for "test-extension".');
|
||||
});
|
||||
|
||||
it('should skip consent when consent string is unchanged', async () => {
|
||||
const extensionConfig: ExtensionConfig = {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
};
|
||||
|
||||
await requestConsentOrFail(mockRequestConsent, {
|
||||
extensionConfig,
|
||||
previousExtensionConfig: extensionConfig,
|
||||
});
|
||||
|
||||
expect(mockRequestConsent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should request consent when consent string changes', async () => {
|
||||
mockRequestConsent.mockResolvedValueOnce(true);
|
||||
|
||||
await requestConsentOrFail(mockRequestConsent, {
|
||||
extensionConfig: {
|
||||
name: 'test-extension',
|
||||
version: '1.0.0',
|
||||
excludeTools: ['tool1'],
|
||||
},
|
||||
previousExtensionConfig: { name: 'test-extension', version: '1.0.0' },
|
||||
});
|
||||
|
||||
expect(mockRequestConsent).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should request consent when commands change', async () => {
|
||||
mockRequestConsent.mockResolvedValueOnce(true);
|
||||
|
||||
await requestConsentOrFail(mockRequestConsent, {
|
||||
extensionConfig: { name: 'test-extension', version: '1.0.0' },
|
||||
commands: ['command1'],
|
||||
previousExtensionConfig: { name: 'test-extension', version: '1.0.0' },
|
||||
previousCommands: [],
|
||||
});
|
||||
|
||||
expect(mockRequestConsent).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
129
packages/cli/src/commands/extensions/disable.test.ts
Normal file
129
packages/cli/src/commands/extensions/disable.test.ts
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
describe,
|
||||
it,
|
||||
expect,
|
||||
vi,
|
||||
beforeEach,
|
||||
type MockInstance,
|
||||
} from 'vitest';
|
||||
import { disableCommand, handleDisable } from './disable.js';
|
||||
import yargs from 'yargs';
|
||||
import { SettingScope } from '../../config/settings.js';
|
||||
|
||||
const mockDisableExtension = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('./utils.js', () => ({
|
||||
getExtensionManager: vi.fn().mockResolvedValue({
|
||||
disableExtension: mockDisableExtension,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('../../utils/errors.js', () => ({
|
||||
getErrorMessage: vi.fn((error: Error) => error.message),
|
||||
}));
|
||||
|
||||
describe('extensions disable command', () => {
|
||||
it('should fail if no name is provided', () => {
|
||||
const validationParser = yargs([])
|
||||
.command(disableCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
expect(() => validationParser.parse('disable')).toThrow(
|
||||
'Not enough non-option arguments: got 0, need at least 1',
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if invalid scope is provided', () => {
|
||||
const validationParser = yargs([])
|
||||
.command(disableCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
expect(() =>
|
||||
validationParser.parse('disable test-extension --scope=invalid'),
|
||||
).toThrow(/Invalid scope: invalid/);
|
||||
});
|
||||
|
||||
it('should accept valid scope values', () => {
|
||||
const parser = yargs([]).command(disableCommand).fail(false).locale('en');
|
||||
// Just check that the scope option is recognized, actual execution needs name first
|
||||
expect(() =>
|
||||
parser.parse('disable my-extension --scope=user'),
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleDisable', () => {
|
||||
let consoleLogSpy: MockInstance;
|
||||
let consoleErrorSpy: MockInstance;
|
||||
let processExitSpy: MockInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
processExitSpy = vi
|
||||
.spyOn(process, 'exit')
|
||||
.mockImplementation(() => undefined as never);
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should disable an extension with user scope', async () => {
|
||||
await handleDisable({
|
||||
name: 'test-extension',
|
||||
scope: 'user',
|
||||
});
|
||||
|
||||
expect(mockDisableExtension).toHaveBeenCalledWith(
|
||||
'test-extension',
|
||||
SettingScope.User,
|
||||
);
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "test-extension" successfully disabled for scope "user".',
|
||||
);
|
||||
});
|
||||
|
||||
it('should disable an extension with workspace scope', async () => {
|
||||
await handleDisable({
|
||||
name: 'test-extension',
|
||||
scope: 'workspace',
|
||||
});
|
||||
|
||||
expect(mockDisableExtension).toHaveBeenCalledWith(
|
||||
'test-extension',
|
||||
SettingScope.Workspace,
|
||||
);
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "test-extension" successfully disabled for scope "workspace".',
|
||||
);
|
||||
});
|
||||
|
||||
it('should default to user scope when no scope is provided', async () => {
|
||||
await handleDisable({
|
||||
name: 'test-extension',
|
||||
});
|
||||
|
||||
expect(mockDisableExtension).toHaveBeenCalledWith(
|
||||
'test-extension',
|
||||
SettingScope.User,
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle errors and exit with code 1', async () => {
|
||||
mockDisableExtension.mockImplementationOnce(() => {
|
||||
throw new Error('Disable failed');
|
||||
});
|
||||
|
||||
await handleDisable({
|
||||
name: 'test-extension',
|
||||
scope: 'user',
|
||||
});
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('Disable failed');
|
||||
expect(processExitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
});
|
||||
136
packages/cli/src/commands/extensions/enable.test.ts
Normal file
136
packages/cli/src/commands/extensions/enable.test.ts
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
describe,
|
||||
it,
|
||||
expect,
|
||||
vi,
|
||||
beforeEach,
|
||||
type MockInstance,
|
||||
} from 'vitest';
|
||||
import { enableCommand, handleEnable } from './enable.js';
|
||||
import yargs from 'yargs';
|
||||
import { SettingScope } from '../../config/settings.js';
|
||||
|
||||
const mockEnableExtension = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('./utils.js', () => ({
|
||||
getExtensionManager: vi.fn().mockResolvedValue({
|
||||
enableExtension: mockEnableExtension,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@qwen-code/qwen-code-core', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('@qwen-code/qwen-code-core')>();
|
||||
return {
|
||||
...actual,
|
||||
FatalConfigError: class FatalConfigError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'FatalConfigError';
|
||||
}
|
||||
},
|
||||
getErrorMessage: (error: Error) => error.message,
|
||||
};
|
||||
});
|
||||
|
||||
describe('extensions enable command', () => {
|
||||
it('should fail if no name is provided', () => {
|
||||
const validationParser = yargs([])
|
||||
.command(enableCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
expect(() => validationParser.parse('enable')).toThrow(
|
||||
'Not enough non-option arguments: got 0, need at least 1',
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if invalid scope is provided', () => {
|
||||
const validationParser = yargs([])
|
||||
.command(enableCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
expect(() =>
|
||||
validationParser.parse('enable test-extension --scope=invalid'),
|
||||
).toThrow(/Invalid scope: invalid/);
|
||||
});
|
||||
|
||||
it('should accept valid scope values', () => {
|
||||
const parser = yargs([]).command(enableCommand).fail(false).locale('en');
|
||||
// Just check that the scope option is recognized, actual execution needs name first
|
||||
expect(() =>
|
||||
parser.parse('enable my-extension --scope=user'),
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleEnable', () => {
|
||||
let consoleLogSpy: MockInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should enable an extension with user scope', async () => {
|
||||
await handleEnable({
|
||||
name: 'test-extension',
|
||||
scope: 'user',
|
||||
});
|
||||
|
||||
expect(mockEnableExtension).toHaveBeenCalledWith(
|
||||
'test-extension',
|
||||
SettingScope.User,
|
||||
);
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "test-extension" successfully enabled for scope "user".',
|
||||
);
|
||||
});
|
||||
|
||||
it('should enable an extension with workspace scope', async () => {
|
||||
await handleEnable({
|
||||
name: 'test-extension',
|
||||
scope: 'workspace',
|
||||
});
|
||||
|
||||
expect(mockEnableExtension).toHaveBeenCalledWith(
|
||||
'test-extension',
|
||||
SettingScope.Workspace,
|
||||
);
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "test-extension" successfully enabled for scope "workspace".',
|
||||
);
|
||||
});
|
||||
|
||||
it('should default to user scope when no scope is provided', async () => {
|
||||
await handleEnable({
|
||||
name: 'test-extension',
|
||||
});
|
||||
|
||||
expect(mockEnableExtension).toHaveBeenCalledWith(
|
||||
'test-extension',
|
||||
SettingScope.User,
|
||||
);
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "test-extension" successfully enabled in all scopes.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw FatalConfigError when enable fails', async () => {
|
||||
mockEnableExtension.mockImplementationOnce(() => {
|
||||
throw new Error('Enable failed');
|
||||
});
|
||||
|
||||
await expect(
|
||||
handleEnable({
|
||||
name: 'test-extension',
|
||||
scope: 'user',
|
||||
}),
|
||||
).rejects.toThrow('Enable failed');
|
||||
});
|
||||
});
|
||||
95
packages/cli/src/commands/extensions/link.test.ts
Normal file
95
packages/cli/src/commands/extensions/link.test.ts
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
describe,
|
||||
it,
|
||||
expect,
|
||||
vi,
|
||||
beforeEach,
|
||||
type MockInstance,
|
||||
} from 'vitest';
|
||||
import { linkCommand, handleLink } from './link.js';
|
||||
import yargs from 'yargs';
|
||||
|
||||
const mockInstallExtension = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('./utils.js', () => ({
|
||||
getExtensionManager: vi.fn().mockResolvedValue({
|
||||
installExtension: mockInstallExtension,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('./consent.js', () => ({
|
||||
requestConsentNonInteractive: vi.fn().mockResolvedValue(true),
|
||||
requestConsentOrFail: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../utils/errors.js', () => ({
|
||||
getErrorMessage: vi.fn((error: Error) => error.message),
|
||||
}));
|
||||
|
||||
describe('extensions link command', () => {
|
||||
it('should fail if no path is provided', () => {
|
||||
const validationParser = yargs([])
|
||||
.command(linkCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
expect(() => validationParser.parse('link')).toThrow(
|
||||
'Not enough non-option arguments: got 0, need at least 1',
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept a path argument', () => {
|
||||
const parser = yargs([]).command(linkCommand).fail(false).locale('en');
|
||||
expect(() => parser.parse('link /some/path')).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleLink', () => {
|
||||
let consoleLogSpy: MockInstance;
|
||||
let consoleErrorSpy: MockInstance;
|
||||
let processExitSpy: MockInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
processExitSpy = vi
|
||||
.spyOn(process, 'exit')
|
||||
.mockImplementation(() => undefined as never);
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should link an extension from a local path', async () => {
|
||||
mockInstallExtension.mockResolvedValueOnce({ name: 'linked-extension' });
|
||||
|
||||
await handleLink({
|
||||
path: '/some/local/path',
|
||||
});
|
||||
|
||||
expect(mockInstallExtension).toHaveBeenCalledWith(
|
||||
{
|
||||
source: '/some/local/path',
|
||||
type: 'link',
|
||||
},
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "linked-extension" linked successfully and enabled.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle errors and exit with code 1', async () => {
|
||||
mockInstallExtension.mockRejectedValueOnce(new Error('Link failed'));
|
||||
|
||||
await handleLink({
|
||||
path: '/some/local/path',
|
||||
});
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('Link failed');
|
||||
expect(processExitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
});
|
||||
90
packages/cli/src/commands/extensions/list.test.ts
Normal file
90
packages/cli/src/commands/extensions/list.test.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
describe,
|
||||
it,
|
||||
expect,
|
||||
vi,
|
||||
beforeEach,
|
||||
type MockInstance,
|
||||
} from 'vitest';
|
||||
import { listCommand, handleList } from './list.js';
|
||||
import yargs from 'yargs';
|
||||
|
||||
const mockGetLoadedExtensions = vi.hoisted(() => vi.fn());
|
||||
const mockToOutputString = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('./utils.js', () => ({
|
||||
getExtensionManager: vi.fn().mockResolvedValue({
|
||||
getLoadedExtensions: mockGetLoadedExtensions,
|
||||
toOutputString: mockToOutputString,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('../../utils/errors.js', () => ({
|
||||
getErrorMessage: vi.fn((error: Error) => error.message),
|
||||
}));
|
||||
|
||||
describe('extensions list command', () => {
|
||||
it('should parse the list command', () => {
|
||||
const parser = yargs([]).command(listCommand).fail(false).locale('en');
|
||||
expect(() => parser.parse('list')).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleList', () => {
|
||||
let consoleLogSpy: MockInstance;
|
||||
let consoleErrorSpy: MockInstance;
|
||||
let processExitSpy: MockInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
processExitSpy = vi
|
||||
.spyOn(process, 'exit')
|
||||
.mockImplementation(() => undefined as never);
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should display message when no extensions are installed', async () => {
|
||||
mockGetLoadedExtensions.mockReturnValueOnce([]);
|
||||
|
||||
await handleList();
|
||||
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith('No extensions installed.');
|
||||
});
|
||||
|
||||
it('should list installed extensions', async () => {
|
||||
const mockExtensions = [
|
||||
{ name: 'extension-1', version: '1.0.0' },
|
||||
{ name: 'extension-2', version: '2.0.0' },
|
||||
];
|
||||
mockGetLoadedExtensions.mockReturnValueOnce(mockExtensions);
|
||||
mockToOutputString.mockImplementation(
|
||||
(ext) => `${ext.name} (${ext.version})`,
|
||||
);
|
||||
|
||||
await handleList();
|
||||
|
||||
expect(mockGetLoadedExtensions).toHaveBeenCalled();
|
||||
expect(mockToOutputString).toHaveBeenCalledTimes(2);
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'extension-1 (1.0.0)\n\nextension-2 (2.0.0)',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle errors and exit with code 1', async () => {
|
||||
mockGetLoadedExtensions.mockImplementationOnce(() => {
|
||||
throw new Error('List failed');
|
||||
});
|
||||
|
||||
await handleList();
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('List failed');
|
||||
expect(processExitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
});
|
||||
262
packages/cli/src/commands/extensions/update.test.ts
Normal file
262
packages/cli/src/commands/extensions/update.test.ts
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {
|
||||
describe,
|
||||
it,
|
||||
expect,
|
||||
vi,
|
||||
beforeEach,
|
||||
type MockInstance,
|
||||
} from 'vitest';
|
||||
import { updateCommand, handleUpdate } from './update.js';
|
||||
import yargs from 'yargs';
|
||||
import { ExtensionUpdateState } from '../../ui/state/extensions.js';
|
||||
|
||||
const mockGetLoadedExtensions = vi.hoisted(() => vi.fn());
|
||||
const mockUpdateExtension = vi.hoisted(() => vi.fn());
|
||||
const mockCheckForAllExtensionUpdates = vi.hoisted(() => vi.fn());
|
||||
const mockUpdateAllUpdatableExtensions = vi.hoisted(() => vi.fn());
|
||||
const mockCheckForExtensionUpdate = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('./utils.js', () => ({
|
||||
getExtensionManager: vi.fn().mockResolvedValue({
|
||||
getLoadedExtensions: mockGetLoadedExtensions,
|
||||
updateExtension: mockUpdateExtension,
|
||||
checkForAllExtensionUpdates: mockCheckForAllExtensionUpdates,
|
||||
updateAllUpdatableExtensions: mockUpdateAllUpdatableExtensions,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@qwen-code/qwen-code-core', () => ({
|
||||
checkForExtensionUpdate: mockCheckForExtensionUpdate,
|
||||
}));
|
||||
|
||||
vi.mock('../../utils/errors.js', () => ({
|
||||
getErrorMessage: vi.fn((error: Error) => error.message),
|
||||
}));
|
||||
|
||||
vi.mock('../../ui/state/extensions.js', () => ({
|
||||
ExtensionUpdateState: {
|
||||
UPDATE_AVAILABLE: 'update available',
|
||||
UP_TO_DATE: 'up to date',
|
||||
ERROR: 'error',
|
||||
},
|
||||
}));
|
||||
|
||||
describe('extensions update command', () => {
|
||||
it('should fail if neither name nor --all is provided', () => {
|
||||
const validationParser = yargs([])
|
||||
.command(updateCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
expect(() => validationParser.parse('update')).toThrow(
|
||||
'Either an extension name or --all must be provided',
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if both name and --all are provided', () => {
|
||||
const validationParser = yargs([])
|
||||
.command(updateCommand)
|
||||
.fail(false)
|
||||
.locale('en');
|
||||
expect(() => validationParser.parse('update test-extension --all')).toThrow(
|
||||
/Arguments .* are mutually exclusive/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept --all flag', () => {
|
||||
const parser = yargs([]).command(updateCommand).fail(false).locale('en');
|
||||
expect(() => parser.parse('update --all')).not.toThrow();
|
||||
});
|
||||
|
||||
it('should accept an extension name', () => {
|
||||
const parser = yargs([]).command(updateCommand).fail(false).locale('en');
|
||||
expect(() => parser.parse('update test-extension')).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleUpdate', () => {
|
||||
let consoleLogSpy: MockInstance;
|
||||
let consoleErrorSpy: MockInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('update by name', () => {
|
||||
it('should show message when extension is not found', async () => {
|
||||
mockGetLoadedExtensions.mockReturnValueOnce([]);
|
||||
|
||||
await handleUpdate({ name: 'non-existent-extension' });
|
||||
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "non-existent-extension" not found.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should show message when extension has no install metadata', async () => {
|
||||
mockGetLoadedExtensions.mockReturnValueOnce([
|
||||
{ name: 'test-extension', installMetadata: undefined },
|
||||
]);
|
||||
|
||||
await handleUpdate({ name: 'test-extension' });
|
||||
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Unable to install extension "test-extension" due to missing install metadata',
|
||||
);
|
||||
});
|
||||
|
||||
it('should show message when extension is already up to date', async () => {
|
||||
const mockExtension = {
|
||||
name: 'test-extension',
|
||||
installMetadata: { source: 'test' },
|
||||
};
|
||||
mockGetLoadedExtensions.mockReturnValueOnce([mockExtension]);
|
||||
mockCheckForExtensionUpdate.mockResolvedValueOnce(
|
||||
ExtensionUpdateState.UP_TO_DATE,
|
||||
);
|
||||
|
||||
await handleUpdate({ name: 'test-extension' });
|
||||
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "test-extension" is already up to date.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should update extension when update is available', async () => {
|
||||
const mockExtension = {
|
||||
name: 'test-extension',
|
||||
installMetadata: { source: 'test' },
|
||||
};
|
||||
mockGetLoadedExtensions.mockReturnValueOnce([mockExtension]);
|
||||
mockCheckForExtensionUpdate.mockResolvedValueOnce(
|
||||
ExtensionUpdateState.UPDATE_AVAILABLE,
|
||||
);
|
||||
mockUpdateExtension.mockResolvedValueOnce({
|
||||
name: 'test-extension',
|
||||
originalVersion: '1.0.0',
|
||||
updatedVersion: '2.0.0',
|
||||
});
|
||||
|
||||
await handleUpdate({ name: 'test-extension' });
|
||||
|
||||
expect(mockUpdateExtension).toHaveBeenCalledWith(
|
||||
mockExtension,
|
||||
ExtensionUpdateState.UPDATE_AVAILABLE,
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "test-extension" successfully updated: 1.0.0 → 2.0.0.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should show up to date message when versions are the same after update', async () => {
|
||||
const mockExtension = {
|
||||
name: 'test-extension',
|
||||
installMetadata: { source: 'test' },
|
||||
};
|
||||
mockGetLoadedExtensions.mockReturnValueOnce([mockExtension]);
|
||||
mockCheckForExtensionUpdate.mockResolvedValueOnce(
|
||||
ExtensionUpdateState.UPDATE_AVAILABLE,
|
||||
);
|
||||
mockUpdateExtension.mockResolvedValueOnce({
|
||||
name: 'test-extension',
|
||||
originalVersion: '1.0.0',
|
||||
updatedVersion: '1.0.0',
|
||||
});
|
||||
|
||||
await handleUpdate({ name: 'test-extension' });
|
||||
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "test-extension" is already up to date.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle errors during update', async () => {
|
||||
const mockExtension = {
|
||||
name: 'test-extension',
|
||||
installMetadata: { source: 'test' },
|
||||
};
|
||||
mockGetLoadedExtensions.mockReturnValueOnce([mockExtension]);
|
||||
mockCheckForExtensionUpdate.mockRejectedValueOnce(
|
||||
new Error('Update check failed'),
|
||||
);
|
||||
|
||||
await handleUpdate({ name: 'test-extension' });
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('Update check failed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('update all', () => {
|
||||
it('should show message when no extensions to update', async () => {
|
||||
mockCheckForAllExtensionUpdates.mockResolvedValueOnce(undefined);
|
||||
mockUpdateAllUpdatableExtensions.mockResolvedValueOnce([]);
|
||||
|
||||
await handleUpdate({ all: true });
|
||||
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith('No extensions to update.');
|
||||
});
|
||||
|
||||
it('should update all extensions with updates available', async () => {
|
||||
mockCheckForAllExtensionUpdates.mockResolvedValueOnce(undefined);
|
||||
mockUpdateAllUpdatableExtensions.mockResolvedValueOnce([
|
||||
{
|
||||
name: 'extension-1',
|
||||
originalVersion: '1.0.0',
|
||||
updatedVersion: '2.0.0',
|
||||
},
|
||||
{
|
||||
name: 'extension-2',
|
||||
originalVersion: '1.0.0',
|
||||
updatedVersion: '1.5.0',
|
||||
},
|
||||
]);
|
||||
|
||||
await handleUpdate({ all: true });
|
||||
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "extension-1" successfully updated: 1.0.0 → 2.0.0.\n' +
|
||||
'Extension "extension-2" successfully updated: 1.0.0 → 1.5.0.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should filter out extensions with same version after update', async () => {
|
||||
mockCheckForAllExtensionUpdates.mockResolvedValueOnce(undefined);
|
||||
mockUpdateAllUpdatableExtensions.mockResolvedValueOnce([
|
||||
{
|
||||
name: 'extension-1',
|
||||
originalVersion: '1.0.0',
|
||||
updatedVersion: '2.0.0',
|
||||
},
|
||||
{
|
||||
name: 'extension-2',
|
||||
originalVersion: '1.0.0',
|
||||
updatedVersion: '1.0.0',
|
||||
},
|
||||
]);
|
||||
|
||||
await handleUpdate({ all: true });
|
||||
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'Extension "extension-1" successfully updated: 1.0.0 → 2.0.0.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle errors during update all', async () => {
|
||||
mockCheckForAllExtensionUpdates.mockRejectedValueOnce(
|
||||
new Error('Update all failed'),
|
||||
);
|
||||
|
||||
await handleUpdate({ all: true });
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('Update all failed');
|
||||
});
|
||||
});
|
||||
});
|
||||
66
packages/cli/src/commands/extensions/utils.test.ts
Normal file
66
packages/cli/src/commands/extensions/utils.test.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { getExtensionManager } from './utils.js';
|
||||
|
||||
const mockRefreshCache = vi.fn();
|
||||
const mockExtensionManagerInstance = {
|
||||
refreshCache: mockRefreshCache,
|
||||
};
|
||||
|
||||
vi.mock('@qwen-code/qwen-code-core', () => ({
|
||||
ExtensionManager: vi
|
||||
.fn()
|
||||
.mockImplementation(() => mockExtensionManagerInstance),
|
||||
}));
|
||||
|
||||
vi.mock('../../config/settings.js', () => ({
|
||||
loadSettings: vi.fn().mockReturnValue({
|
||||
merged: {},
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('../../config/trustedFolders.js', () => ({
|
||||
isWorkspaceTrusted: vi.fn().mockReturnValue({ isTrusted: true }),
|
||||
}));
|
||||
|
||||
vi.mock('./consent.js', () => ({
|
||||
requestConsentOrFail: vi.fn(),
|
||||
requestConsentNonInteractive: vi.fn(),
|
||||
}));
|
||||
|
||||
describe('getExtensionManager', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockRefreshCache.mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
it('should return an ExtensionManager instance', async () => {
|
||||
const manager = await getExtensionManager();
|
||||
|
||||
expect(manager).toBeDefined();
|
||||
expect(manager).toBe(mockExtensionManagerInstance);
|
||||
});
|
||||
|
||||
it('should call refreshCache on the ExtensionManager', async () => {
|
||||
await getExtensionManager();
|
||||
|
||||
expect(mockRefreshCache).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use current working directory as workspace', async () => {
|
||||
const { ExtensionManager } = await import('@qwen-code/qwen-code-core');
|
||||
|
||||
await getExtensionManager();
|
||||
|
||||
expect(ExtensionManager).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
workspaceDir: process.cwd(),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -231,18 +231,21 @@ describe('Configuration Integration Tests', () => {
|
|||
expect(config.getExtensionContextFilePaths()).toEqual([]);
|
||||
});
|
||||
|
||||
it('should correctly store and return extension context file paths', () => {
|
||||
const contextFiles = ['/path/to/file1.txt', '/path/to/file2.js'];
|
||||
it('should correctly store and return extension context file paths with outputLanguageFilePath', () => {
|
||||
const outputLanguageFilePath = '/path/to/language.txt';
|
||||
const configParams: ConfigParameters = {
|
||||
cwd: '/tmp',
|
||||
generationConfig: TEST_CONTENT_GENERATOR_CONFIG,
|
||||
embeddingModel: 'test-embedding-model',
|
||||
targetDir: tempDir,
|
||||
debugMode: false,
|
||||
extensionContextFilePaths: contextFiles,
|
||||
outputLanguageFilePath,
|
||||
};
|
||||
const config = new Config(configParams);
|
||||
expect(config.getExtensionContextFilePaths()).toEqual(contextFiles);
|
||||
// outputLanguageFilePath should be included in extension context file paths
|
||||
expect(config.getExtensionContextFilePaths()).toContain(
|
||||
outputLanguageFilePath,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -862,14 +862,19 @@ export async function loadCliConfig(
|
|||
argv.excludeTools,
|
||||
);
|
||||
|
||||
const allowedMcpServers = argv.allowedMcpServerNames
|
||||
? new Set(argv.allowedMcpServerNames.filter(Boolean))
|
||||
: settings.mcp?.allowed
|
||||
let allowedMcpServers: Set<string> | undefined;
|
||||
let excludedMcpServers: Set<string> | undefined;
|
||||
if (argv.allowedMcpServerNames) {
|
||||
allowedMcpServers = new Set(argv.allowedMcpServerNames.filter(Boolean));
|
||||
excludedMcpServers = undefined;
|
||||
} else {
|
||||
allowedMcpServers = settings.mcp?.allowed
|
||||
? new Set(settings.mcp.allowed.filter(Boolean))
|
||||
: undefined;
|
||||
const excludedMcpServers = settings.mcp?.excluded
|
||||
? new Set(settings.mcp.excluded.filter(Boolean))
|
||||
: undefined;
|
||||
excludedMcpServers = settings.mcp?.excluded
|
||||
? new Set(settings.mcp.excluded.filter(Boolean))
|
||||
: undefined;
|
||||
}
|
||||
|
||||
const selectedAuthType =
|
||||
(argv.authType as AuthType | undefined) ||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ describe('extensionsCommand', () => {
|
|||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: 'No extensions installed. Run `/extensions explore` to check out the gallery.',
|
||||
text: 'No extensions installed.',
|
||||
},
|
||||
expect.any(Number),
|
||||
);
|
||||
|
|
@ -241,7 +241,7 @@ describe('extensionsCommand', () => {
|
|||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
text: 'Extension ext-one not found.',
|
||||
text: 'Extension "ext-one" not found.',
|
||||
},
|
||||
expect.any(Number),
|
||||
);
|
||||
|
|
@ -645,7 +645,7 @@ describe('extensionsCommand', () => {
|
|||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: 'Extension "test-extension" disabled for the scope "User"',
|
||||
text: 'Extension "test-extension" disabled for scope "User"',
|
||||
},
|
||||
expect.any(Number),
|
||||
);
|
||||
|
|
@ -663,7 +663,7 @@ describe('extensionsCommand', () => {
|
|||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: 'Extension "test-extension" disabled for the scope "Workspace"',
|
||||
text: 'Extension "test-extension" disabled for scope "Workspace"',
|
||||
},
|
||||
expect.any(Number),
|
||||
);
|
||||
|
|
@ -675,7 +675,7 @@ describe('extensionsCommand', () => {
|
|||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
text: 'Unsupported scope invalid, should be one of "user" or "workspace"',
|
||||
text: 'Unsupported scope "invalid", should be one of "user" or "workspace"',
|
||||
},
|
||||
expect.any(Number),
|
||||
);
|
||||
|
|
@ -741,7 +741,7 @@ describe('extensionsCommand', () => {
|
|||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: 'Extension "test-extension" enabled for the scope "User"',
|
||||
text: 'Extension "test-extension" enabled for scope "User"',
|
||||
},
|
||||
expect.any(Number),
|
||||
);
|
||||
|
|
@ -759,7 +759,7 @@ describe('extensionsCommand', () => {
|
|||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: 'Extension "test-extension" enabled for the scope "Workspace"',
|
||||
text: 'Extension "test-extension" enabled for scope "Workspace"',
|
||||
},
|
||||
expect.any(Number),
|
||||
);
|
||||
|
|
@ -771,7 +771,7 @@ describe('extensionsCommand', () => {
|
|||
expect(mockContext.ui.addItem).toHaveBeenCalledWith(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
text: 'Unsupported scope invalid, should be one of "user" or "workspace"',
|
||||
text: 'Unsupported scope "invalid", should be one of "user" or "workspace"',
|
||||
},
|
||||
expect.any(Number),
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue