You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

错误原因

  1. @Input() quadrados未赋值:组件HTML中的.casa元素依赖*ngFor="let quadrado of quadrados"渲染,但测试代码中没有给component.quadrados赋值,导致初始化时没有渲染任何.casa元素,fixture.debugElement.query(By.css('.casa'))返回null,访问nativeElement时触发错误。
  2. 缺少依赖服务的Mock:组件构造函数依赖JogadasService,测试模块未提供该服务的实例或Mock,会导致组件初始化失败。
  3. 断言语法错误:expect(emitMessageSpy).toHaveBeenCalled缺少括号,正确写法是expect(emitMessageSpy).toHaveBeenCalled()。
  4. 重复绑定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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 22:50:38