mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 14:22:02 +00:00
747 lines
22 KiB
TypeScript
747 lines
22 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { AgentService } from '@/services/agent-service.js';
|
|
import { ProviderFactory } from '@/providers/provider-factory.js';
|
|
import * as fs from 'fs/promises';
|
|
import * as imageHandler from '@automaker/utils';
|
|
import * as promptBuilder from '@automaker/utils';
|
|
import * as contextLoader from '@automaker/utils';
|
|
import { collectAsyncGenerator } from '../../utils/helpers.js';
|
|
|
|
// Create a shared mock logger instance for assertions using vi.hoisted
|
|
const mockLogger = vi.hoisted(() => ({
|
|
info: vi.fn(),
|
|
error: vi.fn(),
|
|
warn: vi.fn(),
|
|
debug: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('fs/promises');
|
|
vi.mock('@/providers/provider-factory.js');
|
|
vi.mock('@automaker/utils', async () => {
|
|
const actual = await vi.importActual<typeof import('@automaker/utils')>('@automaker/utils');
|
|
return {
|
|
...actual,
|
|
loadContextFiles: vi.fn(),
|
|
buildPromptWithImages: vi.fn(),
|
|
readImageAsBase64: vi.fn(),
|
|
createLogger: vi.fn(() => mockLogger),
|
|
};
|
|
});
|
|
|
|
describe('agent-service.ts', () => {
|
|
let service: AgentService;
|
|
const mockEvents = {
|
|
subscribe: vi.fn(),
|
|
emit: vi.fn(),
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
service = new AgentService('/test/data', mockEvents as any);
|
|
|
|
// Mock loadContextFiles to return empty context by default
|
|
vi.mocked(contextLoader.loadContextFiles).mockResolvedValue({
|
|
files: [],
|
|
formattedPrompt: '',
|
|
});
|
|
});
|
|
|
|
describe('initialize', () => {
|
|
it('should create state directory', async () => {
|
|
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
|
|
|
|
await service.initialize();
|
|
|
|
expect(fs.mkdir).toHaveBeenCalledWith(expect.stringContaining('agent-sessions'), {
|
|
recursive: true,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('startConversation', () => {
|
|
it('should create new session with empty messages', async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
|
|
const result = await service.startConversation({
|
|
sessionId: 'session-1',
|
|
workingDirectory: '/test/dir',
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.messages).toEqual([]);
|
|
expect(result.sessionId).toBe('session-1');
|
|
});
|
|
|
|
it('should load existing session', async () => {
|
|
const existingMessages = [
|
|
{
|
|
id: 'msg-1',
|
|
role: 'user',
|
|
content: 'Hello',
|
|
timestamp: '2024-01-01T00:00:00Z',
|
|
},
|
|
];
|
|
|
|
vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(existingMessages));
|
|
|
|
const result = await service.startConversation({
|
|
sessionId: 'session-1',
|
|
workingDirectory: '/test/dir',
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.messages).toEqual(existingMessages);
|
|
});
|
|
|
|
it('should use process.cwd() if no working directory provided', async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
|
|
const result = await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
it('should reuse existing session if already started', async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
|
|
// Start session first time
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
|
|
// Start again with same ID
|
|
const result = await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
// First call reads session file, metadata file, and queue state file (3 calls)
|
|
// Second call should reuse in-memory session (no additional calls)
|
|
expect(fs.readFile).toHaveBeenCalledTimes(3);
|
|
});
|
|
});
|
|
|
|
describe('sendMessage', () => {
|
|
beforeEach(async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
|
|
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
workingDirectory: '/test/dir',
|
|
});
|
|
});
|
|
|
|
it('should throw if session not found', async () => {
|
|
await expect(
|
|
service.sendMessage({
|
|
sessionId: 'nonexistent',
|
|
message: 'Hello',
|
|
})
|
|
).rejects.toThrow('Session nonexistent not found');
|
|
});
|
|
|
|
it('should process message and stream responses', async () => {
|
|
const mockProvider = {
|
|
getName: () => 'claude',
|
|
executeQuery: async function* () {
|
|
yield {
|
|
type: 'assistant',
|
|
message: {
|
|
role: 'assistant',
|
|
content: [{ type: 'text', text: 'Response' }],
|
|
},
|
|
};
|
|
yield {
|
|
type: 'result',
|
|
subtype: 'success',
|
|
};
|
|
},
|
|
};
|
|
|
|
vi.mocked(ProviderFactory.getProviderForModel).mockReturnValue(mockProvider as any);
|
|
|
|
vi.mocked(promptBuilder.buildPromptWithImages).mockResolvedValue({
|
|
content: 'Hello',
|
|
hasImages: false,
|
|
});
|
|
|
|
const result = await service.sendMessage({
|
|
sessionId: 'session-1',
|
|
message: 'Hello',
|
|
workingDirectory: '/custom/dir',
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(mockEvents.emit).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle images in message', async () => {
|
|
const mockProvider = {
|
|
getName: () => 'claude',
|
|
executeQuery: async function* () {
|
|
yield {
|
|
type: 'result',
|
|
subtype: 'success',
|
|
};
|
|
},
|
|
};
|
|
|
|
vi.mocked(ProviderFactory.getProviderForModel).mockReturnValue(mockProvider as any);
|
|
|
|
vi.mocked(imageHandler.readImageAsBase64).mockResolvedValue({
|
|
base64: 'base64data',
|
|
mimeType: 'image/png',
|
|
filename: 'test.png',
|
|
originalPath: '/path/test.png',
|
|
});
|
|
|
|
vi.mocked(promptBuilder.buildPromptWithImages).mockResolvedValue({
|
|
content: 'Check image',
|
|
hasImages: true,
|
|
});
|
|
|
|
await service.sendMessage({
|
|
sessionId: 'session-1',
|
|
message: 'Check this',
|
|
imagePaths: ['/path/test.png'],
|
|
});
|
|
|
|
expect(imageHandler.readImageAsBase64).toHaveBeenCalledWith('/path/test.png');
|
|
});
|
|
|
|
it('should handle failed image loading gracefully', async () => {
|
|
const mockProvider = {
|
|
getName: () => 'claude',
|
|
executeQuery: async function* () {
|
|
yield {
|
|
type: 'result',
|
|
subtype: 'success',
|
|
};
|
|
},
|
|
};
|
|
|
|
vi.mocked(ProviderFactory.getProviderForModel).mockReturnValue(mockProvider as any);
|
|
|
|
vi.mocked(imageHandler.readImageAsBase64).mockRejectedValue(new Error('Image not found'));
|
|
|
|
vi.mocked(promptBuilder.buildPromptWithImages).mockResolvedValue({
|
|
content: 'Check image',
|
|
hasImages: false,
|
|
});
|
|
|
|
await service.sendMessage({
|
|
sessionId: 'session-1',
|
|
message: 'Check this',
|
|
imagePaths: ['/path/test.png'],
|
|
});
|
|
|
|
expect(mockLogger.error).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should use custom model if provided', async () => {
|
|
const mockProvider = {
|
|
getName: () => 'claude',
|
|
executeQuery: async function* () {
|
|
yield {
|
|
type: 'result',
|
|
subtype: 'success',
|
|
};
|
|
},
|
|
};
|
|
|
|
vi.mocked(ProviderFactory.getProviderForModel).mockReturnValue(mockProvider as any);
|
|
|
|
vi.mocked(promptBuilder.buildPromptWithImages).mockResolvedValue({
|
|
content: 'Hello',
|
|
hasImages: false,
|
|
});
|
|
|
|
await service.sendMessage({
|
|
sessionId: 'session-1',
|
|
message: 'Hello',
|
|
model: 'claude-sonnet-4-20250514',
|
|
});
|
|
|
|
expect(ProviderFactory.getProviderForModel).toHaveBeenCalledWith('claude-sonnet-4-20250514');
|
|
});
|
|
|
|
it('should save session messages', async () => {
|
|
const mockProvider = {
|
|
getName: () => 'claude',
|
|
executeQuery: async function* () {
|
|
yield {
|
|
type: 'result',
|
|
subtype: 'success',
|
|
};
|
|
},
|
|
};
|
|
|
|
vi.mocked(ProviderFactory.getProviderForModel).mockReturnValue(mockProvider as any);
|
|
|
|
vi.mocked(promptBuilder.buildPromptWithImages).mockResolvedValue({
|
|
content: 'Hello',
|
|
hasImages: false,
|
|
});
|
|
|
|
await service.sendMessage({
|
|
sessionId: 'session-1',
|
|
message: 'Hello',
|
|
});
|
|
|
|
expect(fs.writeFile).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('stopExecution', () => {
|
|
it('should stop execution for a session', async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
|
|
// Should return success
|
|
const result = await service.stopExecution('session-1');
|
|
expect(result.success).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('getHistory', () => {
|
|
it('should return message history', async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
|
|
const history = service.getHistory('session-1');
|
|
|
|
expect(history).toBeDefined();
|
|
expect(history?.messages).toEqual([]);
|
|
});
|
|
|
|
it('should handle non-existent session', () => {
|
|
const history = service.getHistory('nonexistent');
|
|
expect(history).toBeDefined(); // Returns error object
|
|
});
|
|
});
|
|
|
|
describe('clearSession', () => {
|
|
it('should clear session messages', async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
|
|
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
|
|
await service.clearSession('session-1');
|
|
|
|
const history = service.getHistory('session-1');
|
|
expect(history?.messages).toEqual([]);
|
|
expect(fs.writeFile).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('createSession', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(fs.readFile).mockResolvedValue('{}');
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
});
|
|
|
|
it('should create a new session with metadata', async () => {
|
|
const session = await service.createSession('Test Session', '/test/project', '/test/dir');
|
|
|
|
expect(session.id).toBeDefined();
|
|
expect(session.name).toBe('Test Session');
|
|
expect(session.projectPath).toBe('/test/project');
|
|
expect(session.workingDirectory).toBeDefined();
|
|
expect(session.createdAt).toBeDefined();
|
|
expect(session.updatedAt).toBeDefined();
|
|
});
|
|
|
|
it('should use process.cwd() if no working directory provided', async () => {
|
|
const session = await service.createSession('Test Session');
|
|
|
|
expect(session.workingDirectory).toBeDefined();
|
|
});
|
|
|
|
it('should validate working directory', async () => {
|
|
// Set ALLOWED_ROOT_DIRECTORY to restrict paths
|
|
const originalAllowedRoot = process.env.ALLOWED_ROOT_DIRECTORY;
|
|
process.env.ALLOWED_ROOT_DIRECTORY = '/allowed/projects';
|
|
|
|
// Re-import platform to initialize with new env var
|
|
vi.resetModules();
|
|
const { initAllowedPaths } = await import('@automaker/platform');
|
|
initAllowedPaths();
|
|
|
|
const { AgentService } = await import('@/services/agent-service.js');
|
|
const testService = new AgentService('/test/data', mockEvents as any);
|
|
vi.mocked(fs.readFile).mockResolvedValue('{}');
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
|
|
await expect(
|
|
testService.createSession('Test Session', undefined, '/invalid/path')
|
|
).rejects.toThrow();
|
|
|
|
// Restore original value
|
|
if (originalAllowedRoot) {
|
|
process.env.ALLOWED_ROOT_DIRECTORY = originalAllowedRoot;
|
|
} else {
|
|
delete process.env.ALLOWED_ROOT_DIRECTORY;
|
|
}
|
|
vi.resetModules();
|
|
const { initAllowedPaths: reinit } = await import('@automaker/platform');
|
|
reinit();
|
|
});
|
|
});
|
|
|
|
describe('setSessionModel', () => {
|
|
beforeEach(async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
|
|
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
});
|
|
|
|
it('should set model for existing session', async () => {
|
|
vi.mocked(fs.readFile).mockResolvedValue('{"session-1": {}}');
|
|
const result = await service.setSessionModel('session-1', 'claude-sonnet-4-20250514');
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should return false for non-existent session', async () => {
|
|
const result = await service.setSessionModel('nonexistent', 'claude-sonnet-4-20250514');
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('updateSession', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(fs.readFile).mockResolvedValue(
|
|
JSON.stringify({
|
|
'session-1': {
|
|
id: 'session-1',
|
|
name: 'Test Session',
|
|
createdAt: '2024-01-01T00:00:00Z',
|
|
updatedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
})
|
|
);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
});
|
|
|
|
it('should update session metadata', async () => {
|
|
const result = await service.updateSession('session-1', { name: 'Updated Name' });
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.name).toBe('Updated Name');
|
|
expect(result?.updatedAt).not.toBe('2024-01-01T00:00:00Z');
|
|
});
|
|
|
|
it('should return null for non-existent session', async () => {
|
|
const result = await service.updateSession('nonexistent', { name: 'Updated Name' });
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('archiveSession', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(fs.readFile).mockResolvedValue(
|
|
JSON.stringify({
|
|
'session-1': {
|
|
id: 'session-1',
|
|
name: 'Test Session',
|
|
createdAt: '2024-01-01T00:00:00Z',
|
|
updatedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
})
|
|
);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
});
|
|
|
|
it('should archive a session', async () => {
|
|
const result = await service.archiveSession('session-1');
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should return false for non-existent session', async () => {
|
|
const result = await service.archiveSession('nonexistent');
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('unarchiveSession', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(fs.readFile).mockResolvedValue(
|
|
JSON.stringify({
|
|
'session-1': {
|
|
id: 'session-1',
|
|
name: 'Test Session',
|
|
archived: true,
|
|
createdAt: '2024-01-01T00:00:00Z',
|
|
updatedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
})
|
|
);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
});
|
|
|
|
it('should unarchive a session', async () => {
|
|
const result = await service.unarchiveSession('session-1');
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should return false for non-existent session', async () => {
|
|
const result = await service.unarchiveSession('nonexistent');
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('deleteSession', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(fs.readFile).mockResolvedValue(
|
|
JSON.stringify({
|
|
'session-1': {
|
|
id: 'session-1',
|
|
name: 'Test Session',
|
|
createdAt: '2024-01-01T00:00:00Z',
|
|
updatedAt: '2024-01-01T00:00:00Z',
|
|
},
|
|
})
|
|
);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
vi.mocked(fs.unlink).mockResolvedValue(undefined);
|
|
});
|
|
|
|
it('should delete a session', async () => {
|
|
const result = await service.deleteSession('session-1');
|
|
|
|
expect(result).toBe(true);
|
|
expect(fs.writeFile).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return false for non-existent session', async () => {
|
|
const result = await service.deleteSession('nonexistent');
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('listSessions', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(fs.readFile).mockResolvedValue(
|
|
JSON.stringify({
|
|
'session-1': {
|
|
id: 'session-1',
|
|
name: 'Test Session 1',
|
|
createdAt: '2024-01-01T00:00:00Z',
|
|
updatedAt: '2024-01-02T00:00:00Z',
|
|
archived: false,
|
|
},
|
|
'session-2': {
|
|
id: 'session-2',
|
|
name: 'Test Session 2',
|
|
createdAt: '2024-01-01T00:00:00Z',
|
|
updatedAt: '2024-01-03T00:00:00Z',
|
|
archived: true,
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it('should list non-archived sessions by default', async () => {
|
|
const sessions = await service.listSessions();
|
|
|
|
expect(sessions.length).toBe(1);
|
|
expect(sessions[0].id).toBe('session-1');
|
|
});
|
|
|
|
it('should include archived sessions when requested', async () => {
|
|
const sessions = await service.listSessions(true);
|
|
|
|
expect(sessions.length).toBe(2);
|
|
});
|
|
|
|
it('should sort sessions by updatedAt descending', async () => {
|
|
const sessions = await service.listSessions(true);
|
|
|
|
expect(sessions[0].id).toBe('session-2');
|
|
expect(sessions[1].id).toBe('session-1');
|
|
});
|
|
});
|
|
|
|
describe('addToQueue', () => {
|
|
beforeEach(async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
|
|
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
});
|
|
|
|
it('should add prompt to queue', async () => {
|
|
const result = await service.addToQueue('session-1', {
|
|
message: 'Test prompt',
|
|
imagePaths: ['/test/image.png'],
|
|
model: 'claude-sonnet-4-20250514',
|
|
});
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.queuedPrompt).toBeDefined();
|
|
expect(result.queuedPrompt?.message).toBe('Test prompt');
|
|
expect(mockEvents.emit).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return error for non-existent session', async () => {
|
|
const result = await service.addToQueue('nonexistent', {
|
|
message: 'Test prompt',
|
|
});
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toBe('Session not found');
|
|
});
|
|
});
|
|
|
|
describe('getQueue', () => {
|
|
beforeEach(async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
|
|
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
});
|
|
|
|
it('should return queue for session', async () => {
|
|
await service.addToQueue('session-1', { message: 'Test prompt' });
|
|
const result = service.getQueue('session-1');
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.queue).toBeDefined();
|
|
expect(result.queue?.length).toBe(1);
|
|
});
|
|
|
|
it('should return error for non-existent session', () => {
|
|
const result = service.getQueue('nonexistent');
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toBe('Session not found');
|
|
});
|
|
});
|
|
|
|
describe('removeFromQueue', () => {
|
|
beforeEach(async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
|
|
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
|
|
const addResult = await service.addToQueue('session-1', { message: 'Test prompt' });
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('should remove prompt from queue', async () => {
|
|
const queueResult = service.getQueue('session-1');
|
|
const promptId = queueResult.queue![0].id;
|
|
|
|
const result = await service.removeFromQueue('session-1', promptId);
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(mockEvents.emit).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return error for non-existent session', async () => {
|
|
const result = await service.removeFromQueue('nonexistent', 'prompt-id');
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toBe('Session not found');
|
|
});
|
|
|
|
it('should return error for non-existent prompt', async () => {
|
|
const result = await service.removeFromQueue('session-1', 'nonexistent-prompt-id');
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toBe('Prompt not found in queue');
|
|
});
|
|
});
|
|
|
|
describe('clearQueue', () => {
|
|
beforeEach(async () => {
|
|
const error: any = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
vi.mocked(fs.readFile).mockRejectedValue(error);
|
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
|
|
|
|
await service.startConversation({
|
|
sessionId: 'session-1',
|
|
});
|
|
|
|
await service.addToQueue('session-1', { message: 'Test prompt 1' });
|
|
await service.addToQueue('session-1', { message: 'Test prompt 2' });
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('should clear all prompts from queue', async () => {
|
|
const result = await service.clearQueue('session-1');
|
|
|
|
expect(result.success).toBe(true);
|
|
const queueResult = service.getQueue('session-1');
|
|
expect(queueResult.queue?.length).toBe(0);
|
|
expect(mockEvents.emit).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return error for non-existent session', async () => {
|
|
const result = await service.clearQueue('nonexistent');
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toBe('Session not found');
|
|
});
|
|
});
|
|
});
|