Search code examples
angulartypescriptunit-testingjasminekarma-jasmine

Test angular snackbar


I am making a simple snackbar for which code as follows,

app.component.ts:

  ngOnInit(){
    this.dataService.valueChanges.pipe(
        filter((data) =>data=== true),
        switchMap(() => {
          const snackBarRef = this.matSnackBar.open(
            'A new value updated',
            'OK',
            {
              duration: 3000
            }
          );

          return snackBarRef.onAction();
        })
      )
      .subscribe(() => {
        this.window.location.reload();
      });
  }

app.component.spec.ts (Including mock data for service)

describe('AppComponent', () => { 
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;
  let matSnackBarSpy: jasmine.SpyObj<MatSnackBar>;

  let a = "";
  let b = "";
  let c = "";

  const mockDataService = {
    valueChanges: of(true)
  };

  beforeEach(async(() => {
    TestBed.configureTestingModule({

    a = "Test";
    b = "X";
    c = "suc";
    matSnackBarSpy = TestBed.get<MatSnackBar>(MatSnackBar);

 })
}))

  describe('#ngOnInit()', () => {

    it('should call MatSnackBar.open()', async(done: DoneFn) => {
      const error = new HttpErrorResponse({ error: 'Some error' });

      component.ngOnInit();

      expect(mockDataService.valueChanges).toBeTruthy();
      expect(matSnackBarSpy.open(a,b,c)).toBeTruthy();

      done();
    });
  });

})

data.service.ts

import { Observable } from 'rxjs';

export class DataService {
  valueChanges: Observable<boolean>;
}

Explanation:

  • I am having a service which has the property valueChanges with type as Observable<boolean> .

  • In component.ts, I am getting the value change as like mentioned above and end result I receive is boolean value true and also snackbar gets opened and everything is working fine.

  • Now I am into implementation of test cases for the above like in compoenent.spec.ts,

      expect(mockDataService.valueChanges).toBeTruthy();
      expect(matSnackBarSpy.open(a,b,c)).toBeTruthy();
    

This results in success case but I am forever receiving this below output in chrome.

enter image description here

Requirement: Need to cover all the tests that currently shows warning/indication of not covered in the above image..

Above test cases are running but test coverage shows still function not covered and also statement not covered warning when we open index.html of the component.


Solution

  • So, you basically should test whether matSnackBar methods are called properly or not. Testing behavior of matSnackBar is not a unit testing.

    Try

    class MatSnackBarStub{
      open(){
        return {
          onAction: () => of({})
        };
      }
    
    }
    

    in component.spec file

      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [SomeComponent],
          providers: [{provide: MatSnackBar , useClass: MatSnackBarStub}]
        }).compileComponents();
      }));
    
      it('should create', () => {
        spyOn(component.matSnackBar,"open").and.callThrough();
        component.ngOnInit();
        expect(component.matSnackBar.open).toHaveBeenCalled();
        // you can also use ".toHaveBeenCalledWith" with necessary params
      });
    

    I would suggest you to take a look at this collection of articles related to unit testing using jasmine and karma. There is one article on how to use stubs and spies. I hope this would help