import { describe, it, expect, vi, beforeEach } from 'vitest';
import { reply } from '../../src/tools/reply.js';
import type { RegistryApiClient } from '../../src/client/api.js';
import { testMessage } from '../fixtures/keys.js';
describe('tools/reply', () => {
let mockClient: RegistryApiClient;
beforeEach(() => {
mockClient = {
replyToThread: vi.fn(),
} as unknown as RegistryApiClient;
});
it('should reply to a thread', async () => {
vi.mocked(mockClient.replyToThread).mockResolvedValue({
message_id: 'msg-reply',
thread_id: testMessage.thread_id!,
});
const result = await reply(
{
threadId: testMessage.thread_id!,
body: 'Thanks for your message!',
},
mockClient
);
expect(mockClient.replyToThread).toHaveBeenCalledWith(
testMessage.thread_id,
'Thanks for your message!',
undefined
);
expect(result.success).toBe(true);
expect(result.messageId).toBe('msg-reply');
expect(result.threadId).toBe(testMessage.thread_id);
});
it('should include metadata when provided', async () => {
vi.mocked(mockClient.replyToThread).mockResolvedValue({
message_id: 'msg-reply',
thread_id: testMessage.thread_id!,
});
await reply(
{
threadId: testMessage.thread_id!,
body: 'Response with metadata',
metadata: { read_receipt: true },
},
mockClient
);
expect(mockClient.replyToThread).toHaveBeenCalledWith(
testMessage.thread_id,
'Response with metadata',
{ read_receipt: true }
);
});
it('should handle reply failure', async () => {
vi.mocked(mockClient.replyToThread).mockRejectedValue(new Error('Thread not found'));
const result = await reply(
{
threadId: '99999999-9999-9999-9999-999999999999',
body: 'Reply to unknown thread',
},
mockClient
);
expect(result.success).toBe(false);
expect(result.error).toContain('Thread not found');
});
it('should handle permission denied', async () => {
vi.mocked(mockClient.replyToThread).mockRejectedValue(
new Error('Not authorized to reply to this thread')
);
const result = await reply(
{
threadId: testMessage.thread_id!,
body: 'Unauthorized reply',
},
mockClient
);
expect(result.success).toBe(false);
expect(result.error).toContain('Not authorized');
});
});