import { FollowsService } from './follows.service'; describe('FollowsService', () => { it('keeps follow successful even if notification creation fails and resyncs counters', async () => { const currentUserId = '507f1f77bcf86cd799439011'; const targetUserId = '507f191e810c19729de860ea'; const followsRepository = { findOne: jest.fn().mockResolvedValue(null), create: jest.fn().mockResolvedValue({ id: 'follow-1' }), count: jest .fn() .mockResolvedValueOnce(6) .mockResolvedValueOnce(14), }; const usersRepository = { findById: jest.fn().mockResolvedValue({ id: targetUserId }), setFollowingCount: jest.fn().mockResolvedValue(undefined), setFollowersCount: jest.fn().mockResolvedValue(undefined), }; const outboxService = { enqueueFollowNotification: jest.fn().mockRejectedValue(new Error('socket down')), }; const blocksRepository = { findAnyBetween: jest.fn().mockResolvedValue(null), }; const service = new FollowsService( followsRepository as any, usersRepository as any, outboxService as any, { bumpGlobalVersion: jest.fn().mockResolvedValue(1) } as any, blocksRepository as any, ); await expect(service.toggleFollow(currentUserId, { targetUserId })).resolves.toEqual({ following: true, }); expect(usersRepository.setFollowingCount).toHaveBeenCalledWith(currentUserId, 6); expect(usersRepository.setFollowersCount).toHaveBeenCalledWith(targetUserId, 14); expect(outboxService.enqueueFollowNotification).toHaveBeenCalledWith( currentUserId, targetUserId, 'follow-1', ); }); it('prevents users from following themselves', async () => { const userId = '507f1f77bcf86cd799439011'; const service = new FollowsService( {} as any, {} as any, {} as any, { bumpGlobalVersion: jest.fn() } as any, { findAnyBetween: jest.fn() } as any, ); await expect(service.followUser(userId, userId)).rejects.toThrow('You cannot follow yourself'); }); it('returns already-following response without creating duplicate notification', async () => { const currentUserId = '507f1f77bcf86cd799439011'; const targetUserId = '507f191e810c19729de860ea'; const followsRepository = { findOne: jest.fn().mockResolvedValue({ id: 'existing-follow' }), count: jest.fn().mockResolvedValueOnce(1).mockResolvedValueOnce(2), create: jest.fn(), }; const usersRepository = { findById: jest.fn().mockResolvedValue({ id: targetUserId, isDisabled: false, isPrivate: false }), setFollowingCount: jest.fn(), setFollowersCount: jest.fn(), }; const outboxService = { enqueueFollowNotification: jest.fn(), }; const service = new FollowsService( followsRepository as any, usersRepository as any, outboxService as any, { bumpGlobalVersion: jest.fn() } as any, { findAnyBetween: jest.fn().mockResolvedValue(null) } as any, ); await expect(service.followUser(currentUserId, targetUserId)).resolves.toMatchObject({ message: 'Already following user', isFollowing: true, followersCount: 2, followingCount: 1, }); expect(followsRepository.create).not.toHaveBeenCalled(); expect(outboxService.enqueueFollowNotification).not.toHaveBeenCalled(); }); });