feishu-mcp
Version:
Model Context Protocol server for Feishu integration
99 lines (98 loc) • 4.15 kB
JavaScript
import { createTasks, listTasks, updateTask, deleteTasks } from '../taskToolApi.js';
function createMockApi() {
const calls = [];
return {
createTasksNested: async (rootItems) => {
calls.push({ method: 'createTasksNested', args: [rootItems] });
return { results: rootItems.map((r) => ({ task: { guid: 'mock', summary: r.summary } })), errors: [] };
},
listTasks: async (pageToken, completed) => {
calls.push({ method: 'listTasks', args: [pageToken, completed] });
return { items: [], has_more: false };
},
updateTask: async (taskGuid, params) => {
calls.push({ method: 'updateTask', args: [taskGuid, params] });
return { task: { guid: taskGuid } };
},
addTaskMembers: async () => ({}),
removeTaskMembers: async () => ({}),
addTaskReminder: async () => ({}),
removeTaskReminders: async () => ({}),
deleteTasks: async (guids) => {
calls.push({ method: 'deleteTasks', args: [guids] });
return { deleted: guids, errors: [] };
},
get _calls() {
return calls;
},
};
}
describe('taskToolApi', () => {
describe('createTasks', () => {
it('应校验参数并转换 TaskCreateItem 为 RootNestedCreateItem', async () => {
const mockApi = createMockApi();
const taskItems = [
{
summary: '任务1',
assigneeIds: ['ou_xxx'],
description: '描述',
},
];
const result = await createTasks(taskItems, mockApi);
const calls = mockApi._calls;
expect(calls).toHaveLength(1);
expect(calls[0].method).toBe('createTasksNested');
const rootItems = calls[0].args[0];
expect(rootItems).toHaveLength(1);
expect(rootItems[0].summary).toBe('任务1');
expect(rootItems[0].members).toEqual([{ id: 'ou_xxx', type: 'user', role: 'assignee' }]);
expect(rootItems[0].description).toBe('描述');
expect(result.results).toHaveLength(1);
});
it('空数组应抛出校验错误', async () => {
const mockApi = createMockApi();
await expect(createTasks([], mockApi)).rejects.toThrow(/参数校验失败/);
expect(mockApi._calls).toHaveLength(0);
});
});
describe('listTasks', () => {
it('应透传 pageToken 和 completed', async () => {
const mockApi = createMockApi();
await listTasks({ pageToken: 'pt', completed: true }, mockApi);
const calls = mockApi._calls;
expect(calls[0].args).toEqual(['pt', true]);
});
});
describe('updateTask', () => {
it('至少需要一项更新', async () => {
const mockApi = createMockApi();
await expect(updateTask({ taskGuid: 'g1' }, mockApi)).rejects.toThrow(/至少需要一项更新/);
});
it('应正确转换字段更新', async () => {
const mockApi = createMockApi();
await updateTask({
taskGuid: 'g1',
summary: '新标题',
dueTimestamp: '123',
isDueAllDay: true,
}, mockApi);
const calls = mockApi._calls;
expect(calls[0].args).toEqual([
'g1',
{ summary: '新标题', due: { timestamp: '123', is_all_day: true } },
]);
});
});
describe('deleteTasks', () => {
it('应校验 taskGuids 并调用 deleteTasks', async () => {
const mockApi = createMockApi();
const result = await deleteTasks(['g1'], mockApi);
expect(mockApi._calls[0].args[0]).toEqual(['g1']);
expect(result.deleted).toEqual(['g1']);
});
it('空数组应抛出校验错误', async () => {
const mockApi = createMockApi();
await expect(deleteTasks([], mockApi)).rejects.toThrow(/参数校验失败/);
});
});
});