'Afraid to Ask' implemented

This commit is contained in:
aodulov
2025-10-13 13:14:30 +03:00
parent 09269190c1
commit 5f8541a5f3
20 changed files with 2081 additions and 190 deletions

View File

@@ -6,30 +6,37 @@ import { LLMService } from '../src/services/LLMService';
// Mock the LLMService
jest.mock('../src/services/LLMService');
// Mock the ws module
const mockHandleWebSocketMessage = jest.fn();
const mockSessions = new Map<string, any>();
const mockBroadcastToSession = jest.fn();
jest.mock('../src/ws', () => ({
sessions: mockSessions,
handleWebSocketMessage: mockHandleWebSocketMessage,
broadcastToSession: mockBroadcastToSession,
SessionState: {
SETUP: 'SETUP',
GATHERING: 'GATHERING',
HARMONIZING: 'HARMONIZING',
FINAL: 'FINAL',
ERROR: 'ERROR',
},
}));
// Mock the routes
const app = express();
app.use(express.json());
// Mock session storage for testing analyze endpoint
const mockSessions = new Map<string, any>();
mockSessions.set('test-session-id', { /* session data */ });
app.post('/sessions', (req, res) => {
res.status(201).json({ sessionId: 'mock-session-id' });
});
app.post('/sessions/:sessionId/analyze', async (req, res) => {
const { sessionId } = req.params;
if (!mockSessions.has(sessionId)) {
return res.status(404).send('Session not found');
}
// Mock LLMService call
const mockLLMService = new LLMService('mock-api-key');
const analysisResult = await mockLLMService.analyzeDesires(req.body.allDesires);
res.status(202).json({ message: 'Analysis triggered', result: analysisResult });
});
// Import the actual router after mocks are set up
import sessionsRouter from '../src/routes/sessions';
app.use('/', sessionsRouter);
describe('POST /sessions', () => {
beforeEach(() => {
mockSessions.clear();
});
it('should create a new session and return a session ID', async () => {
const response = await request(app)
.post('/sessions')
@@ -38,42 +45,136 @@ describe('POST /sessions', () => {
expect(response.status).toBe(201);
expect(response.body).toHaveProperty('sessionId');
expect(typeof response.body.sessionId).toBe('string');
expect(mockSessions.has(response.body.sessionId)).toBe(true);
});
});
describe('POST /sessions/:sessionId/analyze', () => {
it('should trigger analysis for a valid session', async () => {
const mockDesires = [
{ wants: ['item1'], accepts: [], noGoes: [] },
{ wants: ['item2'], accepts: [], noGoes: [] },
];
describe('POST /sessions/:sessionId/responses', () => {
const testSessionId = 'test-session-id';
const testUserId = 'test-user-id';
// Mock the analyzeDesires method to return a predictable result
(LLMService as jest.Mock).mockImplementation(() => ({
analyzeDesires: jest.fn().mockResolvedValue({
"item1": "Concept A",
"item2": "Concept A"
}),
}));
beforeEach(() => {
mockSessions.clear();
mockHandleWebSocketMessage.mockClear();
mockBroadcastToSession.mockClear();
// Initialize a session for testing
mockSessions.set(testSessionId, {
state: 'GATHERING',
topic: 'Test Topic',
expectedResponses: 1,
submittedCount: 0,
responses: new Map(),
clients: new Map(),
finalResult: null,
});
});
it('should accept a response with afraidToAsk and call handleWebSocketMessage', async () => {
const responsePayload = {
userId: testUserId,
wants: ['More features'],
accepts: ['Bug fixes'],
afraidToAsk: 'A raise',
};
const response = await request(app)
.post('/sessions/test-session-id/analyze')
.send({ allDesires: mockDesires });
.post(`/sessions/${testSessionId}/responses`)
.send(responsePayload);
expect(response.status).toBe(202);
expect(response.body).toHaveProperty('message', 'Analysis triggered');
expect(response.body).toHaveProperty('result');
expect(response.body.result).toEqual({
"item1": "Concept A",
"item2": "Concept A"
expect(response.body).toEqual({ message: 'Response submission acknowledged and processed.' });
expect(mockHandleWebSocketMessage).toHaveBeenCalledTimes(1);
expect(mockHandleWebSocketMessage).toHaveBeenCalledWith(
expect.any(Object), // dummyWs
testSessionId,
{
type: 'SUBMIT_RESPONSE',
clientId: testUserId,
payload: {
response: {
wants: ['More features'],
accepts: ['Bug fixes'],
afraidToAsk: 'A raise',
},
},
}
);
});
it('should return 404 if session is not found', async () => {
const responsePayload = {
userId: testUserId,
wants: ['More features'],
accepts: ['Bug fixes'],
afraidToAsk: 'A raise',
};
const response = await request(app)
.post(`/sessions/non-existent-session/responses`)
.send(responsePayload);
expect(response.status).toBe(404);
expect(response.body).toEqual({ message: 'Session not found.' });
expect(mockHandleWebSocketMessage).not.toHaveBeenCalled();
});
it('should return 500 if handleWebSocketMessage throws an error', async () => {
mockHandleWebSocketMessage.mockRejectedValueOnce(new Error('WebSocket processing error'));
const responsePayload = {
userId: testUserId,
wants: ['More features'],
accepts: ['Bug fixes'],
afraidToAsk: 'A raise',
};
const response = await request(app)
.post(`/sessions/${testSessionId}/responses`)
.send(responsePayload);
expect(response.status).toBe(500);
expect(response.body).toHaveProperty('message', 'Error processing response.');
expect(response.body).toHaveProperty('error', 'WebSocket processing error');
expect(mockHandleWebSocketMessage).toHaveBeenCalledTimes(1);
});
});
describe('POST /sessions/:sessionId/terminate', () => {
const testSessionId = 'session-to-terminate';
beforeEach(() => {
mockSessions.clear();
// Initialize a session for testing termination
mockSessions.set(testSessionId, {
state: 'FINAL',
topic: 'Test Topic',
expectedResponses: 1,
submittedCount: 1,
responses: new Map([['client1', { wants: ['test'], accepts: [], noGoes: [], afraidToAsk: 'secret' }]]),
clients: new Map(),
finalResult: { goTo: 'test' },
});
});
it('should terminate the session and purge its data', async () => {
expect(mockSessions.has(testSessionId)).toBe(true);
const response = await request(app)
.post(`/sessions/${testSessionId}/terminate`)
.send();
expect(response.status).toBe(200);
expect(response.body).toEqual({ message: 'Session terminated and data purged successfully.' });
expect(mockSessions.has(testSessionId)).toBe(false);
});
it('should return 404 if session is not found', async () => {
const response = await request(app)
.post('/sessions/non-existent-session/analyze')
.send({ allDesires: [] });
.post(`/sessions/non-existent-session/terminate`)
.send();
expect(response.status).toBe(404);
expect(response.body).toEqual({ message: 'Session not found.' });
});
});