Kaynağa Gözat

chore: remove integration tests (#11598)

* chore: remove integration test files

* chore: remove integration test job from CI workflow

---------

Co-authored-by: Roo Code <[email protected]>
Co-authored-by: Hannes Rudolph <[email protected]>
roomote[bot] 1 gün önce
ebeveyn
işleme
aff46b14e2

+ 0 - 63
.github/workflows/code-qa.yml

@@ -58,66 +58,3 @@ jobs:
               uses: ./.github/actions/setup-node-pnpm
             - name: Run unit tests
               run: pnpm test
-
-    check-openrouter-api-key:
-        runs-on: ubuntu-latest
-        outputs:
-            exists: ${{ steps.openrouter-api-key-check.outputs.defined }}
-        steps:
-            - name: Check if OpenRouter API key exists
-              id: openrouter-api-key-check
-              shell: bash
-              run: |
-                  if [ "${{ secrets.OPENROUTER_API_KEY }}" != '' ]; then
-                    echo "defined=true" >> $GITHUB_OUTPUT;
-                  else
-                    echo "defined=false" >> $GITHUB_OUTPUT;
-                  fi
-
-    integration-test:
-        runs-on: ubuntu-latest
-        needs: [check-openrouter-api-key]
-        if: needs.check-openrouter-api-key.outputs.exists == 'true'
-        steps:
-            - name: Checkout code
-              uses: actions/checkout@v4
-            - name: Setup Node.js and pnpm
-              uses: ./.github/actions/setup-node-pnpm
-            - name: Create .env.local file
-              working-directory: apps/vscode-e2e
-              run: echo "OPENROUTER_API_KEY=${{ secrets.OPENROUTER_API_KEY }}" > .env.local
-            - name: Set VS Code test version
-              run: echo "VSCODE_VERSION=1.101.2" >> $GITHUB_ENV
-            - name: Cache VS Code test runtime
-              uses: actions/cache@v4
-              with:
-                  path: apps/vscode-e2e/.vscode-test
-                  key: ${{ runner.os }}-vscode-test-${{ env.VSCODE_VERSION }}
-            - name: Pre-download VS Code test runtime with retry
-              working-directory: apps/vscode-e2e
-              run: |
-                  for attempt in 1 2 3; do
-                    echo "Download attempt $attempt of 3..."
-                    node -e "
-                    const { downloadAndUnzipVSCode } = require('@vscode/test-electron');
-                    downloadAndUnzipVSCode({ version: process.env.VSCODE_VERSION || '1.101.2' })
-                      .then(() => {
-                        console.log('✅ VS Code test runtime downloaded successfully');
-                        process.exit(0);
-                      })
-                      .catch(err => {
-                        console.error('❌ Failed to download VS Code (attempt $attempt):', err);
-                        process.exit(1);
-                      });
-                    " && break || {
-                      if [ $attempt -eq 3 ]; then
-                        echo "All download attempts failed"
-                        exit 1
-                      fi
-                      echo "Retrying in 5 seconds..."
-                      sleep 5
-                    }
-                  done
-            - name: Run integration tests
-              working-directory: apps/vscode-e2e
-              run: xvfb-run -a pnpm test:ci

+ 0 - 147
packages/cloud/src/__tests__/CloudService.integration.test.ts

@@ -1,147 +0,0 @@
-// npx vitest run src/__tests__/CloudService.integration.test.ts
-
-import type { ExtensionContext } from "vscode"
-
-import { CloudService } from "../CloudService.js"
-import { StaticSettingsService } from "../StaticSettingsService.js"
-import { CloudSettingsService } from "../CloudSettingsService.js"
-
-vi.mock("vscode", () => ({
-	ExtensionContext: vi.fn(),
-	window: {
-		showInformationMessage: vi.fn(),
-		showErrorMessage: vi.fn(),
-	},
-	env: {
-		openExternal: vi.fn(),
-	},
-	Uri: {
-		parse: vi.fn(),
-	},
-}))
-
-describe("CloudService Integration - Settings Service Selection", () => {
-	let mockContext: ExtensionContext
-
-	beforeEach(() => {
-		CloudService.resetInstance()
-
-		mockContext = {
-			subscriptions: [],
-			workspaceState: {
-				get: vi.fn(),
-				update: vi.fn(),
-				keys: vi.fn().mockReturnValue([]),
-			},
-			secrets: {
-				get: vi.fn(),
-				store: vi.fn(),
-				delete: vi.fn(),
-				onDidChange: vi.fn().mockReturnValue({ dispose: vi.fn() }),
-			},
-			globalState: {
-				get: vi.fn(),
-				update: vi.fn(),
-				setKeysForSync: vi.fn(),
-				keys: vi.fn().mockReturnValue([]),
-			},
-			extensionUri: { scheme: "file", path: "/mock/path" },
-			extensionPath: "/mock/path",
-			extensionMode: 1,
-			asAbsolutePath: vi.fn((relativePath: string) => `/mock/path/${relativePath}`),
-			storageUri: { scheme: "file", path: "/mock/storage" },
-			extension: {
-				packageJSON: {
-					version: "1.0.0",
-				},
-			},
-		} as unknown as ExtensionContext
-	})
-
-	afterEach(() => {
-		CloudService.resetInstance()
-		delete process.env.ROO_CODE_CLOUD_ORG_SETTINGS
-		delete process.env.ROO_CODE_CLOUD_TOKEN
-	})
-
-	it("should use CloudSettingsService when no environment variable is set", async () => {
-		// Ensure no environment variables are set
-		delete process.env.ROO_CODE_CLOUD_ORG_SETTINGS
-		delete process.env.ROO_CODE_CLOUD_TOKEN
-
-		const cloudService = await CloudService.createInstance(mockContext)
-
-		// Access the private settingsService to check its type
-		const settingsService = (cloudService as unknown as { settingsService: unknown }).settingsService
-		expect(settingsService).toBeInstanceOf(CloudSettingsService)
-	})
-
-	it("should use StaticSettingsService when ROO_CODE_CLOUD_ORG_SETTINGS is set", async () => {
-		const validSettings = {
-			version: 1,
-			cloudSettings: {
-				recordTaskMessages: true,
-				enableTaskSharing: true,
-				taskShareExpirationDays: 30,
-			},
-			defaultSettings: {
-				enableCheckpoints: true,
-			},
-			allowList: {
-				allowAll: true,
-				providers: {},
-			},
-		}
-
-		// Set the environment variable
-		process.env.ROO_CODE_CLOUD_ORG_SETTINGS = Buffer.from(JSON.stringify(validSettings)).toString("base64")
-
-		const cloudService = await CloudService.createInstance(mockContext)
-
-		// Access the private settingsService to check its type
-		const settingsService = (cloudService as unknown as { settingsService: unknown }).settingsService
-		expect(settingsService).toBeInstanceOf(StaticSettingsService)
-
-		// Verify the settings are correctly loaded
-		expect(cloudService.getAllowList()).toEqual(validSettings.allowList)
-	})
-
-	it("should throw error when ROO_CODE_CLOUD_ORG_SETTINGS contains invalid data", async () => {
-		// Set invalid environment variable
-		process.env.ROO_CODE_CLOUD_ORG_SETTINGS = "invalid-base64-data"
-
-		await expect(CloudService.createInstance(mockContext)).rejects.toThrow("Failed to initialize CloudService")
-	})
-
-	it("should prioritize static token auth when both environment variables are set", async () => {
-		const validSettings = {
-			version: 1,
-			cloudSettings: {
-				recordTaskMessages: true,
-				enableTaskSharing: true,
-				taskShareExpirationDays: 30,
-			},
-			defaultSettings: {
-				enableCheckpoints: true,
-			},
-			allowList: {
-				allowAll: true,
-				providers: {},
-			},
-		}
-
-		// Set both environment variables
-		process.env.ROO_CODE_CLOUD_TOKEN = "test-token"
-		process.env.ROO_CODE_CLOUD_ORG_SETTINGS = Buffer.from(JSON.stringify(validSettings)).toString("base64")
-
-		const cloudService = await CloudService.createInstance(mockContext)
-
-		// Should use StaticSettingsService for settings
-		const settingsService = (cloudService as unknown as { settingsService: unknown }).settingsService
-		expect(settingsService).toBeInstanceOf(StaticSettingsService)
-
-		// Should use StaticTokenAuthService for auth (from the existing logic)
-		expect(cloudService.isAuthenticated()).toBe(true)
-		expect(cloudService.hasActiveSession()).toBe(true)
-	})
-})

+ 0 - 406
src/core/tools/__tests__/executeCommandTimeout.integration.spec.ts

@@ -1,406 +0,0 @@
-// Integration tests for command execution timeout functionality
-// npx vitest run src/core/tools/__tests__/executeCommandTimeout.integration.spec.ts
-
-import * as vscode from "vscode"
-import * as fs from "fs/promises"
-import { executeCommandInTerminal, executeCommandTool, ExecuteCommandOptions } from "../ExecuteCommandTool"
-import { Task } from "../../task/Task"
-import { TerminalRegistry } from "../../../integrations/terminal/TerminalRegistry"
-
-// Mock dependencies
-vitest.mock("vscode", () => ({
-	workspace: {
-		getConfiguration: vitest.fn(),
-	},
-}))
-
-vitest.mock("fs/promises")
-vitest.mock("../../../integrations/terminal/TerminalRegistry")
-vitest.mock("../../task/Task")
-vitest.mock("../../prompts/responses", () => ({
-	formatResponse: {
-		toolError: vitest.fn((msg) => `Tool Error: ${msg}`),
-		rooIgnoreError: vitest.fn((msg) => `RooIgnore Error: ${msg}`),
-	},
-}))
-vitest.mock("../../../utils/text-normalization", () => ({
-	unescapeHtmlEntities: vitest.fn((text) => text),
-}))
-vitest.mock("../../../shared/package", () => ({
-	Package: {
-		name: "roo-cline",
-	},
-}))
-
-describe("Command Execution Timeout Integration", () => {
-	let mockTask: any
-	let mockTerminal: any
-	let mockProcess: any
-
-	beforeEach(() => {
-		vitest.clearAllMocks()
-
-		// Mock fs.access to resolve successfully for working directory
-		;(fs.access as any).mockResolvedValue(undefined)
-
-		// Mock task
-		mockTask = {
-			cwd: "/test/directory",
-			terminalProcess: undefined,
-			providerRef: {
-				deref: vitest.fn().mockResolvedValue({
-					postMessageToWebview: vitest.fn(),
-				}),
-			},
-			say: vitest.fn().mockResolvedValue(undefined),
-		}
-
-		// Mock terminal process
-		mockProcess = {
-			abort: vitest.fn(),
-			then: vitest.fn(),
-			catch: vitest.fn(),
-		}
-
-		// Mock terminal
-		mockTerminal = {
-			runCommand: vitest.fn().mockReturnValue(mockProcess),
-			getCurrentWorkingDirectory: vitest.fn().mockReturnValue("/test/directory"),
-		}
-
-		// Mock TerminalRegistry
-		;(TerminalRegistry.getOrCreateTerminal as any).mockResolvedValue(mockTerminal)
-
-		// Mock VSCode configuration
-		const mockGetConfiguration = vitest.fn().mockReturnValue({
-			get: vitest.fn().mockReturnValue(0), // Default 0 (no timeout)
-		})
-		;(vscode.workspace.getConfiguration as any).mockReturnValue(mockGetConfiguration())
-	})
-
-	it("should pass timeout configuration to executeCommand", async () => {
-		const customTimeoutMs = 15000 // 15 seconds in milliseconds
-		const options: ExecuteCommandOptions = {
-			executionId: "test-execution",
-			command: "echo test",
-			commandExecutionTimeout: customTimeoutMs,
-		}
-
-		// Mock a quick-completing process
-		const quickProcess = Promise.resolve()
-		mockTerminal.runCommand.mockReturnValue(quickProcess)
-
-		await executeCommandInTerminal(mockTask as Task, options)
-
-		// Verify that the terminal was called with the command
-		expect(mockTerminal.runCommand).toHaveBeenCalledWith("echo test", expect.any(Object))
-	})
-
-	it("should handle timeout scenario", async () => {
-		const shortTimeoutMs = 100 // Very short timeout in milliseconds
-		const options: ExecuteCommandOptions = {
-			executionId: "test-execution",
-			command: "sleep 10",
-			commandExecutionTimeout: shortTimeoutMs,
-		}
-
-		// Create a process that never resolves but has an abort method
-		const longRunningProcess = new Promise(() => {
-			// Never resolves to simulate a hanging command
-		})
-
-		// Add abort method to the promise
-		;(longRunningProcess as any).abort = vitest.fn()
-
-		mockTerminal.runCommand.mockReturnValue(longRunningProcess)
-
-		// Execute with timeout
-		const result = await executeCommandInTerminal(mockTask as Task, options)
-
-		// Should return timeout error
-		expect(result[0]).toBe(false) // Not rejected by user
-		expect(result[1]).toContain("terminated after exceeding")
-		expect(result[1]).toContain("0.1s") // Should show seconds in error message
-	}, 10000) // Increase test timeout to 10 seconds
-
-	it("should abort process on timeout", async () => {
-		const shortTimeoutMs = 50 // Short timeout in milliseconds
-		const options: ExecuteCommandOptions = {
-			executionId: "test-execution",
-			command: "sleep 10",
-			commandExecutionTimeout: shortTimeoutMs,
-		}
-
-		// Create a process that can be aborted
-		const abortSpy = vitest.fn()
-
-		// Mock the process to never resolve but be abortable
-		const neverResolvingPromise = new Promise(() => {})
-		;(neverResolvingPromise as any).abort = abortSpy
-
-		mockTerminal.runCommand.mockReturnValue(neverResolvingPromise)
-
-		await executeCommandInTerminal(mockTask as Task, options)
-
-		// Verify abort was called
-		expect(abortSpy).toHaveBeenCalled()
-	}, 5000) // Increase test timeout to 5 seconds
-
-	it("should clean up timeout on successful completion", async () => {
-		const options: ExecuteCommandOptions = {
-			executionId: "test-execution",
-			command: "echo test",
-			commandExecutionTimeout: 5000,
-		}
-
-		// Mock a process that completes quickly
-		const quickProcess = Promise.resolve()
-		mockTerminal.runCommand.mockReturnValue(quickProcess)
-
-		const result = await executeCommandInTerminal(mockTask as Task, options)
-
-		// Should complete successfully without timeout
-		expect(result[0]).toBe(false) // Not rejected
-		expect(result[1]).not.toContain("terminated after exceeding")
-	})
-
-	it("should use default timeout when not specified (0 = no timeout)", async () => {
-		const options: ExecuteCommandOptions = {
-			executionId: "test-execution",
-			command: "echo test",
-			// commandExecutionTimeout not specified, should use default (0)
-		}
-
-		const quickProcess = Promise.resolve()
-		mockTerminal.runCommand.mockReturnValue(quickProcess)
-
-		await executeCommandInTerminal(mockTask as Task, options)
-
-		// Should complete without issues using default (no timeout)
-		expect(mockTerminal.runCommand).toHaveBeenCalled()
-	})
-
-	it("should not timeout when commandExecutionTimeout is 0", async () => {
-		const options: ExecuteCommandOptions = {
-			executionId: "test-execution",
-			command: "sleep 10",
-			commandExecutionTimeout: 0, // No timeout
-		}
-
-		// Create a process that resolves after a delay to simulate a long-running command
-		const longRunningProcess = new Promise((resolve) => {
-			setTimeout(resolve, 200) // 200ms delay
-		})
-
-		mockTerminal.runCommand.mockReturnValue(longRunningProcess)
-
-		const result = await executeCommandInTerminal(mockTask as Task, options)
-
-		// Should complete successfully without timeout
-		expect(result[0]).toBe(false) // Not rejected
-		expect(result[1]).not.toContain("terminated after exceeding")
-	})
-
-	describe("Command Timeout Allowlist", () => {
-		let mockBlock: any
-		let mockAskApproval: any
-		let mockHandleError: any
-		let mockPushToolResult: any
-
-		beforeEach(() => {
-			// Reset mocks for allowlist tests
-			vitest.clearAllMocks()
-			;(fs.access as any).mockResolvedValue(undefined)
-			;(TerminalRegistry.getOrCreateTerminal as any).mockResolvedValue(mockTerminal)
-
-			// Mock the executeCommandTool parameters
-			mockBlock = {
-				type: "tool_use",
-				name: "execute_command",
-				params: {
-					command: "",
-					cwd: undefined,
-				},
-				nativeArgs: {
-					command: "",
-					cwd: undefined,
-				},
-				partial: false,
-			}
-
-			mockAskApproval = vitest.fn().mockResolvedValue(true) // Always approve
-			mockHandleError = vitest.fn()
-			mockPushToolResult = vitest.fn()
-
-			// Mock task with additional properties needed by executeCommandTool
-			mockTask = {
-				cwd: "/test/directory",
-				terminalProcess: undefined,
-				providerRef: {
-					deref: vitest.fn().mockResolvedValue({
-						postMessageToWebview: vitest.fn(),
-						getState: vitest.fn().mockResolvedValue({
-							terminalOutputLineLimit: 500,
-							terminalShellIntegrationDisabled: false,
-						}),
-					}),
-				},
-				say: vitest.fn().mockResolvedValue(undefined),
-				consecutiveMistakeCount: 0,
-				recordToolError: vitest.fn(),
-				sayAndCreateMissingParamError: vitest.fn(),
-				rooIgnoreController: {
-					validateCommand: vitest.fn().mockReturnValue(null),
-				},
-				lastMessageTs: Date.now(),
-				ask: vitest.fn(),
-				didRejectTool: false,
-			}
-		})
-
-		it("should skip timeout for commands in allowlist", async () => {
-			// Mock VSCode configuration with timeout and allowlist
-			const mockGetConfiguration = vitest.fn().mockReturnValue({
-				get: vitest.fn().mockImplementation((key: string) => {
-					if (key === "commandExecutionTimeout") return 1 // 1 second timeout
-					if (key === "commandTimeoutAllowlist") return ["npm", "git"]
-					return undefined
-				}),
-			})
-			;(vscode.workspace.getConfiguration as any).mockReturnValue(mockGetConfiguration())
-
-			mockBlock.params.command = "npm install"
-			mockBlock.nativeArgs.command = "npm install"
-
-			// Create a process that would timeout if not allowlisted
-			const longRunningProcess = new Promise((resolve) => {
-				setTimeout(resolve, 2000) // 2 seconds, longer than 1 second timeout
-			})
-			mockTerminal.runCommand.mockReturnValue(longRunningProcess)
-
-			await executeCommandTool.handle(mockTask as Task, mockBlock, {
-				askApproval: mockAskApproval,
-				handleError: mockHandleError,
-				pushToolResult: mockPushToolResult,
-			})
-
-			// Should complete successfully without timeout because "npm" is in allowlist
-			expect(mockPushToolResult).toHaveBeenCalled()
-			const result = mockPushToolResult.mock.calls[0][0]
-			expect(result).not.toContain("terminated after exceeding")
-		}, 3000)
-
-		it("should apply timeout for commands not in allowlist", async () => {
-			// Mock VSCode configuration with timeout and allowlist
-			const mockGetConfiguration = vitest.fn().mockReturnValue({
-				get: vitest.fn().mockImplementation((key: string) => {
-					if (key === "commandExecutionTimeout") return 1 // 1 second timeout
-					if (key === "commandTimeoutAllowlist") return ["npm", "git"]
-					return undefined
-				}),
-			})
-			;(vscode.workspace.getConfiguration as any).mockReturnValue(mockGetConfiguration())
-
-			mockBlock.params.command = "sleep 10" // Not in allowlist
-			mockBlock.nativeArgs.command = "sleep 10"
-
-			// Create a process that never resolves
-			const neverResolvingProcess = new Promise(() => {})
-			;(neverResolvingProcess as any).abort = vitest.fn()
-			mockTerminal.runCommand.mockReturnValue(neverResolvingProcess)
-
-			await executeCommandTool.handle(mockTask as Task, mockBlock, {
-				askApproval: mockAskApproval,
-				handleError: mockHandleError,
-				pushToolResult: mockPushToolResult,
-			})
-
-			// Should timeout because "sleep" is not in allowlist
-			expect(mockPushToolResult).toHaveBeenCalled()
-			const result = mockPushToolResult.mock.calls[0][0]
-			expect(result).toContain("terminated after exceeding")
-		}, 3000)
-
-		it("should handle empty allowlist", async () => {
-			// Mock VSCode configuration with timeout and empty allowlist
-			const mockGetConfiguration = vitest.fn().mockReturnValue({
-				get: vitest.fn().mockImplementation((key: string) => {
-					if (key === "commandExecutionTimeout") return 1 // 1 second timeout
-					if (key === "commandTimeoutAllowlist") return []
-					return undefined
-				}),
-			})
-			;(vscode.workspace.getConfiguration as any).mockReturnValue(mockGetConfiguration())
-
-			mockBlock.params.command = "npm install"
-			mockBlock.nativeArgs.command = "npm install"
-
-			// Create a process that never resolves
-			const neverResolvingProcess = new Promise(() => {})
-			;(neverResolvingProcess as any).abort = vitest.fn()
-			mockTerminal.runCommand.mockReturnValue(neverResolvingProcess)
-
-			await executeCommandTool.handle(mockTask as Task, mockBlock, {
-				askApproval: mockAskApproval,
-				handleError: mockHandleError,
-				pushToolResult: mockPushToolResult,
-			})
-
-			// Should timeout because allowlist is empty
-			expect(mockPushToolResult).toHaveBeenCalled()
-			const result = mockPushToolResult.mock.calls[0][0]
-			expect(result).toContain("terminated after exceeding")
-		}, 3000)
-
-		it("should match command prefixes correctly", async () => {
-			// Mock VSCode configuration with timeout and allowlist
-			const mockGetConfiguration = vitest.fn().mockReturnValue({
-				get: vitest.fn().mockImplementation((key: string) => {
-					if (key === "commandExecutionTimeout") return 1 // 1 second timeout
-					if (key === "commandTimeoutAllowlist") return ["git log", "npm run"]
-					return undefined
-				}),
-			})
-			;(vscode.workspace.getConfiguration as any).mockReturnValue(mockGetConfiguration())
-
-			const longRunningProcess = new Promise((resolve) => {
-				setTimeout(resolve, 2000) // 2 seconds
-			})
-			const neverResolvingProcess = new Promise(() => {})
-			;(neverResolvingProcess as any).abort = vitest.fn()
-
-			// Test exact prefix match - should not timeout
-			mockBlock.params.command = "git log --oneline"
-			mockBlock.nativeArgs.command = "git log --oneline"
-			mockTerminal.runCommand.mockReturnValueOnce(longRunningProcess)
-
-			await executeCommandTool.handle(mockTask as Task, mockBlock, {
-				askApproval: mockAskApproval,
-				handleError: mockHandleError,
-				pushToolResult: mockPushToolResult,
-			})
-
-			expect(mockPushToolResult).toHaveBeenCalled()
-			const result1 = mockPushToolResult.mock.calls[0][0]
-			expect(result1).not.toContain("terminated after exceeding")
-
-			// Reset mocks for second test
-			mockPushToolResult.mockClear()
-
-			// Test partial prefix match (should not match) - should timeout
-			mockBlock.params.command = "git status" // "git" alone is not in allowlist, only "git log"
-			mockBlock.nativeArgs.command = "git status"
-			mockTerminal.runCommand.mockReturnValueOnce(neverResolvingProcess)
-
-			await executeCommandTool.handle(mockTask as Task, mockBlock, {
-				askApproval: mockAskApproval,
-				handleError: mockHandleError,
-				pushToolResult: mockPushToolResult,
-			})
-
-			expect(mockPushToolResult).toHaveBeenCalled()
-			const result2 = mockPushToolResult.mock.calls[0][0]
-			expect(result2).toContain("terminated after exceeding")
-		}, 5000)
-	})
-})

+ 0 - 130
src/core/webview/__tests__/webviewMessageHandler.imageMentions.integration.spec.ts

@@ -1,130 +0,0 @@
-import * as fs from "fs/promises"
-import * as path from "path"
-import * as os from "os"
-
-// Must mock dependencies before importing the handler module.
-vi.mock("../../../api/providers/fetchers/modelCache")
-
-import { webviewMessageHandler } from "../webviewMessageHandler"
-import type { ClineProvider } from "../ClineProvider"
-
-vi.mock("vscode", () => ({
-	window: {
-		showInformationMessage: vi.fn(),
-		showErrorMessage: vi.fn(),
-	},
-	workspace: {
-		workspaceFolders: [{ uri: { fsPath: "/mock/workspace" } }],
-	},
-}))
-
-// Mock imageHelpers - use actual implementations for functions that need real file access
-vi.mock("../../tools/helpers/imageHelpers", async (importOriginal) => {
-	const actual = await importOriginal<typeof import("../../tools/helpers/imageHelpers")>()
-	return {
-		...actual,
-		validateImageForProcessing: vi.fn().mockResolvedValue({ isValid: true, sizeInMB: 0.001 }),
-		ImageMemoryTracker: vi.fn().mockImplementation(() => ({
-			getTotalMemoryUsed: vi.fn().mockReturnValue(0),
-			addMemoryUsage: vi.fn(),
-		})),
-	}
-})
-
-describe("webviewMessageHandler - image mentions (integration)", () => {
-	it("resolves image mentions for newTask and passes images to createTask", async () => {
-		const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "roo-image-mentions-"))
-		try {
-			const imgBytes = Buffer.from("png-bytes")
-			await fs.writeFile(path.join(tmpRoot, "cat.png"), imgBytes)
-
-			const mockProvider = {
-				cwd: tmpRoot,
-				getCurrentTask: vi.fn().mockReturnValue(undefined),
-				createTask: vi.fn().mockResolvedValue(undefined),
-				postMessageToWebview: vi.fn().mockResolvedValue(undefined),
-				getState: vi.fn().mockResolvedValue({
-					maxImageFileSize: 5,
-					maxTotalImageSize: 20,
-				}),
-			} as unknown as ClineProvider
-
-			await webviewMessageHandler(mockProvider, {
-				type: "newTask",
-				text: "Please look at @/cat.png",
-				images: [],
-			} as any)
-
-			expect(mockProvider.createTask).toHaveBeenCalledWith("Please look at @/cat.png", [
-				`data:image/png;base64,${imgBytes.toString("base64")}`,
-			])
-		} finally {
-			await fs.rm(tmpRoot, { recursive: true, force: true })
-		}
-	})
-
-	it("resolves image mentions for askResponse and passes images to handleWebviewAskResponse", async () => {
-		const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "roo-image-mentions-"))
-		try {
-			const imgBytes = Buffer.from("jpg-bytes")
-			await fs.writeFile(path.join(tmpRoot, "cat.jpg"), imgBytes)
-
-			const handleWebviewAskResponse = vi.fn()
-			const mockProvider = {
-				cwd: tmpRoot,
-				getCurrentTask: vi.fn().mockReturnValue({
-					cwd: tmpRoot,
-					handleWebviewAskResponse,
-				}),
-				getState: vi.fn().mockResolvedValue({
-					maxImageFileSize: 5,
-					maxTotalImageSize: 20,
-				}),
-			} as unknown as ClineProvider
-
-			await webviewMessageHandler(mockProvider, {
-				type: "askResponse",
-				askResponse: "messageResponse",
-				text: "Please look at @/cat.jpg",
-				images: [],
-			} as any)
-
-			expect(handleWebviewAskResponse).toHaveBeenCalledWith("messageResponse", "Please look at @/cat.jpg", [
-				`data:image/jpeg;base64,${imgBytes.toString("base64")}`,
-			])
-		} finally {
-			await fs.rm(tmpRoot, { recursive: true, force: true })
-		}
-	})
-
-	it("resolves gif image mentions (matching read_file behavior)", async () => {
-		const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "roo-image-mentions-"))
-		try {
-			const imgBytes = Buffer.from("gif-bytes")
-			await fs.writeFile(path.join(tmpRoot, "animation.gif"), imgBytes)
-
-			const mockProvider = {
-				cwd: tmpRoot,
-				getCurrentTask: vi.fn().mockReturnValue(undefined),
-				createTask: vi.fn().mockResolvedValue(undefined),
-				postMessageToWebview: vi.fn().mockResolvedValue(undefined),
-				getState: vi.fn().mockResolvedValue({
-					maxImageFileSize: 5,
-					maxTotalImageSize: 20,
-				}),
-			} as unknown as ClineProvider
-
-			await webviewMessageHandler(mockProvider, {
-				type: "newTask",
-				text: "See @/animation.gif",
-				images: [],
-			} as any)
-
-			expect(mockProvider.createTask).toHaveBeenCalledWith("See @/animation.gif", [
-				`data:image/gif;base64,${imgBytes.toString("base64")}`,
-			])
-		} finally {
-			await fs.rm(tmpRoot, { recursive: true, force: true })
-		}
-	})
-})