UNPKG

@skyramp/mcp

Version:

Skyramp MCP (Model Context Protocol) Server - AI-powered test generation and execution

195 lines (194 loc) 8.38 kB
// @ts-ignore import { registerInitTestbotTool } from "./initTestbotTool.js"; import { simpleGit } from "simple-git"; import * as fs from "fs/promises"; import * as fsSync from "fs"; import * as path from "path"; import * as os from "os"; // Mock logger and AnalyticsService to avoid side effects jest.mock("../utils/logger.js", () => ({ logger: { info: jest.fn(), error: jest.fn() }, })); jest.mock("../services/AnalyticsService.js", () => ({ AnalyticsService: { pushMCPToolEvent: jest.fn() }, })); /** * Captures the tool handler callback from registerInitTestbotTool * by providing a fake McpServer with a mock registerTool method. */ function captureToolHandler() { let handler; const fakeServer = { registerTool: (_name, _opts, fn) => { handler = fn; }, }; registerInitTestbotTool(fakeServer); return handler; } /** * Creates a temp directory, initializes a git repo, and optionally * adds a GitHub remote. */ async function createTempRepo(options) { const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "init-testbot-test-")); const git = simpleGit(tmpDir); await git.init(); if (options?.addGithubRemote !== false) { await git.addRemote("origin", "https://github.com/test-org/test-repo.git"); } return tmpDir; } describe("registerInitTestbotTool", () => { let handler; let tmpDirs = []; beforeAll(() => { handler = captureToolHandler(); }); afterEach(async () => { for (const dir of tmpDirs) { await fs.rm(dir, { recursive: true, force: true }); } tmpDirs = []; }); it("should register the tool on the server", () => { const registerToolMock = jest.fn(); const fakeServer = { registerTool: registerToolMock }; registerInitTestbotTool(fakeServer); expect(registerToolMock).toHaveBeenCalledWith("skyramp_init_testbot", expect.objectContaining({ description: expect.any(String), inputSchema: expect.any(Object), }), expect.any(Function)); }); it("should return error for non-git directory", async () => { const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "init-testbot-test-")); tmpDirs.push(tmpDir); const result = await handler({ repository_path: tmpDir, agent_type: "cursor", }); expect(result.isError).toBe(true); expect(result.content[0].text).toContain("is not a Git repository"); }); it("should return error for git repo without GitHub remote", async () => { const tmpDir = await createTempRepo({ addGithubRemote: false }); tmpDirs.push(tmpDir); const result = await handler({ repository_path: tmpDir, agent_type: "cursor", }); expect(result.isError).toBe(true); expect(result.content[0].text).toContain("No GitHub remote found"); }); it("should create workflow file on success", async () => { const tmpDir = await createTempRepo(); tmpDirs.push(tmpDir); const result = await handler({ repository_path: tmpDir, agent_type: "cursor", }); expect(result.isError).toBeUndefined(); expect(result.content[0].text).toContain("workflow created successfully"); const workflowPath = path.join(tmpDir, ".github", "workflows", "skyramp-test-bot.yml"); expect(fsSync.existsSync(workflowPath)).toBe(true); }); it("should return already-exists message when workflow file exists", async () => { const tmpDir = await createTempRepo(); tmpDirs.push(tmpDir); // Create the workflow file first const workflowDir = path.join(tmpDir, ".github", "workflows"); await fs.mkdir(workflowDir, { recursive: true }); await fs.writeFile(path.join(workflowDir, "skyramp-test-bot.yml"), "existing"); const result = await handler({ repository_path: tmpDir, agent_type: "cursor", }); expect(result.isError).toBeUndefined(); expect(result.content[0].text).toContain("already exists"); // Verify original file was not overwritten const content = await fs.readFile(path.join(workflowDir, "skyramp-test-bot.yml"), "utf-8"); expect(content).toBe("existing"); }); it("should generate workflow with cursor API key by default", async () => { const tmpDir = await createTempRepo(); tmpDirs.push(tmpDir); await handler({ repository_path: tmpDir, agent_type: "cursor", }); const workflowContent = await fs.readFile(path.join(tmpDir, ".github", "workflows", "skyramp-test-bot.yml"), "utf-8"); expect(workflowContent).toContain("cursor_api_key"); expect(workflowContent).not.toContain("copilot_api_key"); }); it("should generate workflow with copilot API key when agent_type is copilot", async () => { const tmpDir = await createTempRepo(); tmpDirs.push(tmpDir); await handler({ repository_path: tmpDir, agent_type: "copilot", }); const workflowContent = await fs.readFile(path.join(tmpDir, ".github", "workflows", "skyramp-test-bot.yml"), "utf-8"); expect(workflowContent).toContain("copilot_api_key"); expect(workflowContent).not.toContain("cursor_api_key"); }); it("should generate workflow without branches key when target_branches is not provided", async () => { const tmpDir = await createTempRepo(); tmpDirs.push(tmpDir); await handler({ repository_path: tmpDir, agent_type: "cursor", }); const workflowContent = await fs.readFile(path.join(tmpDir, ".github", "workflows", "skyramp-test-bot.yml"), "utf-8"); expect(workflowContent).toContain("pull_request:"); expect(workflowContent).not.toContain("branches:"); }); it("should generate workflow with branches key when target_branches is provided", async () => { const tmpDir = await createTempRepo(); tmpDirs.push(tmpDir); await handler({ repository_path: tmpDir, agent_type: "cursor", target_branches: ["main", "develop"], }); const workflowContent = await fs.readFile(path.join(tmpDir, ".github", "workflows", "skyramp-test-bot.yml"), "utf-8"); expect(workflowContent).toContain("branches:"); expect(workflowContent).toContain("- 'main'"); expect(workflowContent).toContain("- 'develop'"); }); it("should include setup instructions with correct secret names for cursor", async () => { const tmpDir = await createTempRepo(); tmpDirs.push(tmpDir); const result = await handler({ repository_path: tmpDir, agent_type: "cursor", }); expect(result.content[0].text).toContain("CURSOR_API_KEY"); expect(result.content[0].text).toContain("SKYRAMP_LICENSE"); expect(result.content[0].text).toContain("all pull requests"); }); it("should include setup instructions with correct secret names for copilot", async () => { const tmpDir = await createTempRepo(); tmpDirs.push(tmpDir); const result = await handler({ repository_path: tmpDir, agent_type: "copilot", target_branches: ["main"], }); expect(result.content[0].text).toContain("COPILOT_API_KEY"); expect(result.content[0].text).toContain("pull requests targeting: main"); }); it("should generate valid YAML workflow structure", async () => { const tmpDir = await createTempRepo(); tmpDirs.push(tmpDir); await handler({ repository_path: tmpDir, agent_type: "cursor", }); const workflowContent = await fs.readFile(path.join(tmpDir, ".github", "workflows", "skyramp-test-bot.yml"), "utf-8"); expect(workflowContent).toContain("name: Skyramp Test Automation"); expect(workflowContent).toContain("runs-on: ubuntu-latest"); expect(workflowContent).toContain("uses: actions/checkout@v4"); expect(workflowContent).toContain("uses: skyramp/test-bot@v1"); expect(workflowContent).toContain("skyramp_license_file:"); }); });