import { Test, TestingModule } from '@nestjs/testing'; import { ConfigService } from '@nestjs/config'; import { AccountsService } from './accounts.service'; import { PrismaService } from '../../prisma/prisma.service'; import * as QRCode from 'qrcode'; jest.mock('qrcode', () => ({ toDataURL: jest.fn().mockResolvedValue('data:image/png;base64,fakedata'), })); const mockAccounts = [ { id: 'acc_1', platform: 'whatsapp', jid: '111@s.whatsapp.net', displayName: 'Test Account', status: 'ACTIVE' }, ]; const mockCreatedAccount = { id: 'acc_new', platform: 'whatsapp', jid: 'pending_uuid@placeholder', displayName: 'My Number', status: 'ACTIVE', }; const mockPrisma = { account: { findMany: jest.fn().mockResolvedValue(mockAccounts), findUnique: jest.fn(), create: jest.fn().mockResolvedValue(mockCreatedAccount), }, }; const mockConfig = { get: jest.fn().mockImplementation((key: string, def: string) => key === 'WHATSAPP_SESSION_PATH' ? './sessions' : def, ), }; describe('AccountsService', () => { let service: AccountsService; beforeEach(async () => { jest.clearAllMocks(); const module: TestingModule = await Test.createTestingModule({ providers: [ AccountsService, { provide: PrismaService, useValue: mockPrisma }, { provide: ConfigService, useValue: mockConfig }, ], }).compile(); service = module.get(AccountsService); }); describe('list()', () => { it('returns accounts from Prisma without qrCode field', async () => { const result = await service.list(); expect(result).toEqual(mockAccounts); expect(mockPrisma.account.findMany).toHaveBeenCalledWith( expect.objectContaining({ select: expect.not.objectContaining({ qrCode: true }) }), ); }); }); describe('getQr()', () => { it('returns null qrDataUrl when account has no qrCode', async () => { mockPrisma.account.findUnique.mockResolvedValue({ status: 'ACTIVE', qrCode: null }); const result = await service.getQr('acc_1'); expect(result).toEqual({ status: 'ACTIVE', qrDataUrl: null }); expect(QRCode.toDataURL).not.toHaveBeenCalled(); }); it('converts qrCode string to data URL when qrCode is present', async () => { mockPrisma.account.findUnique.mockResolvedValue({ status: 'DISCONNECTED', qrCode: 'raw-qr-string' }); const result = await service.getQr('acc_1'); expect(QRCode.toDataURL).toHaveBeenCalledWith('raw-qr-string'); expect(result).toEqual({ status: 'DISCONNECTED', qrDataUrl: 'data:image/png;base64,fakedata' }); }); it('returns not_found status when account does not exist', async () => { mockPrisma.account.findUnique.mockResolvedValue(null); const result = await service.getQr('nonexistent'); expect(result).toEqual({ status: 'not_found', qrDataUrl: null }); }); }); describe('create()', () => { it('creates account with platform whatsapp and status ACTIVE', async () => { await service.create('My Number'); expect(mockPrisma.account.create).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ platform: 'whatsapp', status: 'ACTIVE', displayName: 'My Number', }), }), ); }); it('generates a unique sessionPath under WHATSAPP_SESSION_PATH', async () => { await service.create(); const call = mockPrisma.account.create.mock.calls[0][0]; expect(call.data.sessionPath).toMatch(/^\.\/sessions\/.+/); }); it('generates a placeholder jid prefixed with pending_', async () => { await service.create(); const call = mockPrisma.account.create.mock.calls[0][0]; expect(call.data.jid).toMatch(/^pending_/); }); it('sets displayName to null when not provided', async () => { await service.create(); const call = mockPrisma.account.create.mock.calls[0][0]; expect(call.data.displayName).toBeNull(); }); it('returns the created account summary', async () => { const result = await service.create('My Number'); expect(result).toEqual(mockCreatedAccount); }); }); });