Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions backend/src/__tests__/action-transform.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('Action transformation integration', () => {

afterEach(async () => {
await conversationService._clear();
actionService._clear();
await actionService._clear();
});

function connectWs(): Promise<WebSocket> {
Expand Down Expand Up @@ -109,7 +109,7 @@ describe('Action transformation integration', () => {

it('should transform pendingAction fields in GET /api/actions/pending', async () => {
// Create an action via the service directly
actionService.createAction(
await actionService.createAction(
'transform-test-user',
'test-conv-id',
'create_event',
Expand Down Expand Up @@ -144,7 +144,7 @@ describe('Action transformation integration', () => {
});

it('should transform action fields in reject response', async () => {
const created = actionService.createAction(
const created = await actionService.createAction(
'transform-test-user',
'test-conv-id',
'delete_event',
Expand All @@ -167,7 +167,7 @@ describe('Action transformation integration', () => {

it('should reject action for unauthorized user', async () => {
// Create an action for a different user
const created = actionService.createAction(
const created = await actionService.createAction(
'other-user-id',
'test-conv-id',
'delete_event',
Expand All @@ -182,7 +182,7 @@ describe('Action transformation integration', () => {
});

it('should transform action fields in approve response', async () => {
const created = actionService.createAction(
const created = await actionService.createAction(
'transform-test-user',
'test-conv-id',
'create_event',
Expand Down
18 changes: 9 additions & 9 deletions backend/src/__tests__/approval-modal-crash.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ describe('Approval modal crash fix integration', () => {

afterEach(async () => {
await conversationService._clear();
actionService._clear();
await actionService._clear();
});

it('toFrontendAction should always produce details as an object', () => {
const action = actionService.createAction(
it('toFrontendAction should always produce details as an object', async () => {
const action = await actionService.createAction(
'approval-modal-test-user',
'conv-1',
'create_event',
Expand All @@ -81,8 +81,8 @@ describe('Approval modal crash fix integration', () => {
expect(frontend).not.toHaveProperty('actionType');
});

it('toFrontendAction should produce valid details for delete actions', () => {
const action = actionService.createAction(
it('toFrontendAction should produce valid details for delete actions', async () => {
const action = await actionService.createAction(
'approval-modal-test-user',
'conv-1',
'delete_event',
Expand All @@ -98,8 +98,8 @@ describe('Approval modal crash fix integration', () => {
expect(frontend.type).toBe('delete_event');
});

it('toFrontendAction should produce valid details for update actions', () => {
const action = actionService.createAction(
it('toFrontendAction should produce valid details for update actions', async () => {
const action = await actionService.createAction(
'approval-modal-test-user',
'conv-1',
'update_event',
Expand All @@ -120,7 +120,7 @@ describe('Approval modal crash fix integration', () => {
});

it('GET /api/actions/pending returns details field (not params) for the modal', async () => {
actionService.createAction(
await actionService.createAction(
'approval-modal-test-user',
'conv-1',
'create_event',
Expand Down Expand Up @@ -154,7 +154,7 @@ describe('Approval modal crash fix integration', () => {
});

it('GET /api/actions/pending returns details for delete action with calendarId and eventId', async () => {
actionService.createAction(
await actionService.createAction(
'approval-modal-test-user',
'conv-1',
'delete_event',
Expand Down
4 changes: 2 additions & 2 deletions backend/src/__tests__/approval-ux.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe('Approval UX Integration', () => {

afterEach(async () => {
await conversationService._clear();
actionService._clear();
await actionService._clear();
});

function connectWs(): Promise<WebSocket> {
Expand Down Expand Up @@ -168,7 +168,7 @@ describe('Approval UX Integration', () => {
const conv = await conversationService.createConversation('approval-test-user', 'Test');

// Create a pending action directly
const action = actionService.createAction(
const action = await actionService.createAction(
'approval-test-user',
conv.id,
'create_event',
Expand Down
2 changes: 1 addition & 1 deletion backend/src/__tests__/chat.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe('Chat Integration (real agent)', () => {

afterEach(async () => {
await conversationService._clear();
actionService._clear();
await actionService._clear();
});

function connectWs(): Promise<WebSocket> {
Expand Down
6 changes: 3 additions & 3 deletions backend/src/__tests__/chat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('Chat & HITL API', () => {

afterEach(async () => {
await conversationService._clear();
actionService._clear();
await actionService._clear();
});

function connectWs(cookie?: string): Promise<WebSocket> {
Expand Down Expand Up @@ -261,7 +261,7 @@ describe('Chat & HITL API', () => {
});

it('should reject a pending action', async () => {
const action = actionService.createAction(
const action = await actionService.createAction(
'test-user-1',
'conv-1',
'create_event',
Expand All @@ -281,7 +281,7 @@ describe('Chat & HITL API', () => {
});

it('should return 409 when rejecting an already rejected action', async () => {
const action = actionService.createAction(
const action = await actionService.createAction(
'test-user-1',
'conv-1',
'create_event',
Expand Down
4 changes: 2 additions & 2 deletions backend/src/__tests__/conversationHistory.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ describe('Conversation History Integration', () => {
await new Promise<void>((resolve) => server.close(() => resolve()));
}, 15000);

afterEach(() => {
afterEach(async () => {
conversationService._clear();
actionService._clear();
await actionService._clear();
});

function connectWs(): Promise<WebSocket> {
Expand Down
8 changes: 5 additions & 3 deletions backend/src/__tests__/database.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,11 @@ describe('Database Integration', () => {

// 5. Create pending action
const action = await pendingActionRepo.create({
user_id: user.id,
conversation_id: conv.id,
action_type: 'create_event',
action_payload: { summary: 'Meeting', startDateTime: '2026-01-30T10:00:00Z' },
description: 'Create a meeting',
});
expect(action.status).toBe('pending');

Expand Down Expand Up @@ -131,9 +133,9 @@ describe('Database Integration', () => {
await userRepo.upsert({ id: 'user-1', email: 'u@test.com', display_name: 'U' });
const conv = await conversationRepo.create('user-1', 'Action Test Conv');

const a1 = await pendingActionRepo.create({ conversation_id: conv.id, action_type: 'create_event', action_payload: { summary: 'Event 1' } });
const a2 = await pendingActionRepo.create({ conversation_id: conv.id, action_type: 'delete_event', action_payload: { eventId: 'e1' } });
const a3 = await pendingActionRepo.create({ conversation_id: conv.id, action_type: 'update_event', action_payload: { eventId: 'e2' } });
const a1 = await pendingActionRepo.create({ user_id: 'user-1', conversation_id: conv.id, action_type: 'create_event', action_payload: { summary: 'Event 1' }, description: 'Create event 1' });
const a2 = await pendingActionRepo.create({ user_id: 'user-1', conversation_id: conv.id, action_type: 'delete_event', action_payload: { eventId: 'e1' }, description: 'Delete event' });
const a3 = await pendingActionRepo.create({ user_id: 'user-1', conversation_id: conv.id, action_type: 'update_event', action_payload: { eventId: 'e2' }, description: 'Update event' });

// Approve first, reject second, leave third pending
await pendingActionRepo.updateStatus(a1.id, 'approved');
Expand Down
10 changes: 6 additions & 4 deletions backend/src/__tests__/database.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,11 @@ describe('Database Layer', () => {

it('should create and find by id', async () => {
const action = await pendingActionRepo.create({
user_id: 'user-1',
conversation_id: conversationId,
action_type: 'create_event',
action_payload: { summary: 'Meeting', startDateTime: '2025-01-01T10:00:00Z' },
description: 'Create a meeting',
});
expect(action.status).toBe('pending');
expect(action.action_type).toBe('create_event');
Expand All @@ -171,22 +173,22 @@ describe('Database Layer', () => {
});

it('should find pending actions by conversation', async () => {
await pendingActionRepo.create({ conversation_id: conversationId, action_type: 'create_event', action_payload: {} });
await pendingActionRepo.create({ conversation_id: conversationId, action_type: 'delete_event', action_payload: {} });
await pendingActionRepo.create({ user_id: 'user-1', conversation_id: conversationId, action_type: 'create_event', action_payload: {}, description: 'Create event' });
await pendingActionRepo.create({ user_id: 'user-1', conversation_id: conversationId, action_type: 'delete_event', action_payload: {}, description: 'Delete event' });

const pending = await pendingActionRepo.findPendingByConversationId(conversationId);
expect(pending).toHaveLength(2);
});

it('should update status to approved', async () => {
const action = await pendingActionRepo.create({ conversation_id: conversationId, action_type: 'create_event', action_payload: {} });
const action = await pendingActionRepo.create({ user_id: 'user-1', conversation_id: conversationId, action_type: 'create_event', action_payload: {}, description: 'Create event' });
const updated = await pendingActionRepo.updateStatus(action.id, 'approved');
expect(updated!.status).toBe('approved');
expect(updated!.resolved_at).toBeDefined();
});

it('should update status to rejected', async () => {
const action = await pendingActionRepo.create({ conversation_id: conversationId, action_type: 'create_event', action_payload: {} });
const action = await pendingActionRepo.create({ user_id: 'user-1', conversation_id: conversationId, action_type: 'create_event', action_payload: {}, description: 'Create event' });
await pendingActionRepo.updateStatus(action.id, 'rejected');

// Rejected actions should not appear in pending query
Expand Down
4 changes: 2 additions & 2 deletions backend/src/__tests__/date-format.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ describe('Date Format Integration', () => {
await new Promise<void>((resolve) => server.close(() => resolve()));
}, 15000);

afterEach(() => {
afterEach(async () => {
conversationService._clear();
actionService._clear();
await actionService._clear();
});

function connectWs(): Promise<WebSocket> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('Pending actions persist across refresh', () => {

afterEach(async () => {
await conversationService._clear();
actionService._clear();
await actionService._clear();
});

function connectWs(): Promise<WebSocket> {
Expand Down Expand Up @@ -95,7 +95,7 @@ describe('Pending actions persist across refresh', () => {

// The LLM may or may not return a pendingAction depending on its response.
// Regardless, let's also manually create one to ensure deterministic testing.
const manualAction = actionService.createAction(
const manualAction = await actionService.createAction(
'refresh-test-user',
conversationId,
'create_event',
Expand Down Expand Up @@ -136,7 +136,7 @@ describe('Pending actions persist across refresh', () => {
const conversationId = chatRes.data.conversationId;

// Create a pending action
const action = actionService.createAction(
const action = await actionService.createAction(
'refresh-test-user',
conversationId,
'create_event',
Expand Down Expand Up @@ -188,12 +188,12 @@ describe('Pending actions persist across refresh', () => {
const convId2 = chat2.data.conversationId;
ws.close();

actionService.createAction(
await actionService.createAction(
'refresh-test-user', convId1, 'create_event',
{ calendarId: 'primary', summary: 'Conv1 Event', startDateTime: new Date().toISOString(), endDateTime: new Date().toISOString() },
'Conv1 action',
);
actionService.createAction(
await actionService.createAction(
'refresh-test-user', convId2, 'create_event',
{ calendarId: 'primary', summary: 'Conv2 Event', startDateTime: new Date().toISOString(), endDateTime: new Date().toISOString() },
'Conv2 action',
Expand Down
4 changes: 2 additions & 2 deletions backend/src/controllers/chat.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export const getPendingActions = async (req: AuthenticatedRequest, res: Response
return;
}

let actions = actionService.getPendingActions(req.user.id);
let actions = await actionService.getPendingActions(req.user.id);

// Support optional conversationId filter
const conversationId = req.query.conversationId;
Expand Down Expand Up @@ -157,7 +157,7 @@ export const rejectAction = async (req: AuthenticatedRequest, res: Response): Pr
}

const actionId = param(req, 'id');
const result = actionService.rejectAction(actionId, req.user.id);
const result = await actionService.rejectAction(actionId, req.user.id);
const rejectionMessage = formatActionMessage(result, false);
try {
await conversationService.addMessage(result.conversationId, 'assistant', rejectionMessage);
Expand Down
1 change: 1 addition & 0 deletions backend/src/database/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ async function initializeIndexes(database: Db): Promise<void> {
await database.collection('conversations').createIndex({ user_id: 1 });
await database.collection('messages').createIndex({ conversation_id: 1 });
await database.collection('pending_actions').createIndex({ conversation_id: 1, status: 1 });
await database.collection('pending_actions').createIndex({ user_id: 1, status: 1 });
}
Loading