mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: restore accidentally removed test suites in CustomModesManager
- Restored updateCustomMode test suite
- Restored deleteCustomMode test suite
- Restored File Operations test suite
- Restored importModeWithRules test suite
- Restored checkRulesDirectoryHasContent test suite
- Restored exportModeWithRules test suite
These test suites were accidentally removed in commit b518a483 during refactoring.
All 51 tests are now passing successfully.
This commit is contained in:
parent
b518a483dd
commit
dba7d6d871
1 changed files with 710 additions and 2 deletions
|
|
@ -1213,6 +1213,714 @@ customModes:
|
|||
})
|
||||
})
|
||||
|
||||
// Add the remaining test suites that were in the original file...
|
||||
// (The rest of the test file continues with updateCustomMode, deleteCustomMode, etc.)
|
||||
describe("updateCustomMode", () => {
|
||||
it("should update mode in settings file while preserving .roomodes precedence", async () => {
|
||||
const newMode: ModeConfig = {
|
||||
slug: "mode1",
|
||||
name: "Updated Mode 1",
|
||||
roleDefinition: "Updated Role 1",
|
||||
groups: ["read"],
|
||||
source: "global",
|
||||
}
|
||||
|
||||
const roomodesModes = [
|
||||
{
|
||||
slug: "mode1",
|
||||
name: "Roomodes Mode 1",
|
||||
roleDefinition: "Role 1",
|
||||
groups: ["read"],
|
||||
source: "project",
|
||||
},
|
||||
]
|
||||
|
||||
const existingModes = [
|
||||
{ slug: "mode2", name: "Mode 2", roleDefinition: "Role 2", groups: ["read"], source: "global" },
|
||||
]
|
||||
|
||||
let settingsContent = { customModes: existingModes }
|
||||
let roomodesContent = { customModes: roomodesModes }
|
||||
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
if (path === mockSettingsPath) {
|
||||
return yaml.stringify(settingsContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.writeFile as Mock).mockImplementation(async (path: string, content: string, _encoding?: string) => {
|
||||
if (path === mockSettingsPath) {
|
||||
settingsContent = yaml.parse(content)
|
||||
}
|
||||
if (path === mockRoomodes) {
|
||||
roomodesContent = yaml.parse(content)
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
await manager.updateCustomMode("mode1", newMode)
|
||||
|
||||
// The mode should be written to its source file (roomodes in this case since it exists there)
|
||||
// But since we're updating with source: "global", it should write to settings file
|
||||
// However, the implementation preserves the sourceFile, so it writes to roomodes
|
||||
expect(fs.writeFile).toHaveBeenCalled()
|
||||
|
||||
// Verify the content of the write
|
||||
const writeCall = (fs.writeFile as Mock).mock.calls[0]
|
||||
const content = yaml.parse(writeCall[1])
|
||||
expect(content.customModes).toContainEqual(
|
||||
expect.objectContaining({
|
||||
slug: "mode1",
|
||||
name: "Updated Mode 1",
|
||||
roleDefinition: "Updated Role 1",
|
||||
}),
|
||||
)
|
||||
|
||||
// Should update global state with merged modes where .roomodes takes precedence
|
||||
expect(mockContext.globalState.update).toHaveBeenCalledWith(
|
||||
"customModes",
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
slug: "mode1",
|
||||
name: "Roomodes Mode 1", // .roomodes version should take precedence
|
||||
source: "project",
|
||||
}),
|
||||
]),
|
||||
)
|
||||
|
||||
// Should trigger onUpdate
|
||||
expect(mockOnUpdate).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("creates .roomodes file when adding project-specific mode", async () => {
|
||||
const projectMode: ModeConfig = {
|
||||
slug: "project-mode",
|
||||
name: "Project Mode",
|
||||
roleDefinition: "Project Role",
|
||||
groups: ["read"],
|
||||
source: "project",
|
||||
}
|
||||
|
||||
// Mock .roomodes to not exist initially
|
||||
let roomodesContent: any = null
|
||||
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
|
||||
return path === mockSettingsPath
|
||||
})
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockSettingsPath) {
|
||||
return yaml.stringify({ customModes: [] })
|
||||
}
|
||||
if (path === mockRoomodes) {
|
||||
if (!roomodesContent) {
|
||||
throw new Error("File not found")
|
||||
}
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.writeFile as Mock).mockImplementation(async (path: string, content: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
roomodesContent = yaml.parse(content)
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
await manager.updateCustomMode("project-mode", projectMode)
|
||||
|
||||
// Verify .roomodes was created with the project mode
|
||||
expect(fs.writeFile).toHaveBeenCalledWith(
|
||||
expect.any(String), // Don't check exact path as it may have different separators on different platforms
|
||||
expect.stringContaining("project-mode"),
|
||||
"utf-8",
|
||||
)
|
||||
|
||||
// Verify the path is correct regardless of separators
|
||||
const writeCall = (fs.writeFile as Mock).mock.calls[0]
|
||||
expect(path.normalize(writeCall[0])).toBe(path.normalize(mockRoomodes))
|
||||
|
||||
// Verify the content written to .roomodes
|
||||
expect(roomodesContent).toEqual({
|
||||
customModes: [
|
||||
expect.objectContaining({
|
||||
slug: "project-mode",
|
||||
name: "Project Mode",
|
||||
roleDefinition: "Project Role",
|
||||
source: "project",
|
||||
}),
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
it("queues write operations", async () => {
|
||||
const mode1: ModeConfig = {
|
||||
slug: "mode1",
|
||||
name: "Mode 1",
|
||||
roleDefinition: "Role 1",
|
||||
groups: ["read"],
|
||||
source: "global",
|
||||
}
|
||||
const mode2: ModeConfig = {
|
||||
slug: "mode2",
|
||||
name: "Mode 2",
|
||||
roleDefinition: "Role 2",
|
||||
groups: ["read"],
|
||||
source: "global",
|
||||
}
|
||||
|
||||
let settingsContent = { customModes: [] }
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockSettingsPath) {
|
||||
return yaml.stringify(settingsContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.writeFile as Mock).mockImplementation(async (path: string, content: string, _encoding?: string) => {
|
||||
if (path === mockSettingsPath) {
|
||||
settingsContent = yaml.parse(content)
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
// Start both updates simultaneously
|
||||
await Promise.all([manager.updateCustomMode("mode1", mode1), manager.updateCustomMode("mode2", mode2)])
|
||||
|
||||
// Verify final state in settings file
|
||||
expect(settingsContent.customModes).toHaveLength(2)
|
||||
expect(settingsContent.customModes.map((m: ModeConfig) => m.name)).toContain("Mode 1")
|
||||
expect(settingsContent.customModes.map((m: ModeConfig) => m.name)).toContain("Mode 2")
|
||||
|
||||
// Verify global state was updated
|
||||
expect(mockContext.globalState.update).toHaveBeenCalledWith(
|
||||
"customModes",
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
slug: "mode1",
|
||||
name: "Mode 1",
|
||||
source: "global",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
slug: "mode2",
|
||||
name: "Mode 2",
|
||||
source: "global",
|
||||
}),
|
||||
]),
|
||||
)
|
||||
|
||||
// Should trigger onUpdate
|
||||
expect(mockOnUpdate).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe("File Operations", () => {
|
||||
it("creates settings directory if it doesn't exist", async () => {
|
||||
const settingsPath = path.join(mockStoragePath, "settings", GlobalFileNames.customModes)
|
||||
await manager.getCustomModesFilePath()
|
||||
|
||||
expect(fs.mkdir).toHaveBeenCalledWith(path.dirname(settingsPath), { recursive: true })
|
||||
})
|
||||
|
||||
it("creates default config if file doesn't exist", async () => {
|
||||
const settingsPath = path.join(mockStoragePath, "settings", GlobalFileNames.customModes)
|
||||
|
||||
// Mock fileExists to return false first time, then true
|
||||
let firstCall = true
|
||||
;(fileExistsAtPath as Mock).mockImplementation(async () => {
|
||||
if (firstCall) {
|
||||
firstCall = false
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
await manager.getCustomModesFilePath()
|
||||
|
||||
expect(fs.writeFile).toHaveBeenCalledWith(settingsPath, expect.stringMatching(/^customModes: \[\]/))
|
||||
})
|
||||
|
||||
it("watches file for changes", async () => {
|
||||
const configPath = path.join(mockStoragePath, "settings", GlobalFileNames.customModes)
|
||||
|
||||
;(fs.readFile as Mock).mockResolvedValue(yaml.stringify({ customModes: [] }))
|
||||
;(arePathsEqual as Mock).mockImplementation(
|
||||
(path1: string, path2: string) => path.normalize(path1) === path.normalize(path2),
|
||||
)
|
||||
|
||||
// Mock createFileSystemWatcher to return a mock watcher
|
||||
const mockWatcher = {
|
||||
onDidChange: vi.fn().mockReturnValue({ dispose: vi.fn() }),
|
||||
onDidCreate: vi.fn().mockReturnValue({ dispose: vi.fn() }),
|
||||
onDidDelete: vi.fn().mockReturnValue({ dispose: vi.fn() }),
|
||||
dispose: vi.fn(),
|
||||
}
|
||||
const createFileSystemWatcherMock = vi.fn().mockReturnValue(mockWatcher)
|
||||
;(vscode.workspace as any).createFileSystemWatcher = createFileSystemWatcherMock
|
||||
|
||||
// Temporarily set NODE_ENV to allow file watching
|
||||
const originalNodeEnv = process.env.NODE_ENV
|
||||
process.env.NODE_ENV = "development"
|
||||
|
||||
try {
|
||||
// Create a new manager to trigger the file watcher setup
|
||||
const testManager = new CustomModesManager(mockContext, mockOnUpdate)
|
||||
|
||||
// Wait a bit for the async watchCustomModesFiles to complete
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
|
||||
// Verify createFileSystemWatcher was called
|
||||
expect(createFileSystemWatcherMock).toHaveBeenCalled()
|
||||
|
||||
// Get the onChange callback that was registered
|
||||
const onChangeCall = mockWatcher.onDidChange.mock.calls[0]
|
||||
expect(onChangeCall).toBeDefined()
|
||||
const [onChangeCallback] = onChangeCall
|
||||
|
||||
// Simulate file change event
|
||||
await onChangeCallback()
|
||||
|
||||
// Verify file was processed
|
||||
expect(fs.readFile).toHaveBeenCalledWith(configPath, "utf-8")
|
||||
expect(mockContext.globalState.update).toHaveBeenCalled()
|
||||
expect(mockOnUpdate).toHaveBeenCalled()
|
||||
|
||||
// Clean up
|
||||
testManager.dispose()
|
||||
} finally {
|
||||
// Restore original NODE_ENV
|
||||
process.env.NODE_ENV = originalNodeEnv
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("deleteCustomMode", () => {
|
||||
it("deletes mode from settings file", async () => {
|
||||
const existingMode = {
|
||||
slug: "mode-to-delete",
|
||||
name: "Mode To Delete",
|
||||
roleDefinition: "Test role",
|
||||
groups: ["read"],
|
||||
source: "global",
|
||||
}
|
||||
|
||||
let settingsContent = { customModes: [existingMode] }
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockSettingsPath) {
|
||||
return yaml.stringify(settingsContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.writeFile as Mock).mockImplementation(async (path: string, content: string, encoding?: string) => {
|
||||
if (path === mockSettingsPath && encoding === "utf-8") {
|
||||
settingsContent = yaml.parse(content)
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
// Mock the global state update to actually update the settingsContent
|
||||
;(mockContext.globalState.update as Mock).mockImplementation((key: string, value: any) => {
|
||||
if (key === "customModes") {
|
||||
settingsContent.customModes = value
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
await manager.deleteCustomMode("mode-to-delete")
|
||||
|
||||
// Verify mode was removed from settings file
|
||||
expect(settingsContent.customModes).toHaveLength(0)
|
||||
|
||||
// Verify global state was updated
|
||||
expect(mockContext.globalState.update).toHaveBeenCalledWith("customModes", [])
|
||||
|
||||
// Should trigger onUpdate
|
||||
expect(mockOnUpdate).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("handles errors gracefully", async () => {
|
||||
const mockShowError = vi.fn()
|
||||
;(vscode.window.showErrorMessage as Mock) = mockShowError
|
||||
;(fs.writeFile as Mock).mockRejectedValue(new Error("Write error"))
|
||||
|
||||
await manager.deleteCustomMode("non-existent-mode")
|
||||
|
||||
expect(mockShowError).toHaveBeenCalledWith("customModes.errors.deleteFailed")
|
||||
})
|
||||
})
|
||||
|
||||
describe("updateModesInFile", () => {
|
||||
it("handles corrupted YAML content gracefully", async () => {
|
||||
const corruptedYaml = "customModes: [invalid yaml content"
|
||||
;(fs.readFile as Mock).mockResolvedValue(corruptedYaml)
|
||||
|
||||
const newMode: ModeConfig = {
|
||||
slug: "test-mode",
|
||||
name: "Test Mode",
|
||||
roleDefinition: "Test Role",
|
||||
groups: ["read"],
|
||||
source: "global",
|
||||
}
|
||||
|
||||
await manager.updateCustomMode("test-mode", newMode)
|
||||
|
||||
// Verify that a valid YAML structure was written
|
||||
const writeCall = (fs.writeFile as Mock).mock.calls[0]
|
||||
const writtenContent = yaml.parse(writeCall[1])
|
||||
expect(writtenContent).toEqual({
|
||||
customModes: [
|
||||
expect.objectContaining({
|
||||
slug: "test-mode",
|
||||
name: "Test Mode",
|
||||
roleDefinition: "Test Role",
|
||||
}),
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("importModeWithRules", () => {
|
||||
it("should return error when YAML content is invalid", async () => {
|
||||
const invalidYaml = "invalid yaml content"
|
||||
|
||||
const result = await manager.importModeWithRules(invalidYaml)
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
expect(result.error).toContain("Invalid import format")
|
||||
})
|
||||
|
||||
it("should return error when no custom modes found in YAML", async () => {
|
||||
const emptyYaml = yaml.stringify({ customModes: [] })
|
||||
|
||||
const result = await manager.importModeWithRules(emptyYaml)
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
expect(result.error).toBe("Invalid import format: Expected 'customModes' array in YAML")
|
||||
})
|
||||
|
||||
it("should return error when no workspace is available", async () => {
|
||||
;(getWorkspacePath as Mock).mockReturnValue(null)
|
||||
const validYaml = yaml.stringify({
|
||||
customModes: [
|
||||
{
|
||||
slug: "test-mode",
|
||||
name: "Test Mode",
|
||||
roleDefinition: "Test Role",
|
||||
groups: ["read"],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const result = await manager.importModeWithRules(validYaml)
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
expect(result.error).toBe("No workspace found")
|
||||
})
|
||||
|
||||
it("should successfully import mode without rules files", async () => {
|
||||
const importYaml = yaml.stringify({
|
||||
customModes: [
|
||||
{
|
||||
slug: "imported-mode",
|
||||
name: "Imported Mode",
|
||||
roleDefinition: "Imported Role",
|
||||
groups: ["read", "edit"],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
let roomodesContent: any = null
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockSettingsPath) {
|
||||
return yaml.stringify({ customModes: [] })
|
||||
}
|
||||
if (path === mockRoomodes && roomodesContent) {
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.writeFile as Mock).mockImplementation(async (path: string, content: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
roomodesContent = yaml.parse(content)
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
const result = await manager.importModeWithRules(importYaml)
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
expect(fs.writeFile).toHaveBeenCalledWith(
|
||||
expect.stringContaining(".roomodes"),
|
||||
expect.stringContaining("imported-mode"),
|
||||
"utf-8",
|
||||
)
|
||||
})
|
||||
|
||||
it("should successfully import mode with rules files", async () => {
|
||||
const importYaml = yaml.stringify({
|
||||
customModes: [
|
||||
{
|
||||
slug: "imported-mode",
|
||||
name: "Imported Mode",
|
||||
roleDefinition: "Imported Role",
|
||||
groups: ["read"],
|
||||
rulesFiles: [
|
||||
{
|
||||
relativePath: "rules-imported-mode/rule1.md",
|
||||
content: "Rule 1 content",
|
||||
},
|
||||
{
|
||||
relativePath: "rules-imported-mode/subfolder/rule2.md",
|
||||
content: "Rule 2 content",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
let roomodesContent: any = null
|
||||
let writtenFiles: Record<string, string> = {}
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockSettingsPath) {
|
||||
return yaml.stringify({ customModes: [] })
|
||||
}
|
||||
if (path === mockRoomodes && roomodesContent) {
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.writeFile as Mock).mockImplementation(async (path: string, content: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
roomodesContent = yaml.parse(content)
|
||||
} else {
|
||||
writtenFiles[path] = content
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
;(fs.mkdir as Mock).mockResolvedValue(undefined)
|
||||
|
||||
const result = await manager.importModeWithRules(importYaml)
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
|
||||
// Verify mode was imported
|
||||
expect(fs.writeFile).toHaveBeenCalledWith(
|
||||
expect.stringContaining(".roomodes"),
|
||||
expect.stringContaining("imported-mode"),
|
||||
"utf-8",
|
||||
)
|
||||
|
||||
// Verify rules files were created
|
||||
expect(fs.mkdir).toHaveBeenCalledWith(expect.stringContaining("rules-imported-mode"), {
|
||||
recursive: true,
|
||||
})
|
||||
expect(fs.mkdir).toHaveBeenCalledWith(
|
||||
expect.stringContaining(path.join("rules-imported-mode", "subfolder")),
|
||||
{ recursive: true },
|
||||
)
|
||||
|
||||
// Verify file contents
|
||||
const rule1Path = Object.keys(writtenFiles).find((p) => p.includes("rule1.md"))
|
||||
const rule2Path = Object.keys(writtenFiles).find((p) => p.includes("rule2.md"))
|
||||
expect(writtenFiles[rule1Path!]).toBe("Rule 1 content")
|
||||
expect(writtenFiles[rule2Path!]).toBe("Rule 2 content")
|
||||
})
|
||||
|
||||
it("should import multiple modes at once", async () => {
|
||||
const importYaml = yaml.stringify({
|
||||
customModes: [
|
||||
{
|
||||
slug: "mode1",
|
||||
name: "Mode 1",
|
||||
roleDefinition: "Role 1",
|
||||
groups: ["read"],
|
||||
},
|
||||
{
|
||||
slug: "mode2",
|
||||
name: "Mode 2",
|
||||
roleDefinition: "Role 2",
|
||||
groups: ["edit"],
|
||||
rulesFiles: [
|
||||
{
|
||||
relativePath: "rules-mode2/rule.md",
|
||||
content: "Mode 2 rules",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
let roomodesContent: any = null
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockSettingsPath) {
|
||||
return yaml.stringify({ customModes: [] })
|
||||
}
|
||||
if (path === mockRoomodes && roomodesContent) {
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.writeFile as Mock).mockImplementation(async (path: string, content: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
roomodesContent = yaml.parse(content)
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
const result = await manager.importModeWithRules(importYaml)
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
expect(roomodesContent.customModes).toHaveLength(2)
|
||||
expect(roomodesContent.customModes[0].slug).toBe("mode1")
|
||||
expect(roomodesContent.customModes[1].slug).toBe("mode2")
|
||||
})
|
||||
})
|
||||
|
||||
describe("checkRulesDirectoryHasContent", () => {
|
||||
it("should return false when no workspace is available", async () => {
|
||||
;(getWorkspacePath as Mock).mockReturnValue(null)
|
||||
|
||||
const result = await manager.checkRulesDirectoryHasContent("test-mode")
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false when mode is not in .roomodes file", async () => {
|
||||
const roomodesContent = { customModes: [{ slug: "other-mode", name: "Other Mode" }] }
|
||||
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
|
||||
return path === mockRoomodes
|
||||
})
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
|
||||
const result = await manager.checkRulesDirectoryHasContent("test-mode")
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false when rules directory doesn't exist", async () => {
|
||||
const roomodesContent = { customModes: [{ slug: "test-mode", name: "Test Mode" }] }
|
||||
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
|
||||
return path === mockRoomodes
|
||||
})
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.stat as Mock).mockRejectedValue(new Error("Directory not found"))
|
||||
|
||||
const result = await manager.checkRulesDirectoryHasContent("test-mode")
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it("should return true when rules directory has content files", async () => {
|
||||
const roomodesContent = { customModes: [{ slug: "test-mode", name: "Test Mode" }] }
|
||||
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
|
||||
return path === mockRoomodes
|
||||
})
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
if (path.includes("rules-test-mode")) {
|
||||
return "Some rule content"
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.stat as Mock).mockResolvedValue({ isDirectory: () => true })
|
||||
;(fs.readdir as Mock).mockResolvedValue([
|
||||
{ name: "rule1.md", isFile: () => true, parentPath: "/mock/workspace/.roo/rules-test-mode" },
|
||||
])
|
||||
|
||||
const result = await manager.checkRulesDirectoryHasContent("test-mode")
|
||||
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("exportModeWithRules", () => {
|
||||
it("should return error when mode is not found", async () => {
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockSettingsPath) {
|
||||
return yaml.stringify({ customModes: [] })
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
|
||||
return path === mockSettingsPath
|
||||
})
|
||||
|
||||
const result = await manager.exportModeWithRules("test-mode")
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
expect(result.error).toBe("Mode not found")
|
||||
})
|
||||
|
||||
it("should successfully export mode without rules when rules directory doesn't exist", async () => {
|
||||
const roomodesContent = {
|
||||
customModes: [{ slug: "test-mode", name: "Test Mode", roleDefinition: "Test Role", groups: ["read"] }],
|
||||
}
|
||||
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
|
||||
return path === mockRoomodes
|
||||
})
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.stat as Mock).mockRejectedValue(new Error("Directory not found"))
|
||||
|
||||
const result = await manager.exportModeWithRules("test-mode")
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
expect(result.yaml).toContain("test-mode")
|
||||
expect(result.yaml).toContain("Test Mode")
|
||||
})
|
||||
|
||||
it("should successfully export mode with rules for a custom mode in .roomodes", async () => {
|
||||
const roomodesContent = {
|
||||
customModes: [
|
||||
{
|
||||
slug: "test-mode",
|
||||
name: "Test Mode",
|
||||
roleDefinition: "Test Role",
|
||||
groups: ["read"],
|
||||
customInstructions: "Existing instructions",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
|
||||
return path === mockRoomodes
|
||||
})
|
||||
;(fs.readFile as Mock).mockImplementation(async (path: string) => {
|
||||
if (path === mockRoomodes) {
|
||||
return yaml.stringify(roomodesContent)
|
||||
}
|
||||
if (path.includes("rules-test-mode")) {
|
||||
return "New rule content from files"
|
||||
}
|
||||
throw new Error("File not found")
|
||||
})
|
||||
;(fs.stat as Mock).mockResolvedValue({ isDirectory: () => true })
|
||||
;(fs.readdir as Mock).mockResolvedValue([
|
||||
{ name: "rule1.md", isFile: () => true, parentPath: "/mock/workspace/.roo/rules-test-mode" },
|
||||
])
|
||||
|
||||
const result = await manager.exportModeWithRules("test-mode")
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
expect(result.yaml).toContain("test-mode")
|
||||
expect(result.yaml).toContain("Existing instructions")
|
||||
expect(result.yaml).toContain("New rule content from files")
|
||||
// Should NOT delete the rules directory
|
||||
expect(fs.rm).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue