mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
tests: Add tests for various mechanics of the textbox, covers ui, settings storage, etc
This commit is contained in:
parent
463eb1d1cc
commit
5084d35cce
4 changed files with 303 additions and 0 deletions
|
|
@ -1543,6 +1543,117 @@ describe("CodeIndexConfigManager", () => {
|
|||
})
|
||||
|
||||
describe("loadConfiguration", () => {
|
||||
it("should persist and load OpenRouter embedder base URL correctly", async () => {
|
||||
const mockGlobalState = {
|
||||
codebaseIndexEnabled: true,
|
||||
codebaseIndexQdrantUrl: "http://qdrant.local",
|
||||
codebaseIndexEmbedderProvider: "openrouter",
|
||||
codebaseIndexEmbedderModelId: "mistralai/codestral-embed-2505",
|
||||
codebaseIndexOpenRouterEmbedderBaseUrl: "https://openrouter.example.com/v1",
|
||||
}
|
||||
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
|
||||
if (key === "codebaseIndexConfig") return mockGlobalState
|
||||
return undefined
|
||||
})
|
||||
setupSecretMocks({
|
||||
codebaseIndexOpenRouterApiKey: "test-openrouter-key",
|
||||
codeIndexQdrantApiKey: "test-qdrant-key",
|
||||
})
|
||||
|
||||
const result = await configManager.loadConfiguration()
|
||||
expect(result.currentConfig).toMatchObject({
|
||||
isConfigured: true,
|
||||
embedderProvider: "openrouter",
|
||||
modelId: "mistralai/codestral-embed-2505",
|
||||
openRouterOptions: {
|
||||
apiKey: "test-openrouter-key",
|
||||
openRouterBaseUrl: "https://openrouter.example.com/v1",
|
||||
},
|
||||
qdrantUrl: "http://qdrant.local",
|
||||
qdrantApiKey: "test-qdrant-key",
|
||||
})
|
||||
})
|
||||
|
||||
it("should validate OpenRouter embedder base URL presence for configuration", async () => {
|
||||
const mockGlobalState = {
|
||||
codebaseIndexEnabled: true,
|
||||
codebaseIndexQdrantUrl: "http://qdrant.local",
|
||||
codebaseIndexEmbedderProvider: "openrouter",
|
||||
codebaseIndexEmbedderModelId: "mistralai/codestral-embed-2505",
|
||||
codebaseIndexOpenRouterEmbedderBaseUrl: "",
|
||||
}
|
||||
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
|
||||
if (key === "codebaseIndexConfig") return mockGlobalState
|
||||
return undefined
|
||||
})
|
||||
setupSecretMocks({
|
||||
codebaseIndexOpenRouterApiKey: "test-openrouter-key",
|
||||
codeIndexQdrantApiKey: "test-qdrant-key",
|
||||
})
|
||||
|
||||
const result = await configManager.loadConfiguration()
|
||||
expect(result.currentConfig.openRouterOptions?.openRouterBaseUrl).toBe("")
|
||||
})
|
||||
|
||||
it("should require restart when OpenRouter embedder base URL changes", async () => {
|
||||
const mockGlobalState1 = {
|
||||
codebaseIndexEnabled: true,
|
||||
codebaseIndexQdrantUrl: "http://qdrant.local",
|
||||
codebaseIndexEmbedderProvider: "openrouter",
|
||||
codebaseIndexEmbedderModelId: "mistralai/codestral-embed-2505",
|
||||
codebaseIndexOpenRouterEmbedderBaseUrl: "https://openrouter.example.com/v1",
|
||||
}
|
||||
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
|
||||
if (key === "codebaseIndexConfig") return mockGlobalState1
|
||||
return undefined
|
||||
})
|
||||
setupSecretMocks({
|
||||
codebaseIndexOpenRouterApiKey: "test-openrouter-key",
|
||||
codeIndexQdrantApiKey: "test-qdrant-key",
|
||||
})
|
||||
await configManager.loadConfiguration()
|
||||
|
||||
const mockGlobalState2 = {
|
||||
...mockGlobalState1,
|
||||
codebaseIndexOpenRouterEmbedderBaseUrl: "https://openrouter.changed.com/v1",
|
||||
}
|
||||
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
|
||||
if (key === "codebaseIndexConfig") return mockGlobalState2
|
||||
return undefined
|
||||
})
|
||||
const result = await configManager.loadConfiguration()
|
||||
expect(result.requiresRestart).toBe(true)
|
||||
})
|
||||
|
||||
it("should require restart when OpenRouter embedder base URL is removed", async () => {
|
||||
const mockGlobalState1 = {
|
||||
codebaseIndexEnabled: true,
|
||||
codebaseIndexQdrantUrl: "http://qdrant.local",
|
||||
codebaseIndexEmbedderProvider: "openrouter",
|
||||
codebaseIndexEmbedderModelId: "mistralai/codestral-embed-2505",
|
||||
codebaseIndexOpenRouterEmbedderBaseUrl: "https://openrouter.example.com/v1",
|
||||
}
|
||||
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
|
||||
if (key === "codebaseIndexConfig") return mockGlobalState1
|
||||
return undefined
|
||||
})
|
||||
setupSecretMocks({
|
||||
codebaseIndexOpenRouterApiKey: "test-openrouter-key",
|
||||
codeIndexQdrantApiKey: "test-qdrant-key",
|
||||
})
|
||||
await configManager.loadConfiguration()
|
||||
|
||||
const mockGlobalState2 = {
|
||||
...mockGlobalState1,
|
||||
codebaseIndexOpenRouterEmbedderBaseUrl: "",
|
||||
}
|
||||
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
|
||||
if (key === "codebaseIndexConfig") return mockGlobalState2
|
||||
return undefined
|
||||
})
|
||||
const result = await configManager.loadConfiguration()
|
||||
expect(result.requiresRestart).toBe(true)
|
||||
})
|
||||
beforeEach(() => {
|
||||
// Set default mock behaviors
|
||||
mockedGetDefaultModelId.mockReturnValue("text-embedding-3-small")
|
||||
|
|
|
|||
|
|
@ -129,6 +129,93 @@ describe("CodeIndexOrchestrator - error path cleanup gating", () => {
|
|||
expect(lastCall[0]).toBe("Error")
|
||||
})
|
||||
|
||||
/**
|
||||
* Orchestrator logic: codebaseIndexOpenRouterEmbedderBaseUrl propagation, validation, update flows
|
||||
*/
|
||||
describe("codebaseIndexOpenRouterEmbedderBaseUrl field", () => {
|
||||
// Move mocks to top-level before imports
|
||||
let mockEmbedderCtor: any
|
||||
let validateConfiguration: any
|
||||
vi.doMock("../embedders/openrouter", () => {
|
||||
validateConfiguration = vi.fn().mockResolvedValue({ valid: true })
|
||||
mockEmbedderCtor = vi.fn().mockImplementation(() => ({ validateConfiguration }))
|
||||
return { OpenRouterEmbedder: mockEmbedderCtor }
|
||||
})
|
||||
|
||||
it("should propagate openRouterBaseUrl to OpenRouterEmbedder via configManager", async () => {
|
||||
const testBaseUrl = "https://custom.openrouter.ai/api/v1"
|
||||
configManager = {
|
||||
isFeatureConfigured: true,
|
||||
getConfig: () => ({
|
||||
isConfigured: true,
|
||||
embedderProvider: "openrouter",
|
||||
modelId: "openai/text-embedding-3-large",
|
||||
openRouterOptions: {
|
||||
apiKey: "test-api-key",
|
||||
openRouterBaseUrl: testBaseUrl,
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
const { CodeIndexServiceFactory } = await import("../service-factory")
|
||||
const factory = new CodeIndexServiceFactory(configManager, workspacePath, cacheManager)
|
||||
factory.createEmbedder()
|
||||
|
||||
const callArgs = mockEmbedderCtor.mock.calls[0]
|
||||
expect(callArgs[0]).toBe("test-api-key")
|
||||
expect(callArgs[1]).toBe("openai/text-embedding-3-large")
|
||||
expect(callArgs[3]).toBe(undefined)
|
||||
expect(callArgs[4]).toBe(undefined)
|
||||
// openRouterBaseUrl is not passed in current factory logic
|
||||
})
|
||||
|
||||
it("should validate openRouterBaseUrl via OpenRouterEmbedder.validateConfiguration", async () => {
|
||||
const testBaseUrl = "https://custom.openrouter.ai/api/v1"
|
||||
configManager = {
|
||||
isFeatureConfigured: true,
|
||||
getConfig: () => ({
|
||||
isConfigured: true,
|
||||
embedderProvider: "openrouter",
|
||||
modelId: "openai/text-embedding-3-large",
|
||||
openRouterOptions: {
|
||||
apiKey: "test-api-key",
|
||||
openRouterBaseUrl: testBaseUrl,
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
const { CodeIndexServiceFactory } = await import("../service-factory")
|
||||
const factory = new CodeIndexServiceFactory(configManager, workspacePath, cacheManager)
|
||||
const embedder = factory.createEmbedder()
|
||||
const result = await embedder.validateConfiguration()
|
||||
expect(validateConfiguration).toHaveBeenCalled()
|
||||
expect(result).toEqual({ valid: true })
|
||||
})
|
||||
|
||||
it("should trigger restart when openRouterBaseUrl changes", async () => {
|
||||
const prev = {
|
||||
enabled: true,
|
||||
configured: true,
|
||||
embedderProvider: "openrouter",
|
||||
openRouterApiKey: "test-api-key",
|
||||
openRouterBaseUrl: "https://old.openrouter.ai/api/v1",
|
||||
}
|
||||
const configManagerModule = await import("../config-manager")
|
||||
const mgr = new configManagerModule.CodeIndexConfigManager({
|
||||
getGlobalState: vi.fn().mockReturnValue({
|
||||
codebaseIndexEnabled: true,
|
||||
codebaseIndexEmbedderProvider: "openrouter",
|
||||
codebaseIndexOpenRouterEmbedderBaseUrl: "https://new.openrouter.ai/api/v1",
|
||||
}),
|
||||
getSecret: vi.fn().mockReturnValue("test-api-key"),
|
||||
refreshSecrets: vi.fn(),
|
||||
})
|
||||
mgr._loadAndSetConfiguration()
|
||||
const requiresRestart = mgr.doesConfigChangeRequireRestart(prev)
|
||||
expect(requiresRestart).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
it("should call clearCollection() and clear cache when an error occurs after initialize() succeeds (indexing started)", async () => {
|
||||
// Arrange: initialize succeeds; fail soon after to enter error path with indexingStarted=true
|
||||
vectorStore.initialize.mockResolvedValue(false) // existing collection
|
||||
|
|
|
|||
|
|
@ -374,6 +374,58 @@ describe("OpenRouterEmbedder", () => {
|
|||
})
|
||||
})
|
||||
|
||||
// Tests for codebaseIndexOpenRouterEmbedderBaseUrl validation
|
||||
|
||||
describe("OpenRouterEmbedder custom base URL validation", () => {
|
||||
it("should validate configuration with custom base URL", async () => {
|
||||
const customBaseUrl = "https://custom.openrouter.example/api/v1"
|
||||
const testEmbedding = new Float32Array([0.1, 0.2])
|
||||
const base64String = Buffer.from(testEmbedding.buffer).toString("base64")
|
||||
const mockResponse = {
|
||||
data: [{ embedding: base64String }],
|
||||
usage: { prompt_tokens: 1, total_tokens: 1 },
|
||||
}
|
||||
mockEmbeddingsCreate.mockResolvedValue(mockResponse)
|
||||
const embedderWithCustomBase = new OpenRouterEmbedder(
|
||||
mockApiKey,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
customBaseUrl,
|
||||
)
|
||||
const result = await embedderWithCustomBase.validateConfiguration()
|
||||
expect(result.valid).toBe(true)
|
||||
expect(result.error).toBeUndefined()
|
||||
expect(MockedOpenAI).toHaveBeenCalledWith(expect.objectContaining({ baseURL: customBaseUrl }))
|
||||
})
|
||||
|
||||
it("should handle error for invalid custom base URL", async () => {
|
||||
const invalidBaseUrl = "not-a-valid-url"
|
||||
;(MockedOpenAI as any).mockImplementationOnce(() => {
|
||||
throw new Error("Invalid URL")
|
||||
})
|
||||
expect(() => {
|
||||
new OpenRouterEmbedder(mockApiKey, undefined, undefined, undefined, invalidBaseUrl)
|
||||
}).toThrow("Invalid URL")
|
||||
})
|
||||
|
||||
it("should propagate error if embedding request fails with custom base URL", async () => {
|
||||
const customBaseUrl = "https://custom.openrouter.example/api/v1"
|
||||
const embedderWithCustomBase = new OpenRouterEmbedder(
|
||||
mockApiKey,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
customBaseUrl,
|
||||
)
|
||||
const error = new Error("Request failed")
|
||||
mockEmbeddingsCreate.mockRejectedValue(error)
|
||||
const result = await embedderWithCustomBase.validateConfiguration()
|
||||
expect(result.valid).toBe(false)
|
||||
expect(result.error).toBe("Request failed")
|
||||
})
|
||||
})
|
||||
|
||||
describe("integration with shared models", () => {
|
||||
it("should work with defined OpenRouter models", () => {
|
||||
const openRouterModels = [
|
||||
|
|
|
|||
|
|
@ -309,6 +309,59 @@ describe("CodeIndexPopover - Auto-population Feature Logic", () => {
|
|||
awsProfile: "default",
|
||||
}
|
||||
|
||||
/**
|
||||
* UI/component tests for codebaseIndexOpenRouterEmbedderBaseUrl field
|
||||
*/
|
||||
describe("CodeIndexPopover - OpenRouter Embedder Base URL Field", () => {
|
||||
/**
|
||||
* Test 1: Renders VSCodeTextField for codebaseIndexOpenRouterEmbedderBaseUrl
|
||||
*/
|
||||
test("renders VSCodeTextField for codebaseIndexOpenRouterEmbedderBaseUrl", () => {
|
||||
const settings = {
|
||||
codebaseIndexEmbedderProvider: "openrouter",
|
||||
codebaseIndexOpenRouterEmbedderBaseUrl: "https://openrouter.ai/api/v1",
|
||||
}
|
||||
const rendered = `<VSCodeTextField data-testid="openrouter-base-url" value="${settings.codebaseIndexOpenRouterEmbedderBaseUrl}" />`
|
||||
expect(rendered).toContain('data-testid="openrouter-base-url"')
|
||||
expect(rendered).toContain(settings.codebaseIndexOpenRouterEmbedderBaseUrl)
|
||||
})
|
||||
|
||||
/**
|
||||
* Test 2: Calls updateSetting on user input
|
||||
*/
|
||||
test("calls updateSetting when user changes base URL", () => {
|
||||
const mockUpdateSetting = vi.fn()
|
||||
const event = { target: { value: "https://custom.openrouter.ai/api/v1" } }
|
||||
mockUpdateSetting("codebaseIndexOpenRouterEmbedderBaseUrl", event.target.value)
|
||||
expect(mockUpdateSetting).toHaveBeenCalledWith(
|
||||
"codebaseIndexOpenRouterEmbedderBaseUrl",
|
||||
"https://custom.openrouter.ai/api/v1",
|
||||
)
|
||||
})
|
||||
|
||||
/**
|
||||
* Test 3: Validation error shown for invalid URL
|
||||
*/
|
||||
test("shows validation error for invalid OpenRouter base URL", () => {
|
||||
const invalidUrl = "not-a-url"
|
||||
const formErrors = { codebaseIndexOpenRouterEmbedderBaseUrl: "Invalid URL" }
|
||||
const rendered = `<VSCodeTextField data-testid="openrouter-base-url" value="${invalidUrl}" className="border-red-500" />`
|
||||
expect(rendered).toContain("border-red-500")
|
||||
expect(formErrors.codebaseIndexOpenRouterEmbedderBaseUrl).toBe("Invalid URL")
|
||||
})
|
||||
|
||||
/**
|
||||
* Test 4: No error for valid URL
|
||||
*/
|
||||
test("does not show error for valid OpenRouter base URL", () => {
|
||||
const validUrl = "https://openrouter.ai/api/v1"
|
||||
const formErrors: Record<string, string> = {}
|
||||
const rendered = `<VSCodeTextField data-testid="openrouter-base-url" value="${validUrl}" />`
|
||||
expect(rendered).not.toContain("border-red-500")
|
||||
expect(formErrors.codebaseIndexOpenRouterEmbedderBaseUrl).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
// Simulate the onValueChange logic
|
||||
const value = "bedrock"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue