【问题标题】:How to test Material2 snack-bar?如何测试 Material2 小吃吧?
【发布时间】:2018-09-13 08:56:24
【问题描述】:

我有一个关于 Angular 5 的项目,但遇到了以下问题。我有一个 组件 ComponentWithSnackBar 触发显示小吃店:

showSnackBar() {
  this.snackBar.open('Message text', 'Close', {
    duration: 5000,
    verticalPosition: 'top',
  });
}

它按预期工作。但我不知道如何测试它。我尝试写测试:

describe('ComponentWithSnackBar', () => {
  let snackBar: MatSnackBar;
  let overlayContainer: OverlayContainer;
  let overlayContainerElement: HTMLElement;

  function createComponent<T>(component: Type<T>, providers: Provider[] = [], declarations: any[] = []): ComponentFixture<T> {
    TestBed.configureTestingModule({
      imports: [AppModule, RouterTestingModule, NoopAnimationsModule],
      declarations: declarations,
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      providers,
    }).compileComponents();

    inject([MatSnackBar, OverlayContainer], (sb: MatSnackBar, oc: OverlayContainer) => {
      snackBar = sb;
      overlayContainer = oc;
      overlayContainerElement = oc.getContainerElement();
    })();

    return TestBed.createComponent<T>(component);
  }

  it(`Should display snack-bar`, fakeAsync(() => {
    const fixture = createComponent(ComponentWithSnackBar);
    const component: ComponentWithSnackBar = fixture.debugElement.componentInstance;

    fixture.detectChanges();
    const button = fixture.debugElement.query(By.css('button')); //button which triggers method showSnackBar 
    button.triggerEventHandler('click', null);
    fixture.detectChanges();
    flush();

    const messageElement = overlayContainerElement.querySelector('snack-bar-container');
    expect(messageElement.textContent).toContain('Message text');
  }));
});

结果我得到错误

TypeError: 无法读取 null 的属性“textContent”

我做错了什么?感谢您的提前!

【问题讨论】:

    标签: angular karma-jasmine angular-material2 angular-test


    【解决方案1】:

    以下内容对我有用:

    describe('MyComponent', () => {
      let component: MyComponent;
      let fixture: ComponentFixture<MyComponent>;
      let element: any;
      let overlayContainer: OverlayContainer;
      let overlayContainerElement: HTMLElement;
      let snackBar: MatSnackBar;
    
    ....
    
    beforeEach(() => {
        fixture = TestBed.createComponent(MyComponent);
        component = fixture.componentInstance;
        element = fixture.nativeElement;
        fixture.detectChanges();
      });
    
    beforeEach(inject([MatSnackBar, OverlayContainer],
        (sb: MatSnackBar, oc: OverlayContainer) => {
          snackBar = sb;
          overlayContainer = oc;
          overlayContainerElement = oc.getContainerElement();
        }));
    
    ....
    
     it('should show my success message', () => {
          
       const containerElement = overlayContainerElement.querySelector('simple-snack-bar');
       
       expect(containerElement.textContent).toContain('My success text');
     });
    

    【讨论】:

    • 序言中的 Github 链接已失效 @dgraf
    • @Milton thanx,我删除了它,因为它不再可以访问了
    【解决方案2】:

    我决定不测试显示小吃店的事实,而只测试带有正确参数的调用方法snackBar.open() 的事实:

    expect(snackBarSpy.open.calls.count()).toEqual(1);
    expect(snackBarSpy.open.calls.first().args).toEqual([message, 'Close', {duration: 5000, verticalPosition: 'top'}]);
    

    【讨论】:

      【解决方案3】:

      我在尝试使用材质对话框测试组件时遇到了类似的问题。我没有找到解决方案,但我想我会分享我所知道的:

      如果您在运行时在测试上设置断点并检查范围,overlayContainerElement(即类为 cdk-overlay-container 的 div)没有子节点。

      另外,如果您将以下内容添加到期望语句之前的测试末尾:

      console.log("overlay wrapper", document.getElementsByClassName('cdk-global-overlay-wrapper')[0]);
      // and or
      console.log("snackbar text", document.getElementsByClassName('snack-bar-container')[0]); // or whatever class you gave this item
      

      它们都记录未定义。

      我的理论是,Angular 变化检测不会在与显示材料部件(例如对话框或快餐栏)相关的组件上运行,这就是为什么它们在测试期间为空/不显示的原因。

      您也可以分享 ComponentWithSnackBar 的代码吗?

      【讨论】:

      • 感谢您的回答。实际上,ComponentWithSnackBar 并不是真正的组件。它只是我的组件的简化版本。我认为,你有一个正确的理论。
      【解决方案4】:
      const mockSnackbar = jasmine.createSpyObj(['open']);
      
      it('test desc'()=>{
          component.showSnackBar()
              expect(mockSnackbar.open).tohavebeencalled();
              expect(mockSnackbar.open).tohavebeencalledwith('Message text',
                  'Close', {
                      duration: 5000,
                      verticalPosition: 'top',
                  });
      })
      

      【讨论】:

        猜你喜欢
        • 2020-09-07
        • 1970-01-01
        • 1970-01-01
        • 2018-07-03
        • 2020-02-20
        • 2020-10-18
        • 2015-02-13
        • 2018-09-12
        • 2019-07-24
        相关资源
        最近更新 更多