From 6dece752ef5b5367547e778dc576eeb45b75d55b Mon Sep 17 00:00:00 2001 From: angjustinl <96008766+ANGJustinl@users.noreply.github.com> Date: Thu, 18 Dec 2025 13:29:55 +0800 Subject: [PATCH] =?UTF-8?q?test(email,=20verification,=20login):=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=B5=8B=E8=AF=95=E4=B8=AD=E7=9A=84=E6=96=AD?= =?UTF-8?q?=E8=A8=80=E5=86=85=E5=AE=B9,=20=E4=BF=AE=E5=A4=8D=E6=B5=8B?= =?UTF-8?q?=E8=AF=95error.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace boolean assertions with structured result object checks in email service tests - Update email service tests to verify success flag and isTestMode property - Add error message assertions for failed email sending scenarios - Change logger spy from 'log' to 'warn' for test mode email output - Update test message to clarify emails are not actually sent in test mode - Add code and createdAt properties to verification code stats mock data - Fix TTL mock value from -1 to -2 to correctly represent non-existent keys - Replace Inject decorator with direct UsersService type injection in LoginCoreService - Ensure verification service tests properly mock TTL values during code verification - Improve test coverage by validating complete response structures instead of simple booleans --- src/core/login_core/login_core.service.ts | 3 +- src/core/utils/email/email.service.spec.ts | 34 ++++++++++++------- .../verification/verification.service.spec.ts | 10 ++++-- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/core/login_core/login_core.service.ts b/src/core/login_core/login_core.service.ts index 7781599..97ad369 100644 --- a/src/core/login_core/login_core.service.ts +++ b/src/core/login_core/login_core.service.ts @@ -18,6 +18,7 @@ import { Injectable, UnauthorizedException, ConflictException, NotFoundException, BadRequestException, Inject } from '@nestjs/common'; import { Users } from '../db/users/users.entity'; +import { UsersService } from '../db/users/users.service'; import { EmailService, EmailSendResult } from '../utils/email/email.service'; import { VerificationService, VerificationCodeType } from '../utils/verification/verification.service'; import * as bcrypt from 'bcrypt'; @@ -102,7 +103,7 @@ export interface VerificationCodeResult { @Injectable() export class LoginCoreService { constructor( - @Inject('UsersService') private readonly usersService: any, + private readonly usersService: UsersService, private readonly emailService: EmailService, private readonly verificationService: VerificationService, ) {} diff --git a/src/core/utils/email/email.service.spec.ts b/src/core/utils/email/email.service.spec.ts index b16eb96..736e852 100644 --- a/src/core/utils/email/email.service.spec.ts +++ b/src/core/utils/email/email.service.spec.ts @@ -117,7 +117,8 @@ describe('EmailService', () => { const result = await service.sendEmail(emailOptions); - expect(result).toBe(true); + expect(result.success).toBe(true); + expect(result.isTestMode).toBe(false); expect(mockTransporter.sendMail).toHaveBeenCalledWith({ from: '"Test Sender" ', to: 'test@example.com', @@ -138,7 +139,8 @@ describe('EmailService', () => { const result = await service.sendEmail(emailOptions); - expect(result).toBe(false); + expect(result.success).toBe(false); + expect(result.error).toBe('发送失败'); }); it('应该在测试模式下输出邮件内容', async () => { @@ -157,13 +159,14 @@ describe('EmailService', () => { }; // Mock the service to use test transporter - const loggerSpy = jest.spyOn(service['logger'], 'log').mockImplementation(); + const loggerSpy = jest.spyOn(service['logger'], 'warn').mockImplementation(); service['transporter'] = testTransporter; const result = await service.sendEmail(emailOptions); - expect(result).toBe(true); - expect(loggerSpy).toHaveBeenCalledWith('=== 邮件发送(测试模式) ==='); + expect(result.success).toBe(true); + expect(result.isTestMode).toBe(true); + expect(loggerSpy).toHaveBeenCalledWith('=== 邮件发送(测试模式 - 邮件未真实发送) ==='); loggerSpy.mockRestore(); }); @@ -183,7 +186,8 @@ describe('EmailService', () => { const result = await service.sendVerificationCode(options); - expect(result).toBe(true); + expect(result.success).toBe(true); + expect(result.isTestMode).toBe(false); expect(mockTransporter.sendMail).toHaveBeenCalledWith( expect.objectContaining({ to: 'test@example.com', @@ -206,7 +210,8 @@ describe('EmailService', () => { const result = await service.sendVerificationCode(options); - expect(result).toBe(true); + expect(result.success).toBe(true); + expect(result.isTestMode).toBe(false); expect(mockTransporter.sendMail).toHaveBeenCalledWith( expect.objectContaining({ to: 'test@example.com', @@ -227,7 +232,8 @@ describe('EmailService', () => { const result = await service.sendVerificationCode(options); - expect(result).toBe(false); + expect(result.success).toBe(false); + expect(result.error).toBe('发送失败'); }); }); @@ -238,7 +244,8 @@ describe('EmailService', () => { const result = await service.sendWelcomeEmail('test@example.com', '测试用户'); - expect(result).toBe(true); + expect(result.success).toBe(true); + expect(result.isTestMode).toBe(false); expect(mockTransporter.sendMail).toHaveBeenCalledWith( expect.objectContaining({ to: 'test@example.com', @@ -253,7 +260,8 @@ describe('EmailService', () => { const result = await service.sendWelcomeEmail('test@example.com', '测试用户'); - expect(result).toBe(false); + expect(result.success).toBe(false); + expect(result.error).toBe('发送失败'); }); }); @@ -358,7 +366,8 @@ describe('EmailService', () => { const result = await service.sendEmail(emailOptions); - expect(result).toBe(false); + expect(result.success).toBe(false); + expect(result.error).toBe('ECONNREFUSED'); }); it('应该正确处理认证错误', async () => { @@ -372,7 +381,8 @@ describe('EmailService', () => { const result = await service.sendEmail(emailOptions); - expect(result).toBe(false); + expect(result.success).toBe(false); + expect(result.error).toBe('Invalid login'); }); it('应该正确处理连接验证错误', async () => { diff --git a/src/core/utils/verification/verification.service.spec.ts b/src/core/utils/verification/verification.service.spec.ts index 298f21a..609652a 100644 --- a/src/core/utils/verification/verification.service.spec.ts +++ b/src/core/utils/verification/verification.service.spec.ts @@ -272,6 +272,7 @@ describe('VerificationService', () => { }; mockRedis.get.mockResolvedValue(JSON.stringify(codeInfo)); + mockRedis.ttl.mockResolvedValue(240); // Mock TTL 返回 240 秒 await expect(service.verifyCode(email, type, '654321')).rejects.toThrow( new BadRequestException('验证码错误,剩余尝试次数: 1') @@ -285,7 +286,7 @@ describe('VerificationService', () => { expect(mockRedis.set).toHaveBeenCalledWith( `verification_code:${type}:${email}`, JSON.stringify(updatedCodeInfo), - 300 + 240 ); }); @@ -298,6 +299,7 @@ describe('VerificationService', () => { }; mockRedis.get.mockResolvedValue(JSON.stringify(codeInfo)); + mockRedis.ttl.mockResolvedValue(240); // Mock TTL 返回 240 秒 await expect(service.verifyCode(email, type, '654321')).rejects.toThrow( new BadRequestException('验证码错误,剩余尝试次数: 0') @@ -391,18 +393,20 @@ describe('VerificationService', () => { ttl: 240, attempts: 1, maxAttempts: 3, + code: '123456', + createdAt: expect.any(Number), }); }); it('应该在验证码不存在时返回基本信息', async () => { mockRedis.exists.mockResolvedValue(false); - mockRedis.ttl.mockResolvedValue(-1); + mockRedis.ttl.mockResolvedValue(-2); // -2 表示键不存在 const result = await service.getCodeStats(email, type); expect(result).toEqual({ exists: false, - ttl: -1, + ttl: -2, // 修改为 -2 }); });