ActivityWatch MCP Server

import { describe, it, expect, beforeEach, jest } from '@jest/globals'; import axios, { AxiosError } from 'axios'; import { activitywatch_list_buckets_tool } from './bucketList.js'; jest.mock('axios'); const mockedAxios = axios as jest.Mocked<typeof axios>; describe('activitywatch_list_buckets Tool', () => { beforeEach(() => { jest.clearAllMocks(); }); it('should fetch and format buckets correctly', async () => { const mockBuckets = { 'aw-watcher-window_hostname': { type: 'window', client: 'aw-watcher-window', hostname: 'hostname', created: '2024-02-19T10:00:00.000Z', data: { key: 'value' } } }; mockedAxios.get.mockResolvedValueOnce({ data: mockBuckets }); const result = await activitywatch_list_buckets_tool.handler({}); expect(result.content[0].type).toBe('text'); const parsedContent = JSON.parse(result.content[0].text); expect(parsedContent).toHaveLength(1); expect(parsedContent[0].type).toBe('window'); expect(parsedContent[0].data).toBeUndefined(); expect(parsedContent[0].id).toBe('aw-watcher-window_hostname'); }); it('should filter buckets by type case-insensitively', async () => { const mockBuckets = { 'aw-watcher-window_hostname': { type: 'window', client: 'aw-watcher-window', hostname: 'hostname', created: '2024-02-19T10:00:00.000Z' }, 'aw-watcher-afk_hostname': { type: 'afk', client: 'aw-watcher-afk', hostname: 'hostname', created: '2024-02-19T10:00:00.000Z' } }; mockedAxios.get.mockResolvedValueOnce({ data: mockBuckets }); // Test with uppercase filter const result = await activitywatch_list_buckets_tool.handler({ type: 'WINDOW' }); const parsedContent = JSON.parse(result.content[0].text); expect(parsedContent).toHaveLength(1); expect(parsedContent[0].type).toBe('window'); }); it('should handle invalid type filter gracefully', async () => { const mockBuckets = { 'aw-watcher-window_hostname': { type: 'window', client: 'aw-watcher-window', hostname: 'hostname', created: '2024-02-19T10:00:00.000Z' } }; mockedAxios.get.mockResolvedValueOnce({ data: mockBuckets }); const result = await activitywatch_list_buckets_tool.handler({ type: undefined }); const parsedContent = JSON.parse(result.content[0].text); expect(parsedContent).toHaveLength(1); // Should return all buckets }); it('should include data when includeData is true', async () => { const mockBuckets = { 'aw-watcher-window_hostname': { type: 'window', client: 'aw-watcher-window', hostname: 'hostname', created: '2024-02-19T10:00:00.000Z', data: { key: 'value' } } }; mockedAxios.get.mockResolvedValueOnce({ data: mockBuckets }); const result = await activitywatch_list_buckets_tool.handler({ includeData: true }); const parsedContent = JSON.parse(result.content[0].text); expect(parsedContent[0].data).toBeDefined(); expect(parsedContent[0].data.key).toBe('value'); }); it('should handle API errors with status codes', async () => { const mockError = new Error('Request failed with status code 404') as AxiosError; mockError.isAxiosError = true; mockError.response = { status: 404, statusText: 'Not Found', headers: {}, config: {} as any, data: 'Not Found' }; mockedAxios.get.mockRejectedValueOnce(mockError); const result = await activitywatch_list_buckets_tool.handler({}); expect(result.isError).toBe(true); expect(result.content[0].text).toContain('Failed to fetch buckets'); expect(result.content[0].text).toContain('404'); }); it('should handle non-Axios errors', async () => { mockedAxios.get.mockRejectedValueOnce(new Error('Generic Error')); const result = await activitywatch_list_buckets_tool.handler({}); expect(result.isError).toBe(true); expect(result.content[0].text).toContain('Failed to fetch buckets: Generic Error'); }); it('should handle network errors without status code', async () => { const mockError = new Error('Network Error') as AxiosError; mockError.isAxiosError = true; mockError.message = 'Network Error'; // No response property to simulate network error mockedAxios.get.mockRejectedValueOnce(mockError); const result = await activitywatch_list_buckets_tool.handler({}); expect(result.isError).toBe(true); expect(result.content[0].text).toBe('Failed to fetch buckets: Network Error'); }); });