Path: blob/main/extensions/copilot/src/extension/context/node/resolvers/test/vscodeContext.spec.ts
13406 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { describe, expect, it } from 'vitest';6import { IWorkbenchService } from '../../../../../platform/workbench/common/workbenchService';7import { parseSettingsAndCommands } from '../vscodeContext';89// Mock implementation of IWorkbenchService for testing10class MockWorkbenchService implements IWorkbenchService {11declare readonly _serviceBrand: undefined;1213constructor(14private mockSettings: { [key: string]: any } = {},15private mockCommands: { label: string; command: string; keybinding: string }[] = []16) { }1718getAllExtensions(): readonly any[] {19return [];20}2122async getAllCommands(): Promise<{ label: string; command: string; keybinding: string }[]> {23return this.mockCommands;24}2526async getAllSettings(): Promise<{ [key: string]: any }> {27return this.mockSettings;28}29}3031describe('parseSettingsAndCommands', () => {32it('returns empty array for non-JSON code blocks', async () => {33const mockService = new MockWorkbenchService();34const codeBlock = '```typescript\nconsole.log("hello");\n```';35const result = await parseSettingsAndCommands(mockService, codeBlock);36expect(result).toEqual([]);37});3839it('returns empty array for invalid JSON', async () => {40const mockService = new MockWorkbenchService();41const codeBlock = '```json\n{ invalid json\n```';42const result = await parseSettingsAndCommands(mockService, codeBlock);43expect(result).toEqual([]);44});4546it('returns empty array for empty parsed array', async () => {47const mockService = new MockWorkbenchService();48const codeBlock = '```json\n[]\n```';49const result = await parseSettingsAndCommands(mockService, codeBlock);50expect(result).toEqual([]);51});5253it('handles trailing commas in JSON', async () => {54const mockService = new MockWorkbenchService({55'editor.fontSize': { value: 14 }56});57const codeBlock = `\`\`\`json58[59{60"type": "setting",61"details": {62"key": "editor.fontSize",63}64},65]66\`\`\``;6768const result = await parseSettingsAndCommands(mockService, codeBlock);69expect(result).toHaveLength(1);70expect(result[0].commandToRun?.command).toBe('workbench.action.openSettings');71expect(result[0].commandToRun?.arguments).toEqual(['@id:editor.fontSize ']);72});7374it('processes settings and creates openSettings command', async () => {75const mockService = new MockWorkbenchService({76'editor.fontSize': { value: 14 },77'workbench.colorTheme': { value: 'Dark+' }78});79const codeBlock = `\`\`\`json80[81{82"type": "setting",83"details": {84"key": "editor.fontSize"85}86},87{88"type": "setting",89"details": {90"key": "workbench.colorTheme"91}92}93]94\`\`\``;9596const result = await parseSettingsAndCommands(mockService, codeBlock);9798expect(result).toHaveLength(1);99expect(result[0].commandToRun?.command).toBe('workbench.action.openSettings');100expect(result[0].commandToRun?.arguments).toEqual(['@id:editor.fontSize @id:workbench.colorTheme ']);101expect(result[0].commandToRun?.title).toBe('Show in Settings Editor');102});103104it('filters out unknown settings', async () => {105const mockService = new MockWorkbenchService({106'editor.fontSize': { value: 14 }107// 'unknown.setting' is intentionally not included108});109const codeBlock = `\`\`\`json110[111{112"type": "setting",113"details": {114"key": "editor.fontSize"115}116},117{118"type": "setting",119"details": {120"key": "unknown.setting"121}122}123]124\`\`\``;125126const result = await parseSettingsAndCommands(mockService, codeBlock);127128expect(result).toHaveLength(1);129expect(result[0].commandToRun?.arguments).toEqual(['@id:editor.fontSize ']);130});131132it('returns empty quickOpen for unknown command', async () => {133const mockService = new MockWorkbenchService({}, [134{ label: 'Show All Commands', command: 'workbench.action.showCommands', keybinding: 'Ctrl+Shift+P' }135]);136const codeBlock = `\`\`\`json137[138{139"type": "command",140"details": {141"key": "unknown.command"142}143}144]145\`\`\``;146147const result = await parseSettingsAndCommands(mockService, codeBlock);148expect(result).toHaveLength(1);149expect(result[0].commandToRun?.command).toBe('workbench.action.quickOpen');150expect(result[0].commandToRun?.arguments).toEqual(['>']);151expect(result[0].commandToRun?.title).toBe('Open Command Palette');152});153154it('processes extension search command', async () => {155const mockService = new MockWorkbenchService();156const codeBlock = `\`\`\`json157[158{159"type": "command",160"details": {161"key": "workbench.extensions.search",162"value": "python"163}164}165]166\`\`\``;167168const result = await parseSettingsAndCommands(mockService, codeBlock);169170expect(result).toHaveLength(1);171expect(result[0].commandToRun?.command).toBe('workbench.extensions.search');172expect(result[0].commandToRun?.arguments).toEqual(['python']);173expect(result[0].commandToRun?.title).toBe('Search Extension Marketplace');174});175176it('processes extension install command', async () => {177const mockService = new MockWorkbenchService();178const codeBlock = `\`\`\`json179[180{181"type": "command",182"details": {183"key": "workbench.extensions.installExtension",184"value": ["ms-python.python"]185}186}187]188\`\`\``;189190const result = await parseSettingsAndCommands(mockService, codeBlock);191192expect(result).toHaveLength(1);193expect(result[0].commandToRun?.command).toBe('workbench.extensions.search');194expect(result[0].commandToRun?.arguments).toEqual(['ms-python.python']);195expect(result[0].commandToRun?.title).toBe('Search Extension Marketplace');196});197198it('handles extension search with known queries', async () => {199const mockService = new MockWorkbenchService();200const codeBlock = `\`\`\`json201[202{203"type": "command",204"details": {205"key": "workbench.extensions.search",206"value": "popular"207}208}209]210\`\`\``;211212const result = await parseSettingsAndCommands(mockService, codeBlock);213214expect(result).toHaveLength(1);215expect(result[0].commandToRun?.arguments).toEqual(['@popular']);216});217218it('handles extension search with tag', async () => {219const mockService = new MockWorkbenchService();220const codeBlock = `\`\`\`json221[222{223"type": "command",224"details": {225"key": "workbench.extensions.search",226"value": "category:themes"227}228}229]230\`\`\``;231232const result = await parseSettingsAndCommands(mockService, codeBlock);233234expect(result).toHaveLength(1);235expect(result[0].commandToRun?.arguments).toEqual(['@category:themes']);236});237238it('processes general command with quickOpen', async () => {239const mockService = new MockWorkbenchService({}, [240{ label: 'Show All Commands', command: 'workbench.action.showCommands', keybinding: 'Ctrl+Shift+P' }241]);242const codeBlock = `\`\`\`json243[244{245"type": "command",246"details": {247"key": "workbench.action.showCommands"248}249}250]251\`\`\``;252253const result = await parseSettingsAndCommands(mockService, codeBlock);254255expect(result).toHaveLength(1);256expect(result[0].commandToRun?.command).toBe('workbench.action.quickOpen');257expect(result[0].commandToRun?.arguments).toEqual(['>Show All Commands']);258expect(result[0].commandToRun?.title).toBe('Show in Command Palette');259});260261it('handles code block without language specified', async () => {262const mockService = new MockWorkbenchService({263'editor.fontSize': { value: 14 }264});265const codeBlock = `\`\`\`266[267{268"type": "setting",269"details": {270"key": "editor.fontSize"271}272}273]274\`\`\``;275276const result = await parseSettingsAndCommands(mockService, codeBlock);277278expect(result).toHaveLength(1);279expect(result[0].commandToRun?.command).toBe('workbench.action.openSettings');280});281282it('handles items without details property', async () => {283const mockService = new MockWorkbenchService({284'editor.fontSize': { value: 14 }285});286const codeBlock = `\`\`\`json287[288{289"type": "setting"290}291]292\`\`\``;293294const result = await parseSettingsAndCommands(mockService, codeBlock);295296expect(result).toHaveLength(1);297expect(result[0].commandToRun?.arguments).toEqual(['']);298});299300it('handles non-string extension arguments', async () => {301const mockService = new MockWorkbenchService();302const codeBlock = `\`\`\`json303[304{305"type": "command",306"details": {307"key": "workbench.extensions.search",308"value": [123, "python", null]309}310}311]312\`\`\``;313314const result = await parseSettingsAndCommands(mockService, codeBlock);315316expect(result).toHaveLength(1);317// Should filter out non-string values318expect(result[0].commandToRun?.arguments).toEqual(['python']);319});320321it('handles command with empty label', async () => {322const mockService = new MockWorkbenchService({}, [323{ label: '', command: 'test.command', keybinding: 'Ctrl+T' }324]);325const codeBlock = `\`\`\`json326[327{328"type": "command",329"details": {330"key": "test.command"331}332}333]334\`\`\``;335336const result = await parseSettingsAndCommands(mockService, codeBlock);337338expect(result).toHaveLength(1);339expect(result[0].commandToRun?.arguments).toEqual(['>']);340expect(result[0].commandToRun?.title).toBe('Show in Command Palette');341});342});343344345