From 51b9418e31f86a421f3dfe5a566437016156df0d Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 23 Dec 2024 21:32:02 -0800 Subject: [PATCH] Tests --- src/core/__tests__/Cline.test.ts | 17 +-- .../__tests__/WorkspaceTracker.test.ts | 116 ++++++++++++++++++ 2 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 src/integrations/workspace/__tests__/WorkspaceTracker.test.ts diff --git a/src/core/__tests__/Cline.test.ts b/src/core/__tests__/Cline.test.ts index ed755bd..99f411e 100644 --- a/src/core/__tests__/Cline.test.ts +++ b/src/core/__tests__/Cline.test.ts @@ -121,13 +121,16 @@ jest.mock('vscode', () => { name: 'mock-workspace', index: 0 }], - onDidCreateFiles: jest.fn(() => mockDisposable), - onDidDeleteFiles: jest.fn(() => mockDisposable), - onDidRenameFiles: jest.fn(() => mockDisposable), - onDidSaveTextDocument: jest.fn(() => mockDisposable), - onDidChangeTextDocument: jest.fn(() => mockDisposable), - onDidOpenTextDocument: jest.fn(() => mockDisposable), - onDidCloseTextDocument: jest.fn(() => mockDisposable) + createFileSystemWatcher: jest.fn(() => ({ + onDidCreate: jest.fn(() => mockDisposable), + onDidDelete: jest.fn(() => mockDisposable), + onDidChange: jest.fn(() => mockDisposable), + dispose: jest.fn() + })), + fs: { + stat: jest.fn().mockResolvedValue({ type: 1 }) // FileType.File = 1 + }, + onDidSaveTextDocument: jest.fn(() => mockDisposable) }, env: { uriScheme: 'vscode', diff --git a/src/integrations/workspace/__tests__/WorkspaceTracker.test.ts b/src/integrations/workspace/__tests__/WorkspaceTracker.test.ts new file mode 100644 index 0000000..1398851 --- /dev/null +++ b/src/integrations/workspace/__tests__/WorkspaceTracker.test.ts @@ -0,0 +1,116 @@ +import * as vscode from "vscode" +import WorkspaceTracker from "../WorkspaceTracker" +import { ClineProvider } from "../../../core/webview/ClineProvider" +import { listFiles } from "../../../services/glob/list-files" + +// Mock modules +const mockOnDidCreate = jest.fn() +const mockOnDidDelete = jest.fn() +const mockOnDidChange = jest.fn() +const mockDispose = jest.fn() + +const mockWatcher = { + onDidCreate: mockOnDidCreate.mockReturnValue({ dispose: mockDispose }), + onDidDelete: mockOnDidDelete.mockReturnValue({ dispose: mockDispose }), + onDidChange: mockOnDidChange.mockReturnValue({ dispose: mockDispose }), + dispose: mockDispose +} + +jest.mock("vscode", () => ({ + workspace: { + workspaceFolders: [{ + uri: { fsPath: "/test/workspace" }, + name: "test", + index: 0 + }], + createFileSystemWatcher: jest.fn(() => mockWatcher), + fs: { + stat: jest.fn().mockResolvedValue({ type: 1 }) // FileType.File = 1 + } + }, + FileType: { File: 1, Directory: 2 } +})) + +jest.mock("../../../services/glob/list-files") + +describe("WorkspaceTracker", () => { + let workspaceTracker: WorkspaceTracker + let mockProvider: ClineProvider + + beforeEach(() => { + jest.clearAllMocks() + + // Create provider mock + mockProvider = { postMessageToWebview: jest.fn() } as any + + // Create tracker instance + workspaceTracker = new WorkspaceTracker(mockProvider) + }) + + it("should initialize with workspace files", async () => { + const mockFiles = [["/test/workspace/file1.ts", "/test/workspace/file2.ts"], false] + ;(listFiles as jest.Mock).mockResolvedValue(mockFiles) + + await workspaceTracker.initializeFilePaths() + + expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({ + type: "workspaceUpdated", + filePaths: ["file1.ts", "file2.ts"] + }) + }) + + it("should handle file creation events", async () => { + // Get the creation callback and call it + const [[callback]] = mockOnDidCreate.mock.calls + await callback({ fsPath: "/test/workspace/newfile.ts" }) + + expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({ + type: "workspaceUpdated", + filePaths: ["newfile.ts"] + }) + }) + + it("should handle file deletion events", async () => { + // First add a file + const [[createCallback]] = mockOnDidCreate.mock.calls + await createCallback({ fsPath: "/test/workspace/file.ts" }) + + // Then delete it + const [[deleteCallback]] = mockOnDidDelete.mock.calls + await deleteCallback({ fsPath: "/test/workspace/file.ts" }) + + // The last call should have empty filePaths + expect(mockProvider.postMessageToWebview).toHaveBeenLastCalledWith({ + type: "workspaceUpdated", + filePaths: [] + }) + }) + + it("should handle file change events", async () => { + const [[callback]] = mockOnDidChange.mock.calls + await callback({ fsPath: "/test/workspace/changed.ts" }) + + expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({ + type: "workspaceUpdated", + filePaths: ["changed.ts"] + }) + }) + + it("should handle directory paths correctly", async () => { + // Mock stat to return directory type + ;(vscode.workspace.fs.stat as jest.Mock).mockResolvedValueOnce({ type: 2 }) // FileType.Directory = 2 + + const [[callback]] = mockOnDidCreate.mock.calls + await callback({ fsPath: "/test/workspace/newdir" }) + + expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({ + type: "workspaceUpdated", + filePaths: ["newdir"] + }) + }) + + it("should clean up watchers on dispose", () => { + workspaceTracker.dispose() + expect(mockDispose).toHaveBeenCalled() + }) +}) \ No newline at end of file