Skip to content

Commit 19cc798

Browse files
Fix backend unit tests failing in CI.
Set DB_NAME in Jest setup and align ChatService specs with filter versioning and current API paths. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 08f3143 commit 19cc798

3 files changed

Lines changed: 99 additions & 26 deletions

File tree

apps/backend/jest.setup.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ jest.setTimeout(30000);
2727
process.env.NODE_ENV = 'test';
2828
process.env.JWT_SECRET = 'test-secret-key';
2929
process.env.MONGODB_URI = 'mongodb://localhost:27017/test';
30+
process.env.DB_NAME = 'test';
3031

3132
// Mock fetch for Node.js tests
3233
global.fetch = jest.fn();

apps/backend/src/app/app.controller.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ describe('AppController', () => {
8989
expect(typeof result.uptime).toBe('number');
9090
expect(result.endpoints).toBeDefined();
9191
expect(result.endpoints.health).toBe('/api');
92-
expect(result.endpoints.docs).toBe('/api/docs');
92+
expect(result.endpoints.docs).toBe('/docs');
9393
});
9494
});
9595

apps/backend/src/app/services/chat.service.spec.ts

Lines changed: 97 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ describe('ChatService', () => {
3333
deleteMany: jest.fn().mockReturnValue(createMockQuery({ deletedCount: 0 })),
3434
countDocuments: jest.fn().mockReturnValue(createMockQuery(0)),
3535
updateMany: jest.fn().mockReturnValue(createMockQuery({ modifiedCount: 0 })),
36+
db: { readyState: 1 },
3637
};
3738

3839
const MockMessageModel = jest.fn().mockImplementation((data) => {
@@ -102,6 +103,7 @@ describe('ChatService', () => {
102103
userId: 'test-user-id',
103104
chatId: 'test-chat-id',
104105
filterConfig: { dateFilter: { type: 'custom' } },
106+
version: 1,
105107
isActive: false,
106108
createdAt: new Date(),
107109
updatedAt: new Date(),
@@ -297,9 +299,19 @@ describe('ChatService', () => {
297299
content: 'Test message',
298300
};
299301

302+
const savedMessage = {
303+
...mockMessage,
304+
filterId: null,
305+
filterVersion: null,
306+
timestamp: expect.any(Date),
307+
};
308+
300309
mockChatModel.findOneAndUpdate.mockReturnValue(createMockQuery(mockChat));
301310
mockMessageModel.findOne.mockReturnValue(createMockQuery(null));
302-
mockChatModel.findOneAndUpdate.mockReturnValue(createMockQuery(mockChat));
311+
MockMessageModel.mockReturnValueOnce({
312+
...savedMessage,
313+
save: jest.fn().mockResolvedValue(savedMessage),
314+
});
303315

304316
const result = await service.addMessage(messageDto);
305317

@@ -308,7 +320,12 @@ describe('ChatService', () => {
308320
chatId: messageDto.chatId,
309321
userId: messageDto.userId,
310322
});
311-
expect(result).toEqual(mockMessage);
323+
expect(result).toEqual(expect.objectContaining({
324+
id: messageDto.id,
325+
content: messageDto.content,
326+
filterId: null,
327+
filterVersion: null,
328+
}));
312329
});
313330

314331
it('should skip duplicate messages', async () => {
@@ -362,15 +379,26 @@ describe('ChatService', () => {
362379
};
363380

364381
const chatWithFilter = { ...mockChat, activeFilterId: 'active-filter-id' };
382+
const activeFilter = {
383+
...mockFilter,
384+
filterId: 'active-filter-id',
385+
isActive: true,
386+
};
387+
365388
mockChatModel.findOneAndUpdate.mockReturnValue(createMockQuery(chatWithFilter));
366389
mockMessageModel.findOne.mockReturnValue(createMockQuery(null));
367-
mockFilterModel.findOne.mockReturnValue(createMockQuery(mockFilter));
390+
mockFilterModel.findOne.mockReturnValue(createMockQuery(activeFilter));
391+
MockMessageModel.mockReturnValueOnce({
392+
...mockMessage,
393+
save: jest.fn().mockResolvedValue(mockMessage),
394+
});
368395

369396
await service.addMessage(messageDto);
370397

371398
expect(mockFilterModel.findOne).toHaveBeenCalledWith({
372399
filterId: 'active-filter-id',
373400
userId: 'test-user-id',
401+
isActive: true,
374402
});
375403
});
376404
});
@@ -433,74 +461,112 @@ describe('ChatService', () => {
433461
filterConfig: { dateFilter: { type: 'custom' } },
434462
};
435463

464+
const savedFilter = { ...mockFilter, version: 1 };
465+
466+
mockFilterModel.findOne.mockReturnValue(createMockQuery(null));
436467
mockChatModel.findOneAndUpdate.mockReturnValue(createMockQuery(mockChat));
468+
MockFilterModel.mockReturnValueOnce({
469+
...savedFilter,
470+
save: jest.fn().mockResolvedValue(savedFilter),
471+
});
437472

438473
const result = await service.createFilter(filterDto);
439474

440-
expect(MockFilterModel).toHaveBeenCalledWith(filterDto);
475+
expect(mockFilterModel.findOne).toHaveBeenCalledWith({
476+
filterId: filterDto.filterId,
477+
userId: filterDto.userId,
478+
});
479+
expect(MockFilterModel).toHaveBeenCalledWith(
480+
expect.objectContaining({ ...filterDto, version: 1 })
481+
);
441482
expect(mockChatModel.findOneAndUpdate).toHaveBeenCalledWith(
442483
{ chatId: filterDto.chatId, userId: filterDto.userId },
443484
{ $addToSet: { associatedFilters: filterDto.filterId } }
444485
);
445-
expect(result).toEqual(mockFilter);
486+
expect(result).toEqual(savedFilter);
446487
});
447488
});
448489

449490
describe('getFiltersForChat', () => {
450491
it('should return all filters for a chat', async () => {
451-
const filters = [mockFilter, { ...mockFilter, filterId: 'filter-2' }];
452-
mockFilterModel.find.mockReturnValue(createMockQuery(filters));
492+
const chatFilters = [mockFilter, { ...mockFilter, filterId: 'filter-2' }];
493+
const globalFilters = [{ ...mockFilter, filterId: 'global-filter', chatId: null }];
494+
mockFilterModel.find
495+
.mockReturnValueOnce(createMockQuery(chatFilters))
496+
.mockReturnValueOnce(createMockQuery(globalFilters));
453497

454498
const result = await service.getFiltersForChat('test-chat-id', 'test-user-id');
455499

456-
expect(mockFilterModel.find).toHaveBeenCalledWith({ chatId: 'test-chat-id', userId: 'test-user-id' });
457-
expect(result).toEqual(filters);
500+
expect(mockFilterModel.find).toHaveBeenNthCalledWith(1, { userId: 'test-user-id', chatId: 'test-chat-id' });
501+
expect(mockFilterModel.find).toHaveBeenNthCalledWith(2, { userId: 'test-user-id', chatId: null });
502+
expect(result).toEqual([...chatFilters, ...globalFilters]);
458503
});
459504
});
460505

461506
describe('updateFilter', () => {
462507
it('should update a filter', async () => {
463-
const updatedFilter = { ...mockFilter, name: 'Updated Filter' };
508+
const latestFilter = { ...mockFilter, version: 1 };
509+
const updatedFilter = { ...mockFilter, name: 'Updated Filter', version: 2 };
464510
const updateData = { name: 'Updated Filter' };
465511

466-
mockFilterModel.findOneAndUpdate.mockReturnValue(createMockQuery(updatedFilter));
512+
mockFilterModel.findOne.mockReturnValue(createMockQuery(latestFilter));
513+
mockFilterModel.updateMany.mockReturnValue(createMockQuery({ modifiedCount: 1 }));
514+
MockFilterModel.mockReturnValueOnce({
515+
...updatedFilter,
516+
save: jest.fn().mockResolvedValue(updatedFilter),
517+
});
467518

468519
const result = await service.updateFilter('test-filter-id', 'test-user-id', updateData);
469520

470-
expect(mockFilterModel.findOneAndUpdate).toHaveBeenCalledWith(
521+
expect(mockFilterModel.findOne).toHaveBeenCalledWith({
522+
filterId: 'test-filter-id',
523+
userId: 'test-user-id',
524+
});
525+
expect(mockFilterModel.updateMany).toHaveBeenCalledWith(
471526
{ filterId: 'test-filter-id', userId: 'test-user-id' },
472-
{ ...updateData, updatedAt: expect.any(Date) },
473-
{ new: true }
527+
{ isActive: false }
528+
);
529+
expect(MockFilterModel).toHaveBeenCalledWith(
530+
expect.objectContaining({
531+
filterId: 'test-filter-id',
532+
version: 2,
533+
name: 'Updated Filter',
534+
})
474535
);
475536
expect(result).toEqual(updatedFilter);
476537
});
477538

478539
it('should throw NotFoundException if filter does not exist', async () => {
479-
mockFilterModel.findOneAndUpdate.mockReturnValue(createMockQuery(null));
540+
mockFilterModel.findOne.mockReturnValue(createMockQuery(null));
480541

481542
await expect(service.updateFilter('non-existent-id', 'test-user-id', { name: 'New Name' })).rejects.toThrow(NotFoundException);
482543
});
483544
});
484545

485546
describe('setActiveFilter', () => {
486547
it('should set a filter as active', async () => {
487-
const activeFilter = { ...mockFilter, isActive: true };
548+
const filterWithVersion = { ...mockFilter, version: 1 };
488549
const updatedChat = { ...mockChat, activeFilterId: 'test-filter-id', currentFilterConfig: mockFilter.filterConfig };
489550

490551
mockFilterModel.updateMany.mockReturnValue(createMockQuery({ modifiedCount: 1 }));
491-
mockFilterModel.findOneAndUpdate.mockReturnValue(createMockQuery(activeFilter));
552+
mockFilterModel.findOne.mockReturnValue(createMockQuery(filterWithVersion));
553+
mockFilterModel.findOneAndUpdate.mockReturnValue(createMockQuery({ ...filterWithVersion, isActive: true }));
492554
mockChatModel.findOneAndUpdate.mockReturnValue(createMockQuery(updatedChat));
493555

494556
const result = await service.setActiveFilter('test-chat-id', 'test-user-id', 'test-filter-id');
495557

496558
expect(mockFilterModel.updateMany).toHaveBeenCalledWith(
497-
{ chatId: 'test-chat-id', userId: 'test-user-id' },
559+
{ userId: 'test-user-id', chatId: 'test-chat-id' },
498560
{ isActive: false }
499561
);
562+
expect(mockFilterModel.findOne).toHaveBeenCalledWith({
563+
filterId: 'test-filter-id',
564+
userId: 'test-user-id',
565+
$or: [{ chatId: 'test-chat-id' }, { chatId: null }],
566+
});
500567
expect(mockFilterModel.findOneAndUpdate).toHaveBeenCalledWith(
501-
{ filterId: 'test-filter-id', userId: 'test-user-id', chatId: 'test-chat-id' },
502-
{ isActive: true },
503-
{ new: true }
568+
{ filterId: 'test-filter-id', userId: 'test-user-id', version: 1 },
569+
{ isActive: true }
504570
);
505571
expect(mockChatModel.findOneAndUpdate).toHaveBeenCalledWith(
506572
{ chatId: 'test-chat-id', userId: 'test-user-id' },
@@ -532,13 +598,14 @@ describe('ChatService', () => {
532598

533599
it('should throw NotFoundException if filter does not exist', async () => {
534600
mockFilterModel.updateMany.mockReturnValue(createMockQuery({ modifiedCount: 1 }));
535-
mockFilterModel.findOneAndUpdate.mockReturnValue(createMockQuery(null));
601+
mockFilterModel.findOne.mockReturnValue(createMockQuery(null));
536602

537603
await expect(service.setActiveFilter('test-chat-id', 'test-user-id', 'non-existent-id')).rejects.toThrow(NotFoundException);
538604
});
539605

540606
it('should throw NotFoundException if chat does not exist', async () => {
541607
mockFilterModel.updateMany.mockReturnValue(createMockQuery({ modifiedCount: 1 }));
608+
mockFilterModel.findOne.mockReturnValue(createMockQuery(mockFilter));
542609
mockFilterModel.findOneAndUpdate.mockReturnValue(createMockQuery(mockFilter));
543610
mockChatModel.findOneAndUpdate.mockReturnValue(createMockQuery(null));
544611

@@ -548,12 +615,17 @@ describe('ChatService', () => {
548615

549616
describe('deleteFilter', () => {
550617
it('should delete a filter', async () => {
551-
mockFilterModel.findOneAndDelete.mockReturnValue(createMockQuery(mockFilter));
618+
mockFilterModel.find.mockReturnValue(createMockQuery([mockFilter]));
619+
mockFilterModel.deleteMany.mockReturnValue(createMockQuery({ deletedCount: 1 }));
552620
mockChatModel.updateMany.mockReturnValue(createMockQuery({ modifiedCount: 1 }));
553621

554622
await service.deleteFilter('test-filter-id', 'test-user-id');
555623

556-
expect(mockFilterModel.findOneAndDelete).toHaveBeenCalledWith({
624+
expect(mockFilterModel.find).toHaveBeenCalledWith({
625+
filterId: 'test-filter-id',
626+
userId: 'test-user-id',
627+
});
628+
expect(mockFilterModel.deleteMany).toHaveBeenCalledWith({
557629
filterId: 'test-filter-id',
558630
userId: 'test-user-id',
559631
});
@@ -568,7 +640,7 @@ describe('ChatService', () => {
568640
});
569641

570642
it('should throw NotFoundException if filter does not exist', async () => {
571-
mockFilterModel.findOneAndDelete.mockReturnValue(createMockQuery(null));
643+
mockFilterModel.find.mockReturnValue(createMockQuery([]));
572644

573645
await expect(service.deleteFilter('non-existent-id', 'test-user-id')).rejects.toThrow(NotFoundException);
574646
});

0 commit comments

Comments
 (0)