Angular 4组件Jasmine测试报错:Cannot read property 'value' of undefined
这个错误的核心原因是你的双向绑定目标fedExTax在测试运行时是undefined,导致尝试访问.value属性失败。因为双向绑定[(ngModel)]需要同时读写目标对象的属性,所以不能用安全导航操作符?.(它只适用于单向读取场景),我们需要确保fedExTax对象在组件初始化时就已存在。
下面是具体的解决步骤:
1. 在组件类中初始化fedExTax对象
最稳妥的方式是在组件内部确保fedExTax始终有值,不管输入属性是否传入。根据你的代码结构,分两种情况处理:
情况A:fedExTax是组件独立属性
如果fedExTax是组件自己维护的属性,直接在组件类中声明并初始化:
// 组件类中 export class IncrementalCaptiveAssumptionsComponent implements OnInit { // 初始化一个默认对象,确保value属性存在 fedExTax = { value: 0 }; // 可根据业务需求设置默认值,比如null、空字符串等 // 其他组件代码... }
情况B:fedExTax来自输入属性fedExciseExpensesInputs
从你代码里的FedExTaxFieldKey = 'fedExciseTax'来看,fedExTax大概率是从fedExciseExpensesInputs数组中提取的项。这时候需要在组件的ngOnInit或ngOnChanges中处理,确保提取不到时初始化默认对象:
// 组件类中 export class IncrementalCaptiveAssumptionsComponent implements OnInit, OnChanges { @Input() fedExciseExpensesInputs: BackendDto.YourExpenseType[]; fedExTax: { value: number }; // 先定义类型 ngOnInit() { this.initFedExTax(); } ngOnChanges(changes: SimpleChanges) { // 如果输入属性变化,重新初始化 if (changes.fedExciseExpensesInputs) { this.initFedExTax(); } } private initFedExTax() { // 从输入数组中查找目标项 const foundItem = this.fedExciseExpensesInputs?.find(x => x.fieldInfo.key === FedExTaxFieldKey); // 找不到则初始化默认对象,找到则直接使用 this.fedExTax = foundItem ?? { value: 0 }; } // 其他组件代码... }
2. 确保测试中的输入属性有效
你的测试代码中已经设置了harness.fedExciseExpensesInputs = fedExciseTaxExpenses;,但需要确认createFedExciseExpenses()函数返回的数组中确实包含fieldInfo.key为fedExciseTax的项。如果没有,需要修改测试数据生成函数:
// 测试数据生成函数示例 export function createFedExciseExpenses() { return [ // 其他项... { fieldInfo: { key: 'fedExciseTax' }, value: 0 // 确保value属性存在 } ]; }
3. 测试中手动初始化(应急方案)
如果暂时无法修改组件代码,可以在测试的beforeEach中手动给组件的fedExTax赋值,确保测试运行时对象存在:
beforeEach(() => { fixture = TestBed.createComponent(HostFormTestComponent); harness = fixture.componentInstance; fixture.detectChanges(); sut = harness.componentUnderTest; // 手动初始化fedExTax sut.fedExTax = { value: 0 }; harness.incrementalExpensesInputs = IncrementalExpenses; harness.fedExciseExpensesInputs = fedExciseTaxExpenses; fixture.detectChanges(); });
为什么不能用[(ngModel)]="fedExTax?.value"?
安全导航操作符?.只能用于单向读取(即[ngModel]部分),但双向绑定的(ngModelChange)部分需要赋值给fedExTax.value,如果fedExTax是undefined,赋值操作依然会报错。所以必须确保fedExTax是一个已存在的对象。
内容的提问来源于stack exchange,提问作者Tom

