Roo-Code/src/__tests__/extension.spec.ts
roomote[bot] d00f1a2bb8
feat: remove Roomote Control from extension (#11271)
* feat: remove Roomote Control from extension

Remove all Roomote Control (remote control) functionality:

- Remove BridgeOrchestrator and entire bridge directory from @roo-code/cloud
- Remove remoteControlEnabled, featureRoomoteControlEnabled from extension state
- Remove extensionBridgeEnabled from CloudUserInfo and user settings
- Remove roomoteControlEnabled from organization/user feature schemas
- Remove enableBridge from Task and ClineProvider
- Remove remote control toggle from CloudView UI
- Remove remoteControlEnabled message handler
- Remove extension bridge disconnect on logout/deactivate
- Update CloudTaskButton to show for all logged-in users
- Remove remote control translation strings from all locales
- Update all related tests

CLO-765

* fix: remove dead getOrganizationMetadata and unused socket.io-client dep

* Readmes

* Readmes

* Types

* fix: remove leftover Roomote Control references from locale READMEs and stale BridgeOrchestrator mock

* Removes cloudtaskbutton

* fix: remove orphaned qrcode packages and dead openInCloud translation keys

* pnpmlock

* Revert these

* Revert these

* Revert these

* Remove socket.io

---------

Co-authored-by: Roo Code <roomote@roocode.com>
Co-authored-by: Bruno Bergher <bruno@roocode.com>
Co-authored-by: cte <cestreich@gmail.com>
2026-02-19 16:33:39 -08:00

347 lines
8.8 KiB
TypeScript

// npx vitest run __tests__/extension.spec.ts
import type * as vscode from "vscode"
import type { AuthState } from "@roo-code/types"
vi.mock("vscode", () => ({
window: {
createOutputChannel: vi.fn().mockReturnValue({
appendLine: vi.fn(),
}),
registerWebviewViewProvider: vi.fn(),
registerUriHandler: vi.fn(),
tabGroups: {
onDidChangeTabs: vi.fn(),
},
onDidChangeActiveTextEditor: vi.fn(),
},
workspace: {
registerTextDocumentContentProvider: vi.fn(),
getConfiguration: vi.fn().mockReturnValue({
get: vi.fn().mockReturnValue([]),
}),
createFileSystemWatcher: vi.fn().mockReturnValue({
onDidCreate: vi.fn(),
onDidChange: vi.fn(),
onDidDelete: vi.fn(),
dispose: vi.fn(),
}),
onDidChangeWorkspaceFolders: vi.fn(),
},
languages: {
registerCodeActionsProvider: vi.fn(),
},
commands: {
executeCommand: vi.fn(),
},
env: {
language: "en",
},
ExtensionMode: {
Production: 1,
},
}))
vi.mock("@dotenvx/dotenvx", () => ({
config: vi.fn(),
}))
// Mock fs so the extension module can safely check for optional .env.
vi.mock("fs", () => ({
existsSync: vi.fn().mockReturnValue(false),
}))
const mockCloudServiceInstance = {
off: vi.fn(),
on: vi.fn(),
getUserInfo: vi.fn().mockReturnValue(null),
isTaskSyncEnabled: vi.fn().mockReturnValue(false),
authService: {
getSessionToken: vi.fn().mockReturnValue("test-session-token"),
},
}
vi.mock("@roo-code/cloud", () => ({
CloudService: {
createInstance: vi.fn(),
hasInstance: vi.fn().mockReturnValue(true),
get instance() {
return mockCloudServiceInstance
},
},
getRooCodeApiUrl: vi.fn().mockReturnValue("https://app.roocode.com"),
}))
vi.mock("@roo-code/telemetry", () => ({
TelemetryService: {
createInstance: vi.fn().mockReturnValue({
register: vi.fn(),
setProvider: vi.fn(),
shutdown: vi.fn(),
}),
get instance() {
return {
register: vi.fn(),
setProvider: vi.fn(),
shutdown: vi.fn(),
}
},
},
PostHogTelemetryClient: vi.fn(),
}))
vi.mock("../utils/outputChannelLogger", () => ({
createOutputChannelLogger: vi.fn().mockReturnValue(vi.fn()),
createDualLogger: vi.fn().mockReturnValue(vi.fn()),
}))
vi.mock("../shared/package", () => ({
Package: {
name: "test-extension",
outputChannel: "Test Output",
version: "1.0.0",
},
}))
vi.mock("../shared/language", () => ({
formatLanguage: vi.fn().mockReturnValue("en"),
}))
vi.mock("../core/config/ContextProxy", () => ({
ContextProxy: {
getInstance: vi.fn().mockResolvedValue({
getValue: vi.fn(),
setValue: vi.fn(),
getValues: vi.fn().mockReturnValue({}),
getProviderSettings: vi.fn().mockReturnValue({}),
}),
},
}))
vi.mock("../integrations/editor/DiffViewProvider", () => ({
DIFF_VIEW_URI_SCHEME: "test-diff-scheme",
}))
vi.mock("../integrations/terminal/TerminalRegistry", () => ({
TerminalRegistry: {
initialize: vi.fn(),
cleanup: vi.fn(),
},
}))
vi.mock("../services/mcp/McpServerManager", () => ({
McpServerManager: {
cleanup: vi.fn().mockResolvedValue(undefined),
getInstance: vi.fn().mockResolvedValue(null),
unregisterProvider: vi.fn(),
},
}))
vi.mock("../services/code-index/manager", () => ({
CodeIndexManager: {
getInstance: vi.fn().mockReturnValue(null),
},
}))
vi.mock("../services/mdm/MdmService", () => ({
MdmService: {
createInstance: vi.fn().mockResolvedValue(null),
},
}))
vi.mock("../utils/migrateSettings", () => ({
migrateSettings: vi.fn().mockResolvedValue(undefined),
}))
vi.mock("../utils/autoImportSettings", () => ({
autoImportSettings: vi.fn().mockResolvedValue(undefined),
}))
vi.mock("../extension/api", () => ({
API: vi.fn().mockImplementation(() => ({})),
}))
vi.mock("../activate", () => ({
handleUri: vi.fn(),
registerCommands: vi.fn(),
registerCodeActions: vi.fn(),
registerTerminalActions: vi.fn(),
CodeActionProvider: vi.fn().mockImplementation(() => ({
providedCodeActionKinds: [],
})),
}))
vi.mock("../i18n", () => ({
initializeI18n: vi.fn(),
t: vi.fn((key) => key),
}))
// Mock ClineProvider
vi.mock("../core/webview/ClineProvider", async () => {
const mockInstance = {
resolveWebviewView: vi.fn(),
postMessageToWebview: vi.fn(),
postStateToWebview: vi.fn(),
postStateToWebviewWithoutClineMessages: vi.fn(),
getState: vi.fn().mockResolvedValue({}),
initializeCloudProfileSyncWhenReady: vi.fn().mockResolvedValue(undefined),
providerSettingsManager: {},
contextProxy: { getGlobalState: vi.fn() },
customModesManager: {},
upsertProviderProfile: vi.fn().mockResolvedValue(undefined),
}
return {
ClineProvider: Object.assign(
vi.fn().mockImplementation(() => mockInstance),
{
// Static method used by extension.ts
getVisibleInstance: vi.fn().mockReturnValue(mockInstance),
sideBarId: "roo-cline-sidebar",
},
),
}
})
// Mock modelCache to prevent network requests during module loading
const mockRefreshModels = vi.fn().mockResolvedValue({})
vi.mock("../api/providers/fetchers/modelCache", () => ({
flushModels: vi.fn(),
getModels: vi.fn().mockResolvedValue([]),
initializeModelCacheRefresh: vi.fn(),
refreshModels: mockRefreshModels,
}))
describe("extension.ts", () => {
let mockContext: vscode.ExtensionContext
let authStateChangedHandler:
| ((data: { state: AuthState; previousState: AuthState }) => void | Promise<void>)
| undefined
beforeEach(() => {
vi.clearAllMocks()
mockContext = {
extensionPath: "/test/path",
globalState: {
get: vi.fn().mockReturnValue(undefined),
update: vi.fn(),
},
subscriptions: [],
} as unknown as vscode.ExtensionContext
authStateChangedHandler = undefined
})
test("does not call dotenvx.config when optional .env does not exist", async () => {
vi.resetModules()
vi.clearAllMocks()
const fs = await import("fs")
vi.mocked(fs.existsSync).mockReturnValue(false)
const dotenvx = await import("@dotenvx/dotenvx")
const { activate } = await import("../extension")
await activate(mockContext)
expect(dotenvx.config).not.toHaveBeenCalled()
})
test("calls dotenvx.config when optional .env exists", async () => {
vi.resetModules()
vi.clearAllMocks()
const fs = await import("fs")
vi.mocked(fs.existsSync).mockReturnValue(true)
const dotenvx = await import("@dotenvx/dotenvx")
const { activate } = await import("../extension")
await activate(mockContext)
expect(dotenvx.config).toHaveBeenCalledTimes(1)
})
describe("Roo model cache refresh on auth state change (ROO-202)", () => {
beforeEach(() => {
vi.resetModules()
mockRefreshModels.mockClear()
})
test("refreshModels is called with session token when auth state changes to active-session", async () => {
const mockAuthService = {
getSessionToken: vi.fn().mockReturnValue("test-session-token"),
}
const { CloudService } = await import("@roo-code/cloud")
vi.mocked(CloudService.createInstance).mockImplementation(async (_context, _logger, handlers) => {
if (handlers?.["auth-state-changed"]) {
authStateChangedHandler = handlers["auth-state-changed"]
}
return {
off: vi.fn(),
on: vi.fn(),
telemetryClient: null,
authService: mockAuthService,
hasActiveSession: vi.fn().mockReturnValue(false),
} as any
})
vi.mocked(CloudService.hasInstance).mockReturnValue(true)
// Activate the extension
const { activate } = await import("../extension")
await activate(mockContext)
// Clear any calls during activation
mockRefreshModels.mockClear()
// Trigger active-session state
await authStateChangedHandler!({
state: "active-session" as AuthState,
previousState: "logged-out" as AuthState,
})
// Verify refreshModels was called with correct parameters including session token
expect(mockRefreshModels).toHaveBeenCalledWith({
provider: "roo",
baseUrl: expect.any(String),
apiKey: "test-session-token",
})
})
test("flushModels is called when auth state changes to logged-out", async () => {
const { flushModels } = await import("../api/providers/fetchers/modelCache")
const { CloudService } = await import("@roo-code/cloud")
vi.mocked(CloudService.createInstance).mockImplementation(async (_context, _logger, handlers) => {
if (handlers?.["auth-state-changed"]) {
authStateChangedHandler = handlers["auth-state-changed"]
}
return {
off: vi.fn(),
on: vi.fn(),
telemetryClient: null,
authService: null,
hasActiveSession: vi.fn().mockReturnValue(false),
} as any
})
vi.mocked(CloudService.hasInstance).mockReturnValue(true)
// Activate the extension
const { activate } = await import("../extension")
await activate(mockContext)
// Trigger logged-out state
await authStateChangedHandler!({
state: "logged-out" as AuthState,
previousState: "active-session" as AuthState,
})
// Verify flushModels was called to clear the cache on logout
expect(flushModels).toHaveBeenCalledWith({ provider: "roo" }, false)
})
})
})