Angular单元测试:获取父组件传入的Observable类型@Input变量值
问题根源与解决方法
问题出在哪?
父组件用async管道把forkJoin返回的Observable解析成普通数据对象,传给子组件的[data]输入属性,但子组件错误地把@Input定义成了Observable类型。这就导致ngOnInit里this.settings = this.data赋值的是Observable对象,不是实际的业务数据,后续访问settings.userRoleObj.profile时,Observable里根本没有userRoleObj这个属性,自然就抛出Cannot read property 'profile' of undefined错误。
修复步骤
1. 修正子组件的@Input定义与逻辑
子组件接收的是父组件解析后的普通对象,不是Observable,先修正类型并添加空值保护:
// child.component.ts export class ChildComponent implements OnInit { // 修正:@Input接收普通mixType对象,而非Observable @Input() data!: mixType; public settings: mixType; public show = false; constructor() {} public ngOnInit(): void { this.settings = this.data; // 现在this.data是真实业务数据 this.setValidation(); } public setValidation(): void { // 空值保护:防止数据缺失时触发报错 if (!this.settings?.userRoleObj?.profile) { this.show = false; return; } const isAdmin = this.settings.userRoleObj.profile.type === UI_CONSTS.IS_ADMIN; if ( this.settings.isAutoApproved && isAdmin && this.settings.baseCountry === UI_CONSTS.BASE_COUNTRY ) { this.show = true; this.setBulletText(); } else { this.show = false; } } public setBulletText(): void { // 设置HTML内容的代码 } }
2. 修正单元测试用例
测试时直接传入模拟的普通数据对象,无需包裹成Observable:
// child-component.spec.ts import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ChildComponent } from './child.component'; import { UI_CONSTS, BASE_COUNTRY } from '../constants'; // 模拟符合显示条件的管理员数据 const MOCK_ADMIN_SETTINGS = { baseCountry: BASE_COUNTRY, isAutoApproved: true, userRoleObj: { profile: { type: UI_CONSTS.IS_ADMIN, }, }, hasOrgEnabled: true, }; // 模拟不符合显示条件的数据(非管理员+自动审批关闭) const MOCK_NON_QUALIFY_SETTINGS = { ...MOCK_ADMIN_SETTINGS, userRoleObj: { profile: { type: '2', }, }, isAutoApproved: false, }; describe('ChildComponent', () => { let component: ChildComponent; let fixture: ComponentFixture<ChildComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ChildComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(ChildComponent); component = fixture.componentInstance; }); it('should show content when admin and all conditions are met', () => { component.data = MOCK_ADMIN_SETTINGS; fixture.detectChanges(); // 触发ngOnInit执行 expect(component.show).toBe(true); }); it('should hide content when conditions are not met', () => { component.data = MOCK_NON_QUALIFY_SETTINGS; fixture.detectChanges(); expect(component.show).toBe(false); }); });
补充说明
async管道的核心作用就是自动订阅Observable,将解析后的普通数据传递给子组件,因此子组件无需再处理Observable类型。- 测试时给
component.data赋值模拟数据后,调用fixture.detectChanges()会触发组件的ngOnInit生命周期,此时settings会被正确赋值,你可以直接访问它的属性。 - 空值保护(
?.操作符)能有效避免因后端返回数据缺失导致的前端报错。
内容的提问来源于stack exchange,提问作者Nitika Gahlawat
相关产品推荐
相关产品推荐

