【问题标题】:Angular Unit test Cannot read properties of undefined角度单元测试无法读取未定义的属性
【发布时间】:2021-12-02 08:28:44
【问题描述】:

我正在尝试对组件进行单元测试, 组件和页面正在导入表单@bloomreach/spa-sdk

  export class ThinComponent implements OnInit {
  @Input() component!: BrComponent;
  componentModels: any;
   page: Page;
  
  constructor() {}

  ngOnInit() {
    this.componentModels = this.component.getModels();  
  }

 getContents(contentRef) {
    if (contentRef && contentRef.$ref) {
      this.content = this.page?.getContent(contentRef).getData();
    }
  }
}

和我的单元测试一样

  it('should create', () => {
     spyOn(component.component, 'getModels').and.returnValue({foo: 'bar'});
     fixture.detectChanges();
     expect(component).toBeTruthy();
  });

抛出错误TypeError: Cannot read properties of undefined (reading 'getModels')

【问题讨论】:

  • 您在单元测试中是否将任何内容传递给@Input() component?好像没有初始化。
  • 这很有效,谢谢。 @RuslanLekhman
  • 我正在尝试测试 getContents() component.page = mockPage;常量内容 = { $ref: 'foo' }; // @ts-ignore spyOn(component.page?.getContent('foo'), 'getData').and.callFake( () => { return 'test'; });但是得到一个错误 Error: : could not find an object to spy on for getData()

标签: angular unit-testing jasmine


【解决方案1】:

Ruslan Lekhman 是对的,您需要初始化 component 输入,我认为 spyOn 不适合它。 spyOn 仅适用于公共方法。

试试这个:

it('should create', () => {
     component.component = { getModels: () => ({ foo: 'bar' }) };
     fixture.detectChanges();
     expect(component).toBeTruthy();
  });

编辑:

尝试将mockPage 更改为类似的内容。

const getDataSpy = jasmine.createSpy('getData');
mockPage = { getContent: () => ({ getData: getDataSpy }) };
....
expect(getDataSpy).and.callFake(() => { return 'test'; });

编辑

组件.ts

import { Component, Input, VERSION } from '@angular/core';

import { Component as BrComponent, Page } from '@bloomreach/spa-sdk';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  name = 'Angular ' + VERSION.major;
  @Input() component!: BrComponent;
  page: Page;
  componentModels: any;
  public content: any;
  public image: string;
  public inViewport = false;
  constructor() {}
  get configuration() {
    return this.component.getParameters();
  }
  ngOnInit() {
    this.componentModels = this.component?.getModels();
    if (this.componentModels) {
      this.getContents(this.componentModels.document);
    }
  }
  getContents(contentRef) {
    if (contentRef && contentRef.$ref) {
      this.content = this.page?.getContent(contentRef).getData();
      if (this.content) {
        if (this.content.image) {
          this.image = this.getImageUrl(this.content.image);
        }
      }
    }
  }

  getImageUrl($ref): string {
    return this.page.getContent($ref).getUrl();
  }
  onVisible(event) {
    this.inViewport = true;
  }
}

Component.spec.ts

import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import { AppComponent } from './AppComponent';
import { Component as BrComponent, Page } from '@bloomreach/spa-sdk';

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

  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        declarations: [AppComponent],
      }).compileComponents();
    })
  );

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    component.component = {
      getModels: () => ({ document: { $ref: {} } }),
      getParameters: () => ({}),
    };
    component.page = {
      getContent: () => ({
        getData: () => ({ image: 'abc' }),
        getUrl: () => 'xyz',
      }),
    };
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should test ngOninit', () => {
    spyOn(component, 'getContents').and.callFake(() => null);
    component.ngOnInit();
    expect(component.getContents).toHaveBeenCalled();
  });
  it('should test getContents', () => {
    component.getContents(component.componentModels.document);
    expect(component.image).toBe('xyz');
  });
});

【讨论】:

  • 我正在尝试测试 getContents() component.page = mockPage;常量内容 = { $ref: 'foo' }; // @ts-ignore spyOn(component.page?.getContent('foo'), 'getData').and.callFake( () => { return 'test'; });但是得到一个错误 Error: : could not find an object to spy on for getData()
  • 查看我的编辑。我认为spyOn(x, 'methodName'),x 必须是一个对象,而不是您展示的 getContent 之类的方法/函数。
  • 我试过这个 const getDataSpy = jasmine.createSpy('getData'); getDataSpy.and.returnValue(() => { return {image: 'test.png'}; }); mockPage = { getContent: () => ({ getData: getDataSpy }) };组件.getContents(内容);期望(component.content.image).toBe('/test.png');零件。内容始终未定义
  • 你能从 console.log(component.content) 中得到什么吗?
  • 打印为未定义
猜你喜欢
  • 2018-04-18
  • 2019-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多