Search code examples
angularjasmineangular-material2ngrxngrx-store-4.0

Why isn't store.dispatch() getting called in the subscribe block?


So I have a MatDialog Box which on close sends some form values. I then dispatch an action in the afterClosed method provided by MatDialogRef.

This works quite alright when I manually test it. But while unit testing, the dispatch isn't called and my test fails.

My Code that runs when opening the dialog & dispatches the action when closed.

openAddUserDialog() {
     this.addUserDialog = this.dialog.open(AddUserDialogComponent, {
      width: 'max-content',
      height: 'max-content',
      minWidth: '35vw',
      minHeight: '20vh',
      autoFocus: false
    });

     this.addUserDialog.afterClosed().subscribe(result => {
      console.log(result);
      this.store.dispatch({type: UserActions.ActionTypes.TryAddUser, payload: result.value});
    });
  }

The Mock for MatDialog

export class MatDialogMock {
  open() {
    return {
      afterClosed: () => of(initialValue)
    };
  }
}

TestBed Config

 beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [MaterialModule, ReactiveFormsModule, BrowserAnimationsModule],
      declarations: [ UserManagementDialogComponent ],
      providers: [{provide: MatDialog, useClass: MatDialogMock}, provideMockStore({initialState})]
    })
    .compileComponents();
  }));

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

    store = TestBed.get(Store);
    spyOn(store, 'dispatch').and.callThrough();
    dialog = TestBed.get(MatDialog);

    fixture.detectChanges();
  });

And the test that should pass

it('should dispatch an action when the form is submitted', fakeAsync(() => {

    spyOn(dialog, 'open').and.callThrough();
    const dialogRef = dialog.open();

    dialogRef.afterClosed().subscribe(result => {
      console.log('verbrberbhyn', result);
      expect(result).toEqual(initialValue);

      tick();

      expect(store.dispatch).toHaveBeenCalledTimes(1);
      expect(store.dispatch).toHaveBeenCalledWith({
        type: UserAtions.ActionTypes.TryAddUser,
        payload: initialValue
      });
    });
  }));

Solution

  • Found out why I couldn't pass the test case.

    afterClosed() gets called after the dialog is closed. So all I had to do was call dialog.close() before subscribing to afterClosed()

    So at the end my test function looks like:

    it('should dispatch an action when the form is submitted', () => {
    
        spyOn(dialog, 'open').and.callThrough();
        component.openAddUserDialog();
        dialog.close();
        component.addUserDialog.afterClosed().subscribe(result => {
    
          expect(result.value).toEqual(initialValue);
          expect(store.dispatch).toHaveBeenCalledTimes(1);
          expect(store.dispatch).toHaveBeenCalledWith({
            type: UserAtions.ActionTypes.TryAddUser,
            payload: result.value
          });
        });
      });
    

    And I also updated the Mock

    export class MatDialogMock {
      open() {
        return {
          afterClosed: () => of({value: initialValue})
        };
      }
    
      close() {}
    }
    

    So as to call close() on the mock dialog and also updated afterClosed() as the action's payload is stored in value property:

    this.addUserDialog.afterClosed().subscribe(result => {
          console.log(result);
          this.store.dispatch({type: UserActions.ActionTypes.TryAddUser, payload: result.value});
        });