Search code examples
angulartypescriptjasminekarma-runnerangular-unit-test

Angular/TypeScript: Unit Test call of snackbar


I have a method onDelete that uses a MatSnackBar which gets injected in the constructor like that:

constructor(private todoListService: TodolistService, private snackBar: MatSnackBar) { }

onDelete(todoList: TodoList): void {
    const deletedTodoListName = todoList.name;
    this.todoListService.delete(todoList).subscribe(response => {
      this.loadTodoLists();

      this.snackBar.open(`${deletedTodoListName} wurde gelöscht`, 'Schliessen', {
        duration: 3000,
        horizontalPosition: 'center',
        verticalPosition: 'bottom',
      });
    });
  }

I tried to unit test this method:

import { async, ComponentFixture, TestBed, inject, getTestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

import { NavigationviewComponent } from './navigationview.component';
import { TodolistService } from '../todolist.service';
import { MatSnackBarModule, MatSnackBar } from '@angular/material/snack-bar';
import { TodoList } from '../todolist';
import { Observable } from 'rxjs';

describe('NavigationviewComponent', () => {
  let injector: TestBed;
  let component: NavigationviewComponent;
  let fixture: ComponentFixture<NavigationviewComponent>;
  let httpMock: HttpTestingController;
  let todoListService: TodolistService;
  let snackBar: MatSnackBar;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule, MatSnackBarModule  ],
      declarations: [ NavigationviewComponent ],
      providers: [ TodolistService, MatSnackBar ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    injector = getTestBed();
    httpMock = injector.inject(HttpTestingController);
    todoListService = injector.inject(TodolistService);
    snackBar = injector.inject(MatSnackBar);
    fixture = TestBed.createComponent(NavigationviewComponent);
    fixture.detectChanges();
    component = fixture.componentInstance;
  });

  afterEach(() => {
    httpMock.verify();
  });

it('should delete the todolist when onDelete is called', () => {
    const todoList: TodoList = { name: 'todoList', listItems: [] };
    spyOn(todoListService, 'delete').and.returnValue(new Observable<object>());
    spyOn(snackBar, 'open');

    component.onDelete(todoList);

    expect(snackBar.open).toHaveBeenCalled();
    const req = httpMock.expectOne('https://angulareinfuehrungsaufgabetodolistapi.azurewebsites.net/todolist');
    expect(req.request.method).toBe('GET');
  });
});

But when executing the test, it says

Expected spy open to have been called.

Why does the test not recognize the call to the snackBar? When executing the code by deleting an item the snackbar is visible.

Thanks in advance


Solution

  • I think your spyOn the 'delete of todoListService is not accurate.

    Try this:

    import { of } from 'rxjs';
    .....
    spyOn(todoListService, 'delete').and.returnValue(of(null)); // it's up to you what you want to return
    
    component.onDelete(todoList);
    
    expect(snackBar.open).toHaveBeenCalled();