如何使用Jasmine为Angular密码验证组件编写全覆盖spec.ts测试代码
完整Jasmine测试代码(覆盖所有语句分支)
以下测试对所有外部依赖(路由、AWS Auth、系统弹窗)做了模拟,不会调用真实服务,直接替换你的spec.ts内容即可运行:
import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { Router, ActivatedRoute } from '@angular/router'; import { Auth } from '@aws-amplify/auth'; import { CodigoVerificacionClaveComponent } from './codigo-verificacion-clave.component'; describe('CodigoVerificacionClaveComponent', () => { let component: CodigoVerificacionClaveComponent; let fixture: ComponentFixture<CodigoVerificacionClaveComponent>; let router: Router; let route: ActivatedRoute; const mockTestEmail = 'test@example.com'; // 全局模拟系统alert弹窗,避免测试时弹出窗口 beforeAll(() => { spyOn(window, 'alert'); }); beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ CodigoVerificacionClaveComponent ], providers: [ // 模拟ActivatedRoute,返回测试用的邮箱参数 { provide: ActivatedRoute, useValue: { snapshot: { paramMap: { get: jasmine.createSpy('get').and.returnValue(mockTestEmail) } } } }, // 模拟Router,监听跳转动作 { provide: Router, useValue: { navigate: jasmine.createSpy('navigate') } } ] }) .compileComponents(); router = TestBed.inject(Router); route = TestBed.inject(ActivatedRoute); // 模拟AWS Auth的两个方法,避免调用真实接口 spyOn(Auth, 'signIn').and.stub(); spyOn(Auth, 'completeNewPassword').and.stub(); }); beforeEach(() => { fixture = TestBed.createComponent(CodigoVerificacionClaveComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('初始化时从路由参数正确获取邮箱', () => { expect(route.snapshot.paramMap.get).toHaveBeenCalledWith('param'); expect(component.currentemail).toBe(mockTestEmail); }); it('登录失败时弹出认证失败提示', fakeAsync(async () => { (Auth.signIn as jasmine.Spy).and.returnValue(Promise.reject(new Error('登录失败'))); component.currentpassword = 'testpwd123'; await component.changePasswordCognito(); tick(); expect(Auth.signIn).toHaveBeenCalledWith(mockTestEmail, 'testpwd123'); expect(window.alert).toHaveBeenCalledWith('User Authentication failed!'); })); it('需重置密码且重置成功时跳转首页', fakeAsync(async () => { const mockUser = { challengeName: 'NEW_PASSWORD_REQUIRED', challengeParam: { requiredAttributes: [] } }; (Auth.signIn as jasmine.Spy).and.returnValue(Promise.resolve(mockUser)); (Auth.completeNewPassword as jasmine.Spy).and.returnValue(Promise.resolve({})); component.currentpassword = 'oldpwd'; component.newpasswordchange = 'newpwd123'; await component.changePasswordCognito(); tick(); expect(Auth.completeNewPassword).toHaveBeenCalledWith(mockUser, 'newpwd123'); expect(window.alert).toHaveBeenCalledWith('El cambio de contraseña ha sido satisfactorio!!!, You are logged in successfully!'); expect(router.navigate).toHaveBeenCalledWith(['/home-express']); })); it('需重置密码但重置失败时打印错误日志', fakeAsync(async () => { const mockUser = { challengeName: 'NEW_PASSWORD_REQUIRED', challengeParam: { requiredAttributes: [] } }; const mockError = new Error('重置密码失败'); (Auth.signIn as jasmine.Spy).and.returnValue(Promise.resolve(mockUser)); (Auth.completeNewPassword as jasmine.Spy).and.returnValue(Promise.reject(mockError)); const consoleSpy = spyOn(console, 'log'); component.currentpassword = 'oldpwd'; component.newpasswordchange = 'newpwd123'; await component.changePasswordCognito(); tick(); expect(consoleSpy).toHaveBeenCalledWith(mockError); consoleSpy.calls.reset(); })); it('无需重置密码且登录成功时跳转首页', fakeAsync(async () => { const mockUser = { challengeName: 'OTHER_CHALLENGE', signInUserSession: { accessToken: 'mock_token' } }; (Auth.signIn as jasmine.Spy).and.returnValue(Promise.resolve(mockUser)); component.currentpassword = 'testpwd123'; await component.changePasswordCognito(); tick(); expect(window.alert).toHaveBeenCalledWith('You are logged in successfully!'); expect(router.navigate).toHaveBeenCalledWith(['/home-express']); })); it('无需重置密码但token为空时提示认证失败', fakeAsync(async () => { const mockUser = { challengeName: 'OTHER_CHALLENGE', signInUserSession: null }; (Auth.signIn as jasmine.Spy).and.returnValue(Promise.resolve(mockUser)); component.currentpassword = 'testpwd123'; await component.changePasswordCognito(); tick(); expect(window.alert).toHaveBeenCalledWith('User Authentication failed!'); })); });
覆盖说明
所有逻辑分支全部覆盖:
- 组件初始化读取路由参数逻辑
- 登录抛出错误分支
- 需重置密码的成功、失败分支
- 无需重置密码的登录成功、登录失败分支
内容的提问来源于stack exchange,提问作者Cristopher Caceres
相关产品推荐
相关产品推荐

