Skip to main content
Glama

mcp-server-circleci

Official
handler.test.ts6.88 kB
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { getFlakyTestLogs, getFlakyTestsOutputDirectory } from './handler.js'; import * as projectDetection from '../../lib/project-detection/index.js'; import * as getFlakyTestsModule from '../../lib/flaky-tests/getFlakyTests.js'; import * as formatFlakyTestsModule from '../../lib/flaky-tests/getFlakyTests.js'; // Mock dependencies vi.mock('../../lib/project-detection/index.js'); vi.mock('../../lib/flaky-tests/getFlakyTests.js'); // Define mock functions using vi.hoisted() to make them available everywhere const { mockWriteFileSync, mockMkdirSync, mockRmSync, mockJoin } = vi.hoisted( () => ({ mockWriteFileSync: vi.fn(), mockMkdirSync: vi.fn(), mockRmSync: vi.fn(), mockJoin: vi.fn(), }), ); vi.mock('fs', () => ({ writeFileSync: mockWriteFileSync, mkdirSync: mockMkdirSync, rmSync: mockRmSync, })); vi.mock('path', () => ({ join: mockJoin, })); describe('getFlakyTestLogs handler', () => { beforeEach(() => { vi.resetAllMocks(); delete process.env.FILE_OUTPUT_DIRECTORY; }); it('should return a valid MCP error response when no inputs are provided', async () => { const args = { params: {}, }; const controller = new AbortController(); const response = await getFlakyTestLogs(args, { signal: controller.signal, }); expect(response).toHaveProperty('content'); expect(response).toHaveProperty('isError', true); expect(Array.isArray(response.content)).toBe(true); expect(response.content[0]).toHaveProperty('type', 'text'); expect(typeof response.content[0].text).toBe('string'); }); it('should return a valid MCP error response when project is not found', async () => { vi.spyOn(projectDetection, 'identifyProjectSlug').mockResolvedValue( undefined, ); const args = { params: { workspaceRoot: '/workspace', gitRemoteURL: 'https://github.com/org/repo.git', }, }; const controller = new AbortController(); const response = await getFlakyTestLogs(args, { signal: controller.signal, }); expect(response).toHaveProperty('content'); expect(response).toHaveProperty('isError', true); expect(Array.isArray(response.content)).toBe(true); expect(response.content[0]).toHaveProperty('type', 'text'); expect(typeof response.content[0].text).toBe('string'); }); it('should use projectSlug directly when provided', async () => { vi.spyOn(getFlakyTestsModule, 'default').mockResolvedValue([ { name: 'flakyTest', message: 'Test failure message', run_time: '1.5', result: 'failure', classname: 'TestClass', file: 'path/to/file.js', }, ]); vi.spyOn(formatFlakyTestsModule, 'formatFlakyTests').mockReturnValue({ content: [ { type: 'text', text: 'Flaky test output', }, ], }); const args = { params: { projectSlug: 'gh/org/repo', }, }; const controller = new AbortController(); await getFlakyTestLogs(args, { signal: controller.signal, }); expect(getFlakyTestsModule.default).toHaveBeenCalledWith({ projectSlug: 'gh/org/repo', }); // Verify that no project detection methods were called expect(projectDetection.getProjectSlugFromURL).not.toHaveBeenCalled(); expect(projectDetection.identifyProjectSlug).not.toHaveBeenCalled(); }); it('should return a valid MCP success response with flaky tests', async () => { vi.spyOn(projectDetection, 'getProjectSlugFromURL').mockReturnValue( 'gh/org/repo', ); vi.spyOn(getFlakyTestsModule, 'default').mockResolvedValue([ { name: 'flakyTest', message: 'Test failure message', run_time: '1.5', result: 'failure', classname: 'TestClass', file: 'path/to/file.js', }, ]); vi.spyOn(formatFlakyTestsModule, 'formatFlakyTests').mockReturnValue({ content: [ { type: 'text', text: 'Flaky test output', }, ], }); const args = { params: { projectURL: 'https://app.circleci.com/pipelines/gh/org/repo', }, }; const controller = new AbortController(); const response = await getFlakyTestLogs(args, { signal: controller.signal, }); expect(response).toHaveProperty('content'); expect(Array.isArray(response.content)).toBe(true); expect(response.content[0]).toHaveProperty('type', 'text'); expect(typeof response.content[0].text).toBe('string'); }); it('should write flaky tests to files when FILE_OUTPUT_DIRECTORY is set', async () => { process.env.FILE_OUTPUT_DIRECTORY = '/tmp/test-output'; // Mock path.join to return predictable file paths for cross-platform test consistency // This ensures the same path format regardless of OS (Windows uses \, Unix uses /) mockJoin.mockImplementation((dir, filename) => `${dir}/${filename}`); vi.spyOn(getFlakyTestsModule, 'default').mockResolvedValue([ { name: 'flakyTest', message: 'Test failure message', run_time: '1.5', result: 'failure', classname: 'TestClass', file: 'path/to/file.js', }, { name: 'anotherFlakyTest', message: 'Another test failure', run_time: '2.1', result: 'failure', classname: 'AnotherClass', file: 'path/to/another.js', }, ]); const args = { params: { projectSlug: 'gh/org/repo', }, }; const controller = new AbortController(); const response = await getFlakyTestLogs(args, { signal: controller.signal, }); expect(mockMkdirSync).toHaveBeenCalledWith(getFlakyTestsOutputDirectory(), { recursive: true, }); expect(mockWriteFileSync).toHaveBeenCalledTimes(3); expect(response).toHaveProperty('content'); expect(Array.isArray(response.content)).toBe(true); expect(response.content[0]).toHaveProperty('type', 'text'); expect(response.content[0].text).toContain( 'Found 2 flaky tests that need stabilization', ); expect(response.content[0].text).toContain(getFlakyTestsOutputDirectory()); }); it('should handle no flaky tests found in file output mode', async () => { process.env.FILE_OUTPUT_DIRECTORY = '/tmp/test-output'; vi.spyOn(getFlakyTestsModule, 'default').mockResolvedValue([]); const args = { params: { projectSlug: 'gh/org/repo', }, }; const controller = new AbortController(); const response = await getFlakyTestLogs(args, { signal: controller.signal, }); expect(response).toHaveProperty('content'); expect(response.content[0].text).toBe( 'No flaky tests found - no files created', ); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CircleCI-Public/mcp-server-circleci'

If you have feedback or need assistance with the MCP directory API, please join our Discord server