Skip to main content
Glama
im47cn

Feishu Project MCP Server

by im47cn
feishu.test.ts6.58 kB
import axios from 'axios'; import { FeishuIntegrator, FeishuIntegratorConfig } from '../../integrators/feishu'; import { Logger, LogLevel } from '../../utils/logger'; import { FeishuItemType } from '../../types/feishu'; jest.mock('axios'); jest.mock('../../utils/logger'); describe('FeishuIntegrator', () => { let integrator: FeishuIntegrator; let config: FeishuIntegratorConfig; let logger: jest.Mocked<Logger>; let mockedAxios: jest.Mocked<typeof axios>; beforeEach(() => { // Mock configuration config = { apiToken: 'test-token', apiUrl: 'https://test-api.feishu.cn', requestTimeout: 5000, }; // Mock logger logger = new Logger({ level: LogLevel.INFO, directory: './logs', }) as jest.Mocked<Logger>; // Mock axios mockedAxios = axios as jest.Mocked<typeof axios>; mockedAxios.create.mockReturnValue(mockedAxios as any); // Create integrator instance integrator = new FeishuIntegrator(config, logger); }); afterEach(() => { jest.clearAllMocks(); }); describe('getProjects', () => { it('should fetch projects successfully', async () => { const mockProjects = { code: 0, data: [ { id: 'project1', name: 'Test Project', createdAt: '2025-03-22T00:00:00Z', updatedAt: '2025-03-22T00:00:00Z', }, ], }; mockedAxios.get.mockResolvedValueOnce({ data: mockProjects }); const result = await integrator.getProjects(); expect(result).toEqual(mockProjects.data); expect(mockedAxios.get).toHaveBeenCalledWith('/projects'); }); it('should handle API errors', async () => { const error = new Error('API Error'); mockedAxios.get.mockRejectedValueOnce(error); await expect(integrator.getProjects()).rejects.toThrow(error); expect(logger.error).toHaveBeenCalledWith('Failed to get projects', { error }); }); }); describe('getRequirements', () => { const projectId = 'project1'; const filter = { status: ['open'], assignee: 'user1' }; it('should fetch requirements successfully', async () => { const mockRequirements = { code: 0, data: [ { id: 'req1', title: 'Test Requirement', type: FeishuItemType.REQUIREMENT, status: 'open', creator: 'user1', projectId: 'project1', createdAt: '2025-03-22T00:00:00Z', updatedAt: '2025-03-22T00:00:00Z', }, ], }; mockedAxios.get.mockResolvedValueOnce({ data: mockRequirements }); const result = await integrator.getRequirements(projectId, filter); expect(result).toEqual(mockRequirements.data); expect(mockedAxios.get).toHaveBeenCalledWith('/requirements', { params: { project_id: projectId, ...filter, }, }); }); it('should handle API errors', async () => { const error = new Error('API Error'); mockedAxios.get.mockRejectedValueOnce(error); await expect(integrator.getRequirements(projectId)).rejects.toThrow(error); expect(logger.error).toHaveBeenCalledWith('Failed to get requirements', { error, projectId, }); }); }); describe('getBugs', () => { const projectId = 'project1'; const filter = { status: ['open'], severity: ['high'] }; it('should fetch bugs successfully', async () => { const mockBugs = { code: 0, data: [ { id: 'bug1', title: 'Test Bug', type: FeishuItemType.BUG, severity: 'high', status: 'open', creator: 'user1', projectId: 'project1', createdAt: '2025-03-22T00:00:00Z', updatedAt: '2025-03-22T00:00:00Z', }, ], }; mockedAxios.get.mockResolvedValueOnce({ data: mockBugs }); const result = await integrator.getBugs(projectId, filter); expect(result).toEqual(mockBugs.data); expect(mockedAxios.get).toHaveBeenCalledWith('/bugs', { params: { project_id: projectId, ...filter, }, }); }); it('should handle API errors', async () => { const error = new Error('API Error'); mockedAxios.get.mockRejectedValueOnce(error); await expect(integrator.getBugs(projectId)).rejects.toThrow(error); expect(logger.error).toHaveBeenCalledWith('Failed to get bugs', { error, projectId, }); }); }); describe('updateItemStatus', () => { const itemId = 'item1'; const status = 'in_progress'; it('should update item status successfully', async () => { const mockResponse = { code: 0, data: { success: true }, }; mockedAxios.patch.mockResolvedValueOnce({ data: mockResponse }); await integrator.updateItemStatus(itemId, status); expect(mockedAxios.patch).toHaveBeenCalledWith(`/item/${itemId}`, { status, }); }); it('should handle API errors', async () => { const error = new Error('API Error'); mockedAxios.patch.mockRejectedValueOnce(error); await expect(integrator.updateItemStatus(itemId, status)).rejects.toThrow(error); expect(logger.error).toHaveBeenCalledWith('Failed to update item status', { error, itemId, status, }); }); }); describe('addComment', () => { const itemId = 'item1'; const content = 'Test comment'; it('should add comment successfully', async () => { const mockComment = { code: 0, data: { id: 'comment1', content, creator: 'user1', itemId, createdAt: '2025-03-22T00:00:00Z', updatedAt: '2025-03-22T00:00:00Z', }, }; mockedAxios.post.mockResolvedValueOnce({ data: mockComment }); const result = await integrator.addComment(itemId, content); expect(result).toEqual(mockComment.data); expect(mockedAxios.post).toHaveBeenCalledWith(`/item/${itemId}/comments`, { content, }); }); it('should handle API errors', async () => { const error = new Error('API Error'); mockedAxios.post.mockRejectedValueOnce(error); await expect(integrator.addComment(itemId, content)).rejects.toThrow(error); expect(logger.error).toHaveBeenCalledWith('Failed to add comment', { error, itemId, }); }); }); });

Latest Blog Posts

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/im47cn/feishu-project-mcp'

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