mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-21 21:01:06 -05:00
Continuing work on support for OpenRouter compression (#43)
This commit is contained in:
@@ -61,6 +61,7 @@ type GlobalStateKey =
|
||||
| "azureApiVersion"
|
||||
| "openRouterModelId"
|
||||
| "openRouterModelInfo"
|
||||
| "openRouterUseMiddleOutTransform"
|
||||
| "allowedCommands"
|
||||
| "soundEnabled"
|
||||
|
||||
@@ -391,6 +392,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
azureApiVersion,
|
||||
openRouterModelId,
|
||||
openRouterModelInfo,
|
||||
openRouterUseMiddleOutTransform,
|
||||
} = message.apiConfiguration
|
||||
await this.updateGlobalState("apiProvider", apiProvider)
|
||||
await this.updateGlobalState("apiModelId", apiModelId)
|
||||
@@ -416,6 +418,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
await this.updateGlobalState("azureApiVersion", azureApiVersion)
|
||||
await this.updateGlobalState("openRouterModelId", openRouterModelId)
|
||||
await this.updateGlobalState("openRouterModelInfo", openRouterModelInfo)
|
||||
await this.updateGlobalState("openRouterUseMiddleOutTransform", openRouterUseMiddleOutTransform)
|
||||
if (this.cline) {
|
||||
this.cline.api = buildApiHandler(message.apiConfiguration)
|
||||
}
|
||||
@@ -943,6 +946,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
azureApiVersion,
|
||||
openRouterModelId,
|
||||
openRouterModelInfo,
|
||||
openRouterUseMiddleOutTransform,
|
||||
lastShownAnnouncementId,
|
||||
customInstructions,
|
||||
alwaysAllowReadOnly,
|
||||
@@ -977,6 +981,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
this.getGlobalState("azureApiVersion") as Promise<string | undefined>,
|
||||
this.getGlobalState("openRouterModelId") as Promise<string | undefined>,
|
||||
this.getGlobalState("openRouterModelInfo") as Promise<ModelInfo | undefined>,
|
||||
this.getGlobalState("openRouterUseMiddleOutTransform") as Promise<boolean | undefined>,
|
||||
this.getGlobalState("lastShownAnnouncementId") as Promise<string | undefined>,
|
||||
this.getGlobalState("customInstructions") as Promise<string | undefined>,
|
||||
this.getGlobalState("alwaysAllowReadOnly") as Promise<boolean | undefined>,
|
||||
@@ -1028,6 +1033,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
azureApiVersion,
|
||||
openRouterModelId,
|
||||
openRouterModelInfo,
|
||||
openRouterUseMiddleOutTransform,
|
||||
},
|
||||
lastShownAnnouncementId,
|
||||
customInstructions,
|
||||
|
||||
234
src/core/webview/__tests__/ClineProvider.test.ts
Normal file
234
src/core/webview/__tests__/ClineProvider.test.ts
Normal file
@@ -0,0 +1,234 @@
|
||||
import { ClineProvider } from '../ClineProvider'
|
||||
import * as vscode from 'vscode'
|
||||
import { ExtensionMessage, ExtensionState } from '../../../shared/ExtensionMessage'
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock('vscode', () => ({
|
||||
ExtensionContext: jest.fn(),
|
||||
OutputChannel: jest.fn(),
|
||||
WebviewView: jest.fn(),
|
||||
Uri: {
|
||||
joinPath: jest.fn(),
|
||||
file: jest.fn()
|
||||
},
|
||||
workspace: {
|
||||
getConfiguration: jest.fn().mockReturnValue({
|
||||
get: jest.fn().mockReturnValue([]),
|
||||
update: jest.fn()
|
||||
}),
|
||||
onDidChangeConfiguration: jest.fn().mockImplementation((callback) => ({
|
||||
dispose: jest.fn()
|
||||
}))
|
||||
},
|
||||
env: {
|
||||
uriScheme: 'vscode'
|
||||
}
|
||||
}))
|
||||
|
||||
// Mock ESM modules
|
||||
jest.mock('p-wait-for', () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn().mockResolvedValue(undefined)
|
||||
}))
|
||||
|
||||
// Mock fs/promises
|
||||
jest.mock('fs/promises', () => ({
|
||||
mkdir: jest.fn(),
|
||||
writeFile: jest.fn(),
|
||||
readFile: jest.fn(),
|
||||
unlink: jest.fn(),
|
||||
rmdir: jest.fn()
|
||||
}))
|
||||
|
||||
// Mock axios
|
||||
jest.mock('axios', () => ({
|
||||
get: jest.fn().mockResolvedValue({ data: { data: [] } }),
|
||||
post: jest.fn()
|
||||
}))
|
||||
|
||||
// Mock buildApiHandler
|
||||
jest.mock('../../../api', () => ({
|
||||
buildApiHandler: jest.fn()
|
||||
}))
|
||||
|
||||
// Mock WorkspaceTracker
|
||||
jest.mock('../../../integrations/workspace/WorkspaceTracker', () => {
|
||||
return jest.fn().mockImplementation(() => ({
|
||||
initializeFilePaths: jest.fn(),
|
||||
dispose: jest.fn()
|
||||
}))
|
||||
})
|
||||
|
||||
// Mock Cline
|
||||
jest.mock('../../Cline', () => {
|
||||
return {
|
||||
Cline: jest.fn().mockImplementation(() => ({
|
||||
abortTask: jest.fn(),
|
||||
handleWebviewAskResponse: jest.fn(),
|
||||
clineMessages: []
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
// Spy on console.error and console.log to suppress expected messages
|
||||
beforeAll(() => {
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {})
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {})
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
jest.restoreAllMocks()
|
||||
})
|
||||
|
||||
describe('ClineProvider', () => {
|
||||
let provider: ClineProvider
|
||||
let mockContext: vscode.ExtensionContext
|
||||
let mockOutputChannel: vscode.OutputChannel
|
||||
let mockWebviewView: vscode.WebviewView
|
||||
let mockPostMessage: jest.Mock
|
||||
let visibilityChangeCallback: (e?: unknown) => void
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset mocks
|
||||
jest.clearAllMocks()
|
||||
|
||||
// Mock context
|
||||
mockContext = {
|
||||
extensionPath: '/test/path',
|
||||
extensionUri: {} as vscode.Uri,
|
||||
globalState: {
|
||||
get: jest.fn(),
|
||||
update: jest.fn(),
|
||||
keys: jest.fn().mockReturnValue([]),
|
||||
},
|
||||
secrets: {
|
||||
get: jest.fn(),
|
||||
store: jest.fn(),
|
||||
delete: jest.fn()
|
||||
},
|
||||
subscriptions: [],
|
||||
extension: {
|
||||
packageJSON: { version: '1.0.0' }
|
||||
},
|
||||
globalStorageUri: {
|
||||
fsPath: '/test/storage/path'
|
||||
}
|
||||
} as unknown as vscode.ExtensionContext
|
||||
|
||||
// Mock output channel
|
||||
mockOutputChannel = {
|
||||
appendLine: jest.fn(),
|
||||
clear: jest.fn(),
|
||||
dispose: jest.fn()
|
||||
} as unknown as vscode.OutputChannel
|
||||
|
||||
// Mock webview
|
||||
mockPostMessage = jest.fn()
|
||||
mockWebviewView = {
|
||||
webview: {
|
||||
postMessage: mockPostMessage,
|
||||
html: '',
|
||||
options: {},
|
||||
onDidReceiveMessage: jest.fn(),
|
||||
asWebviewUri: jest.fn()
|
||||
},
|
||||
visible: true,
|
||||
onDidDispose: jest.fn().mockImplementation((callback) => {
|
||||
callback()
|
||||
return { dispose: jest.fn() }
|
||||
}),
|
||||
onDidChangeVisibility: jest.fn().mockImplementation((callback) => {
|
||||
visibilityChangeCallback = callback
|
||||
return { dispose: jest.fn() }
|
||||
})
|
||||
} as unknown as vscode.WebviewView
|
||||
|
||||
provider = new ClineProvider(mockContext, mockOutputChannel)
|
||||
})
|
||||
|
||||
test('constructor initializes correctly', () => {
|
||||
expect(provider).toBeInstanceOf(ClineProvider)
|
||||
// Since getVisibleInstance returns the last instance where view.visible is true
|
||||
// @ts-ignore - accessing private property for testing
|
||||
provider.view = mockWebviewView
|
||||
expect(ClineProvider.getVisibleInstance()).toBe(provider)
|
||||
})
|
||||
|
||||
test('resolveWebviewView sets up webview correctly', () => {
|
||||
provider.resolveWebviewView(mockWebviewView)
|
||||
|
||||
expect(mockWebviewView.webview.options).toEqual({
|
||||
enableScripts: true,
|
||||
localResourceRoots: [mockContext.extensionUri]
|
||||
})
|
||||
expect(mockWebviewView.webview.html).toContain('<!DOCTYPE html>')
|
||||
})
|
||||
|
||||
test('postMessageToWebview sends message to webview', async () => {
|
||||
provider.resolveWebviewView(mockWebviewView)
|
||||
|
||||
const mockState: ExtensionState = {
|
||||
version: '1.0.0',
|
||||
clineMessages: [],
|
||||
taskHistory: [],
|
||||
shouldShowAnnouncement: false,
|
||||
apiConfiguration: {
|
||||
apiProvider: 'openrouter'
|
||||
},
|
||||
customInstructions: undefined,
|
||||
alwaysAllowReadOnly: false,
|
||||
alwaysAllowWrite: false,
|
||||
alwaysAllowExecute: false,
|
||||
alwaysAllowBrowser: false,
|
||||
uriScheme: 'vscode',
|
||||
soundEnabled: true
|
||||
}
|
||||
|
||||
const message: ExtensionMessage = {
|
||||
type: 'state',
|
||||
state: mockState
|
||||
}
|
||||
await provider.postMessageToWebview(message)
|
||||
|
||||
expect(mockPostMessage).toHaveBeenCalledWith(message)
|
||||
})
|
||||
|
||||
test('handles webviewDidLaunch message', async () => {
|
||||
provider.resolveWebviewView(mockWebviewView)
|
||||
|
||||
// Get the message handler from onDidReceiveMessage
|
||||
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
|
||||
|
||||
// Simulate webviewDidLaunch message
|
||||
await messageHandler({ type: 'webviewDidLaunch' })
|
||||
|
||||
// Should post state and theme to webview
|
||||
expect(mockPostMessage).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('clearTask aborts current task', async () => {
|
||||
const mockAbortTask = jest.fn()
|
||||
// @ts-ignore - accessing private property for testing
|
||||
provider.cline = { abortTask: mockAbortTask }
|
||||
|
||||
await provider.clearTask()
|
||||
|
||||
expect(mockAbortTask).toHaveBeenCalled()
|
||||
// @ts-ignore - accessing private property for testing
|
||||
expect(provider.cline).toBeUndefined()
|
||||
})
|
||||
|
||||
test('getState returns correct initial state', async () => {
|
||||
const state = await provider.getState()
|
||||
|
||||
expect(state).toHaveProperty('apiConfiguration')
|
||||
expect(state.apiConfiguration).toHaveProperty('apiProvider')
|
||||
expect(state).toHaveProperty('customInstructions')
|
||||
expect(state).toHaveProperty('alwaysAllowReadOnly')
|
||||
expect(state).toHaveProperty('alwaysAllowWrite')
|
||||
expect(state).toHaveProperty('alwaysAllowExecute')
|
||||
expect(state).toHaveProperty('alwaysAllowBrowser')
|
||||
expect(state).toHaveProperty('taskHistory')
|
||||
expect(state).toHaveProperty('soundEnabled')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user