Angular测试报错:Cannot read properties of null (reading 'nativeElement')
解决Angular测试中「Cannot read properties of null (reading 'nativeElement')」错误
我是Angular CLI 15的新手,想要测试组件中点击事件触发并向父组件传值的功能,但运行测试代码时出现「Cannot read properties of null (reading 'nativeElement')」错误。相关代码如下:
测试代码
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { QuadradosComponent } from './quadrados.component'; describe('QuadradosComponent', () => { let component: QuadradosComponent; let fixture: ComponentFixture<QuadradosComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ QuadradosComponent ] }) .compileComponents(); fixture = TestBed.createComponent(QuadradosComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('Deve emitir mensagem quando clicar na div', () => { const emitMessageSpy = spyOn(component.eventoOutput, 'emit') let divClick = fixture.debugElement.query(By.css('.casa')).nativeElement divClick.click() expect(emitMessageSpy).toHaveBeenCalled }) });
组件.ts代码
import { Component, EventEmitter, Input, Output, OnInit} from '@angular/core'; import { JogadasService } from 'src/app/services/jogadas.service'; @Component({ selector: 'app-quadrados', templateUrl: './quadrados.component.html', styleUrls: ['./quadrados.component.css'] }) export class QuadradosComponent implements OnInit{ constructor(public service: JogadasService) {} ngOnInit(): void { this.service.emitirVitoria.subscribe( array => this.vitoria.push(...array) ) console.log(document.getElementsByClassName('casa')) } vitoria: number[] =[]; posicoes: number = 0; @Input() quadrados?: Array<number>; @Output() eventoOutput = new EventEmitter(); @Output() index = new EventEmitter(); eventoClick(evento: MouseEvent) { this.eventoOutput.emit(evento); console.log(document.getElementsByClassName('casa')) } pegaIndex(index: number) { this.posicoes = index; this.index.emit(this.posicoes); } vitoriaArray(modelo: number) { for(let i = 0; i< this.vitoria.length; i++) { if(this.vitoria[i] == modelo) { return this.vitoria[i] } } } }
组件HTML代码
<div class="centraliza"> <div class="jogo-da-velha"> <div class="linha"> <div class="casa" *ngFor="let quadrado of quadrados, let i = index" (click)="pegaIndex(i)" [ngClass]="i == vitoriaArray(i) ? 'casa-vencedor' : null" (click)="eventoClick($event)" ></div> </div> </div> </div>
错误原因
- @Input() quadrados未赋值:组件HTML中的
.casa元素依赖*ngFor="let quadrado of quadrados"渲染,但测试代码中没有给component.quadrados赋值,导致初始化时没有渲染任何.casa元素,fixture.debugElement.query(By.css('.casa'))返回null,访问nativeElement时触发错误。 - 缺少依赖服务的Mock:组件构造函数依赖
JogadasService,测试模块未提供该服务的实例或Mock,会导致组件初始化失败。 - 断言语法错误:
expect(emitMessageSpy).toHaveBeenCalled缺少括号,正确写法是expect(emitMessageSpy).toHaveBeenCalled()。 - 重复绑定click事件:HTML中同一个
.casa元素绑定了两个(click)事件,后面的eventoClick($event)会覆盖前面的pegaIndex(i),导致只有后者会被触发。
解决方案
1. 修改测试代码,补充必要的依赖和输入值
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { JogadasService } from 'src/app/services/jogadas.service'; // 创建Mock服务替换真实依赖 class MockJogadasService { emitirVitoria = { subscribe: jasmine.createSpy('subscribe') }; } import { QuadradosComponent } from './quadrados.component'; describe('QuadradosComponent', () => { let component: QuadradosComponent; let fixture: ComponentFixture<QuadradosComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ QuadradosComponent ], // 注入Mock服务 providers: [ { provide: JogadasService, useClass: MockJogadasService } ] }) .compileComponents(); fixture = TestBed.createComponent(QuadradosComponent); component = fixture.componentInstance; // 给@Input()赋值,确保*ngFor渲染出.casa元素 component.quadrados = [1, 2, 3]; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('Deve emitir mensagem quando clicar na div', () => { const emitMessageSpy = spyOn(component.eventoOutput, 'emit'); // 获取渲染后的第一个.casa元素 let divClick = fixture.debugElement.query(By.css('.casa')).nativeElement; divClick.click(); // 修正断言语法 expect(emitMessageSpy).toHaveBeenCalled(); }); // 新增测试index输出的用例 it('Deve emitir index quando clicar na div', () => { const emitIndexSpy = spyOn(component.index, 'emit'); let divClick = fixture.debugElement.query(By.css('.casa')).nativeElement; divClick.click(); expect(emitIndexSpy).toHaveBeenCalledWith(0); }); });
2. 修复组件HTML中的重复click事件
将两个(click)合并为一个方法,确保两个逻辑都能执行:
<div class="centraliza"> <div class="jogo-da-velha"> <div class="linha"> <div class="casa" *ngFor="let quadrado of quadrados, let i = index" (click)="handleClick($event, i)" [ngClass]="i == vitoriaArray(i) ? 'casa-vencedor' : null" ></div> </div> </div> </div>
在组件.ts中添加合并后的方法:
handleClick(evento: MouseEvent, index: number) { this.eventoOutput.emit(evento); this.pegaIndex(index); }
内容的提问来源于stack exchange,提问作者Túlio Roberto
相关产品推荐
相关产品推荐

