如何在Angular 7中模拟MatSidenav类型的输入

时间:2019-04-22 14:43:39

标签: angular angular-material karma-jasmine

可以模拟MatSidenav吗?

我要对从父组件输入MatSidenav作为输入的组件进行单元测试。

到目前为止,我在业力窗口中收到此错误:

错误1:

  

ChildComponent>应该创建   TypeError:无法读取null的属性“ runOutsideAngular”

错误2:

  

ChildComponent>在sidenav更改上应该起作用   TypeError:无法读取null的属性“ runOutsideAngular”

我理解错误是因为我用空参数模拟了超类,有人可以向我展示一个更好的解决方案吗?

我的代码如下。

parent-component.html


<mat-sidenav-container>

  <mat-sidenav #filtersSidenav mode="side" opened="true" position="end"></mat-sidenav>

  <mat-sidenav-content>
    <app-child-component [sidenav]="filtersSidenav"></app-child-component >
  </mat-sidenav-content>

</mat-sidenav-container>

app-child-component.ts

import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-child-component',
  templateUrl: './app-child-component.html',
  styleUrls: ['./app-child-component.scss']
})
export class ChildComponent implements OnInit {

  @Input() sidenav: MatSidenav;

  constructor() { }

  ngOnInit() {
    if (this.sidenav) {
      this.sidenav.openedChange.subscribe( res => {
        console.log('works');
      });
    }
  }

}

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MatSidenav } from '@angular/material';
import { of, Observable } from 'rxjs';

// Modules
import { MaterialModule } from '@app-global-modules/material.module.ts';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { RouterTestingModule } from '@angular/router/testing';

// Components
import { ChildComponent } from './child-component.component';

// Other
import { EventEmitter } from '@angular/core';


class SidenavMock extends MatSidenav {

  openedChange: EventEmitter<boolean> = new EventEmitter<boolean>(true);

  constructor() {
    super(null, null, null, null, null, null);
  }

}


describe('ChildComponent', () => {

  let component: ChildComponent;
  let fixture: ComponentFixture<ChildComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        MaterialModule,
        ReactiveFormsModule,
        HttpClientModule,
        RouterTestingModule
      ],
      declarations: [
        ChildComponent,
      ]
    })
    .compileComponents();
  }));


  beforeEach(async() => {
    fixture = TestBed.createComponent(ChildComponent);
    component = fixture.componentInstance;


    component.sidenav = new SidenavMock(); // <== I mock

    component.ngOnInit();
    await fixture.whenStable();
    fixture.detectChanges();
  });


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


  fit('on sidenav change should work', () => {
    const consoleLogSpy = spyOn(console, 'log').and.callThrough();
    component.sidenav.toggle();

    expect(consoleLogSpy).toHaveBeenCalledWith('works');
  });


});


1 个答案:

答案 0 :(得分:0)

您可以尝试:

@Component({
    selector: 'testing-component',
    template: `
        <mat-sidenav-container>

        <mat-sidenav #filtersSidenav mode="side" opened="true" position="end"></mat-sidenav>

        <mat-sidenav-content>
            <app-child-component [sidenav]="filtersSidenav"></app-child-component >
        </mat-sidenav-content>

        </mat-sidenav-container>
    `
})
class TestBedComponent {
    @ViewChild(ChildComponent) public componentUnderTest: ChildComponent ;    
    constructor() {}
}

在规格文件中:

// Components
import { ChildComponent } from './child-component.component';
// Other
import { EventEmitter } from '@angular/core';


describe('ChildComponent', () => {

  let component: TestBedComponent;
  let fixture: ComponentFixture<TestBedComponent>;
  let childComponent: ChildComponent;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        MaterialModule,
        ReactiveFormsModule,
        HttpClientModule,
        RouterTestingModule
      ],
      declarations: [
        ChildComponent,TestBedComponent
      ]
    })
    .compileComponents();
  }));


  beforeEach(async() => {
    fixture = TestBed.createComponent(TestBedComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
    childComponent = component.componentUnderTest;
  });


  fit('should create', () => {
    expect(childComponent).toBeTruthy();
  });
});

当子组件需要一些紧密耦合的数据时(如我在您的情况中所见),通常首选这种测试方法。

您可以像在规范文件中childComponent一样继续测试component