如何对依赖于元素高度的组件进行单元测试(使用角度 5)?

Yur*_*aki 5 unit-testing jasmine typescript angular

我有一个带有输入的组件fsElement。这fsElement应该是任何 html 元素的 id。然后我的组件使用这个提供的 id 来获取元素的高度。这是相关代码:

export class BotaoTelaCheiaComponent implements OnInit {

  @Input() fsElement:string;

  private _originalHeight: number;

  constructor() { }

  ngOnInit() {}

  ngAfterViewInit() {

    this._originalHeight = document.getElementById(this.fsElement).clientHeight; 

  }

}
Run Code Online (Sandbox Code Playgroud)

当我运行时 ng test它失败了TypeError: Cannot read property 'clientHeight' of null。我只是运行 Angular cli 生成的标准测试:

describe('BotaoTelaCheiaComponent', () => {
  let component: BotaoTelaCheiaComponent;
  let fixture: ComponentFixture<BotaoTelaCheiaComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ BotaoTelaCheiaComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(BotaoTelaCheiaComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});
Run Code Online (Sandbox Code Playgroud)

如何重写此测试或我的组件以使其通过?

Est*_*ask 3

生命周期挂钩(OnInit等)在 中执行的首次更改检测时触发beforeEach

为了避免这种情况,fixture.detectChanges()应该按需删除beforeEach并调用。

  it('should create', () => {
    expect(component).toBeTruthy();
    component.fsElement = 'foo';
    spyOn(document, 'getElementById').and.returnValue({ clientHeight: 100 });
    fixture.detectChanges();
    expect(document.getElementById).toHaveBeenCalledWith('foo');
    expect(component['_originalHeight']).toBe(100);
  });
Run Code Online (Sandbox Code Playgroud)

或者,可以将真实的 DOM 元素id="foo"添加到 DOM in 中beforeEach并在 中删除afterEach

直接 DOM 访问使 Angular 测试变得复杂,因为它需要模拟全局变量或 DOM。

  • 这不是 Angular 特有的。有关间谍的解释请参见[Jasmine 文档](http://jasmine.github.io/edge/introduction.html)。您可以像使用 JS、“document.appendChild(..)”等一样提供真实的 DOM 元素。但是你不应该在单元测试中提供真正的 DOM 元素。您只是测试真实 DOM 所期望的行为。真正的 DOM 是集成和/或 e2e 测试的用途。 (2认同)