import { NotFoundException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; import { JwtService } from '@nestjs/jwt'; import { getRepositoryToken } from '@nestjs/typeorm'; import { ConfigService } from '@nestjs/config'; import { AuthService } from './auth.service'; import { UserService } from '../user/user.service'; import { AppConfigService } from 'src/modules/config/config.service'; import { MailService } from 'src/modules/mail/mail.service'; import { NumeroDossierService } from 'src/modules/numero-dossier/numero-dossier.service'; import { Parents } from 'src/entities/parents.entity'; import { Users } from 'src/entities/users.entity'; import { Children } from 'src/entities/children.entity'; import { AssistanteMaternelle } from 'src/entities/assistantes_maternelles.entity'; describe('AuthService (#118 create-password API)', () => { let service: AuthService; const usersRepoMock = { findOne: jest.fn(), createQueryBuilder: jest.fn(), update: jest.fn(), }; const mailServiceMock = { sendPasswordResetEmail: jest.fn().mockResolvedValue(undefined), }; const appConfigMock = { get: jest.fn().mockReturnValue(7), }; beforeEach(async () => { jest.clearAllMocks(); const qbChain: any = {}; qbChain.where = jest.fn().mockReturnValue(qbChain); qbChain.select = jest.fn().mockReturnValue(qbChain); qbChain.getOne = jest.fn().mockResolvedValue(null); qbChain.update = jest.fn().mockReturnValue(qbChain); qbChain.set = jest.fn().mockReturnValue(qbChain); qbChain.andWhere = jest.fn().mockReturnValue(qbChain); qbChain.execute = jest.fn().mockResolvedValue({ affected: 0 }); usersRepoMock.createQueryBuilder.mockReturnValue(qbChain); usersRepoMock.update.mockResolvedValue({ affected: 1, raw: [] }); const module: TestingModule = await Test.createTestingModule({ providers: [ AuthService, { provide: UserService, useValue: {} }, { provide: JwtService, useValue: {} }, { provide: ConfigService, useValue: { get: jest.fn() } }, { provide: AppConfigService, useValue: appConfigMock }, { provide: MailService, useValue: mailServiceMock }, { provide: NumeroDossierService, useValue: {} }, { provide: getRepositoryToken(Parents), useValue: {} }, { provide: getRepositoryToken(Users), useValue: usersRepoMock }, { provide: getRepositoryToken(Children), useValue: {} }, { provide: getRepositoryToken(AssistanteMaternelle), useValue: {} }, ], }).compile(); service = module.get(AuthService); }); it('should be defined', () => { expect(service).toBeDefined(); }); it('returns 404-like error when verify token is missing', async () => { await expect(service.verifyCreatePasswordToken('')).rejects.toThrow(NotFoundException); }); it('returns valid=true when token exists and is not expired', async () => { usersRepoMock.findOne.mockResolvedValue({ id: 'u1', password: null, token_creation_mdp_expire_le: new Date(Date.now() + 60_000), }); await expect(service.verifyCreatePasswordToken('tok-123')).resolves.toEqual({ valid: true, message: 'Token valide', }); }); describe('#127 forgot / reset password', () => { it('requestPasswordReset returns generic message when email unknown', async () => { const r = await service.requestPasswordReset('unknown@test.fr'); expect(r.message).toContain('Si cette adresse'); expect(mailServiceMock.sendPasswordResetEmail).not.toHaveBeenCalled(); }); it('requestPasswordReset sends mail when user has password', async () => { usersRepoMock.createQueryBuilder.mockReturnValueOnce({ where: jest.fn().mockReturnThis(), select: jest.fn().mockReturnThis(), getOne: jest.fn().mockResolvedValue({ id: 'u1', email: 'a@test.fr', prenom: 'A', nom: 'B', password: 'hashed', }), }); const r = await service.requestPasswordReset('a@test.fr'); expect(r.message).toContain('Si cette adresse'); expect(usersRepoMock.update).toHaveBeenCalled(); expect(mailServiceMock.sendPasswordResetEmail).toHaveBeenCalledWith( expect.objectContaining({ email: 'a@test.fr', token: expect.any(String) }), ); }); it('resetPasswordWithResetToken throws when token unknown', async () => { usersRepoMock.findOne.mockResolvedValue(null); await expect(service.resetPasswordWithResetToken('bad', 'Password1')).rejects.toThrow( NotFoundException, ); }); it('resetPasswordWithResetToken succeeds when update affects row', async () => { usersRepoMock.findOne.mockResolvedValue({ id: 'u1', password: 'oldhash', password_reset_expires: new Date(Date.now() + 60_000), }); const exec = jest.fn().mockResolvedValue({ affected: 1 }); const chain: any = {}; chain.update = jest.fn().mockReturnValue(chain); chain.set = jest.fn().mockReturnValue(chain); chain.where = jest.fn().mockReturnValue(chain); chain.andWhere = jest.fn().mockReturnValue(chain); chain.execute = exec; usersRepoMock.createQueryBuilder.mockReturnValueOnce(chain); const r = await service.resetPasswordWithResetToken('good-token', 'Password1'); expect(r.message.toLowerCase()).toContain('mis à jour'); expect(exec).toHaveBeenCalled(); }); }); });