Mocking MatSnackBar in Angular 8 & Jasmine

你。 提交于 2021-01-24 18:58:36

问题


I have an Angular 8 application that uses the Angular Material MatSnackBar and I am trying to test that the open() method of the class is called. The call to the open() method is within the body of an NgRx store selector, like this:

ngOnInit() {
  this.store.dispatch(fromStore.getFeaturedPlaylists());

  this.subscription = this.store.pipe(
    select(fromStore.selectError),
    filter(err => !!err),
    switchMap((err) => this.snackBar.open(
      `Error: ${err.message}`,
      'Try again',
      {duration: 5000}).afterDismissed())
  ).subscribe(() => this.store.dispatch(fromStore.getFeaturedPlaylists()));
}

The relevant part of my test looks like this:

describe('FeaturedPlaylistsComponent', () => {

  let component: FeaturedPlaylistsComponent;
  let fixture: ComponentFixture<FeaturedPlaylistsComponent>;
  let matSnackBarSpy: jasmine.SpyObj<MatSnackBar>;

  beforeEach(async(() => {
    const spy = jasmine.createSpyObj('MatSnackBar', ['open']);

    TestBed.configureTestingModule({
      declarations: [
        // other declarations here
        FeaturedPlaylistsComponent
      ],
      providers: [
        // other providers here
        {provide: MatSnackBar, useValue: spy}
      ]
    })
    .compileComponents();

    matSnackBarSpy = TestBed.get<MatSnackBar>(MatSnackBar);
  }));

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

  describe('#ngOnInit()', () => { // fails
    // lots of other test...
    it('should call MatSnackBar.open() on error', () => {
      const error = new HttpErrorResponse({error: 'Some error'});

      component.ngOnInit();
      store.dispatch(fromStore.setError({error}));

      expect(matSnackBarSpy.open).toHaveBeenCalled();
    });
  });

});

Now I know that this ngOnInit() function is working because I have another test that tests that the getFeaturedPlayists() action is dispatched twice: once on the first line of the function and once in the subscribe block:

it('should dispatch a getFeaturedPlaylists() action on error', () => { // succeeds
  const spy = spyOn(store, 'dispatch').and.callThrough();
  const error = new HttpErrorResponse({error: 'Some error'});

  component.ngOnInit();
  store.dispatch(fromStore.setError({error}));

  expect(spy).toHaveBeenCalledTimes(2);
  expect(spy.calls.allArgs()).toEqual([
    [fromStore.getFeaturedPlaylists()],
    [fromStore.setError({error})]
  ]);
});

To be honest I'm surprised that this test works: I would have assumed that I would need a tick(5000) to wait for the dialog to be dismissed, so perhaps there is actually something more sinister going on here.

Another thing: if I move the open() call to the first line of the function, like this:

ngOnInit() {
  this.snackBar.open(
    `Error: Some error`,
    'Try again',
    {duration: 5000});
  // this.store.dispatch(fromStore.getFeaturedPlaylists());

  // this.subscription = this.store.pipe(
  //   select(fromStore.selectError),
  //   filter(err => !!err),
  //   switchMap((err) => this.snackBar.open(
  //     `Error: ${err.message}`,
  //     'Try again',
  //     {duration: 5000}).afterDismissed())
  // ).subscribe(() => this.store.dispatch(fromStore.getFeaturedPlaylists()));
}

the should call MatSnackBar.open() on error test works, so my understanding is that it is something to do with the call to open() being within this store selector.

Can anyone tell me why the should dispatch a getFeaturedPlaylists() action on error test works and the should call MatSnackBar.open() on error test doesn't?


回答1:


Ok, I realized that I was using a mock store so no selectors were actually working. Using the real store for these tests, and with a little fiddling, I got them to work.



来源:https://stackoverflow.com/questions/58429612/mocking-matsnackbar-in-angular-8-jasmine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!